-
-
Notifications
You must be signed in to change notification settings - Fork 671
feat: add expo config plugin #2218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,4 +82,7 @@ lib/ | |
!**/.yarn/versions | ||
|
||
# Docs | ||
docs/docs/api/* | ||
docs/docs/api/* | ||
|
||
# Keep expo plugin build code | ||
!plugin/build |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,6 @@ docs/ | |
.gitattributes | ||
.yarn/cache | ||
package/ | ||
plugin/src | ||
plugin/jest.config.js | ||
plugin/tsconfig.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('./plugin/build/withIAP'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
const appBuildGradleWithoutIAP = ` | ||
apply plugin: "com.android.application" | ||
|
||
import com.android.build.OutputFile | ||
|
||
def reactNativeArchitectures() { | ||
def value = project.getProperties().get("reactNativeArchitectures") | ||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] | ||
} | ||
|
||
android { | ||
ndkVersion rootProject.ext.ndkVersion | ||
|
||
compileSdkVersion rootProject.ext.compileSdkVersion | ||
|
||
defaultConfig { | ||
applicationId 'com.test.withIAP' | ||
minSdkVersion rootProject.ext.minSdkVersion | ||
targetSdkVersion rootProject.ext.targetSdkVersion | ||
versionCode 34 | ||
versionName "1.16.2" | ||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()`; | ||
|
||
const appBuildGradleWithPlayStoreIAP = ` | ||
apply plugin: "com.android.application" | ||
|
||
import com.android.build.OutputFile | ||
|
||
def reactNativeArchitectures() { | ||
def value = project.getProperties().get("reactNativeArchitectures") | ||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] | ||
} | ||
|
||
android { | ||
ndkVersion rootProject.ext.ndkVersion | ||
|
||
compileSdkVersion rootProject.ext.compileSdkVersion | ||
|
||
defaultConfig { | ||
missingDimensionStrategy "store", "play" | ||
applicationId 'com.test.withIAP' | ||
minSdkVersion rootProject.ext.minSdkVersion | ||
targetSdkVersion rootProject.ext.targetSdkVersion | ||
versionCode 34 | ||
versionName "1.16.2" | ||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()`; | ||
|
||
const appBuildGradleWithAmazonStoreIAP = ` | ||
apply plugin: "com.android.application" | ||
|
||
import com.android.build.OutputFile | ||
|
||
def reactNativeArchitectures() { | ||
def value = project.getProperties().get("reactNativeArchitectures") | ||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] | ||
} | ||
|
||
android { | ||
ndkVersion rootProject.ext.ndkVersion | ||
|
||
compileSdkVersion rootProject.ext.compileSdkVersion | ||
|
||
defaultConfig { | ||
missingDimensionStrategy "store", "amazon" | ||
applicationId 'com.test.withIAP' | ||
minSdkVersion rootProject.ext.minSdkVersion | ||
targetSdkVersion rootProject.ext.targetSdkVersion | ||
versionCode 34 | ||
versionName "1.16.2" | ||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()`; | ||
|
||
const appBuildGradleWithBothIAP = ` | ||
apply plugin: "com.android.application" | ||
|
||
import com.android.build.OutputFile | ||
|
||
def reactNativeArchitectures() { | ||
def value = project.getProperties().get("reactNativeArchitectures") | ||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] | ||
} | ||
|
||
android { | ||
ndkVersion rootProject.ext.ndkVersion | ||
|
||
compileSdkVersion rootProject.ext.compileSdkVersion | ||
flavorDimensions "appstore" | ||
|
||
productFlavors { | ||
googlePlay { | ||
dimension "appstore" | ||
missingDimensionStrategy "store", "play" | ||
} | ||
|
||
amazon { | ||
dimension "appstore" | ||
missingDimensionStrategy "store", "amazon" | ||
} | ||
} | ||
|
||
defaultConfig { | ||
applicationId 'com.test.withIAP' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should these be customizable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only a part of some faked |
||
minSdkVersion rootProject.ext.minSdkVersion | ||
targetSdkVersion rootProject.ext.targetSdkVersion | ||
versionCode 34 | ||
versionName "1.16.2" | ||
Comment on lines
+104
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these arbitrary/ do they matter to the person building an expo app? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All files in the |
||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()`; | ||
|
||
const projectBuildGradleWithoutIAP = ` | ||
// Top-level build file where you can add configuration options common to all sub-projects/modules. | ||
|
||
buildscript { | ||
ext { | ||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0' | ||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21') | ||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31') | ||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31') | ||
if (findProperty('android.kotlinVersion')) { | ||
kotlinVersion = findProperty('android.kotlinVersion') | ||
} | ||
frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0' | ||
|
||
if (System.properties['os.arch'] == 'aarch64') { | ||
// For M1 Users we need to use the NDK 24 which added support for aarch64 | ||
ndkVersion = '24.0.8215888' | ||
} else { | ||
// Otherwise we default to the side-by-side NDK version from AGP. | ||
ndkVersion = '21.4.7075529' | ||
} | ||
} | ||
}`; | ||
|
||
const projectBuildGradleWithIAP = ` | ||
// Top-level build file where you can add configuration options common to all sub-projects/modules. | ||
|
||
buildscript { | ||
ext { | ||
supportLibVersion = "28.0.0" | ||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0' | ||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21') | ||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31') | ||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31') | ||
if (findProperty('android.kotlinVersion')) { | ||
kotlinVersion = findProperty('android.kotlinVersion') | ||
} | ||
frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0' | ||
|
||
if (System.properties['os.arch'] == 'aarch64') { | ||
// For M1 Users we need to use the NDK 24 which added support for aarch64 | ||
ndkVersion = '24.0.8215888' | ||
} else { | ||
// Otherwise we default to the side-by-side NDK version from AGP. | ||
ndkVersion = '21.4.7075529' | ||
} | ||
} | ||
}`; | ||
|
||
export { | ||
appBuildGradleWithAmazonStoreIAP, | ||
appBuildGradleWithBothIAP, | ||
appBuildGradleWithoutIAP, | ||
appBuildGradleWithPlayStoreIAP, | ||
projectBuildGradleWithIAP, | ||
projectBuildGradleWithoutIAP, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import {modifyAppBuildGradle, modifyProjectBuildGradle} from '../src/withIAP'; | ||
|
||
import { | ||
appBuildGradleWithAmazonStoreIAP, | ||
appBuildGradleWithBothIAP, | ||
appBuildGradleWithoutIAP, | ||
appBuildGradleWithPlayStoreIAP, | ||
projectBuildGradleWithIAP, | ||
projectBuildGradleWithoutIAP, | ||
} from './fixtures/buildGradleFiles'; | ||
|
||
jest.mock('@expo/config-plugins', () => { | ||
const plugins = jest.requireActual('@expo/config-plugins'); | ||
|
||
return { | ||
...plugins, | ||
WarningAggregator: {addWarningAndroid: jest.fn()}, | ||
}; | ||
}); | ||
|
||
describe('Configures Android native project correctly', () => { | ||
it(`Add supportLibVersion to android/build.gradle if it is not present`, () => { | ||
expect(modifyProjectBuildGradle(projectBuildGradleWithoutIAP)).toMatch( | ||
projectBuildGradleWithIAP, | ||
); | ||
}); | ||
|
||
it(`Add play store missingDimenstionStrategy to android/app/build.gradle if is not present`, () => { | ||
expect( | ||
modifyAppBuildGradle(appBuildGradleWithoutIAP, 'Play Store'), | ||
).toMatch(appBuildGradleWithPlayStoreIAP); | ||
}); | ||
|
||
it(`Add amazon store missingDimenstionStrategy to android/app/build.gradle if is not present`, () => { | ||
expect( | ||
modifyAppBuildGradle(appBuildGradleWithoutIAP, 'Amazon AppStore'), | ||
).toMatch(appBuildGradleWithAmazonStoreIAP); | ||
}); | ||
|
||
it(`Add play store and amazon payment providers to android/app/build.gradle if is not present`, () => { | ||
expect(modifyAppBuildGradle(appBuildGradleWithoutIAP, 'both')).toMatch( | ||
appBuildGradleWithBothIAP, | ||
); | ||
}); | ||
it(`Doesn't modify android/build.gradle if supportLibVersion already configured`, () => { | ||
expect(modifyProjectBuildGradle(projectBuildGradleWithIAP)).toMatch( | ||
projectBuildGradleWithIAP, | ||
); | ||
}); | ||
|
||
it(`Doesn't modify android/app/build.gradle if missingDimensionStrategy already configured`, () => { | ||
expect( | ||
modifyAppBuildGradle(appBuildGradleWithPlayStoreIAP, 'Play Store'), | ||
).toMatch(appBuildGradleWithPlayStoreIAP); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import type {ConfigPlugin} from '@expo/config-plugins'; | ||
declare type PaymentProvider = 'Amazon AppStore' | 'both' | 'Play Store'; | ||
export declare const modifyAppBuildGradle: ( | ||
buildGradle: string, | ||
paymentProvider: PaymentProvider, | ||
) => string; | ||
export declare const modifyProjectBuildGradle: (buildGradle: string) => string; | ||
interface Props { | ||
paymentProvider?: PaymentProvider; | ||
} | ||
declare const withIAP: ConfigPlugin<Props | undefined>; | ||
export default withIAP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like these variables have some duplication, any thoughts on using a common template?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that there is too much of it. In current unit tests implementation, we are passing initial
build.gradle
(part of it to be precise) to the function and comparing the result with the correct version. This is done 3 times, one for eachpaymentProvider
. We could remove irrelevant lines and leave only lines close todefaultConfig
. What do you think?