Skip to content

Commit

Permalink
feat: expo config plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
hyochan committed Aug 14, 2024
1 parent 5520ad3 commit ba1965e
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
open_collective: react-native-iap
buy_me_a_coffee: dooboolab
1 change: 1 addition & 0 deletions app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./plugin/build/withIAP');
12 changes: 3 additions & 9 deletions example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"plugins": [
[
"expo-build-properties",
{
"ios": {
"deploymentTarget": "15.0"
}
}
]
["expo-build-properties", {"ios": {"deploymentTarget": "15.0"}}],
["../app.plugin.js"]
],
"splash": {
"image": "./assets/splash.png",
Expand Down Expand Up @@ -43,4 +37,4 @@
"url": "https://u.expo.dev/db487b8b-afc5-4850-8f1b-006e97822308"
}
}
}
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"expo-module": "expo-module",
"open:ios": "xed example/ios",
"open:android": "open -a \"Android Studio\" example/android",
"lint:kotlin": "ktlint --format ./android"
"lint:kotlin": "ktlint --format ./android",
"build:plugin": "tsc --build plugin",
"clean:plugin": "expo-module clean plugin",
"lint:plugin": "eslint plugin/src/*"
},
"keywords": [
"react-native",
Expand Down
164 changes: 164 additions & 0 deletions plugin/__tests__/fixtures/buildGradleFiles.ts
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'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 34
versionName "1.16.2"
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,
};
56 changes: 56 additions & 0 deletions plugin/__tests__/withIAP-test.ts
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);
});
});
5 changes: 5 additions & 0 deletions plugin/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// In documentation there is `preset: expo-module-scripts`, but it runs tests for every platform (ios, android, web, node)
// We need only node tests right now
module.exports = {
preset: 'jest-expo/node',
};
Loading

0 comments on commit ba1965e

Please sign in to comment.