Skip to content

Commit 9b5c405

Browse files
ceafivemikehardy
authored andcommitted
feat(app-distribution): add Android app distribution plugin and configuration
1 parent 4939028 commit 9b5c405

File tree

16 files changed

+474
-4
lines changed

16 files changed

+474
-4
lines changed

docs/app-distribution/usage/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ cd ios/ && pod install
2424

2525
## Add the App Distribution Plugin
2626

27-
> This module does not handle Expo config plugins yet but does require a native integration similar to the perf module. If you want to add support for Expo to the App Distribution module we would welcome a PR!
27+
> If you're using Expo, make sure to add the `@react-native-firebase/app-distribution` config plugin to your `app.json` or `app.config.js`. It handles the below installation steps for you. For instructions on how to do that, view the [Expo](/#expo) installation section.
2828
2929
On Android, you need to install the Google App Distribution Plugin.
3030

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./plugin/build');

packages/app-distribution/package.json

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"scripts": {
99
"build": "genversion --semi lib/version.js",
1010
"build:clean": "rimraf android/build && rimraf ios/build",
11-
"prepare": "yarn run build"
11+
"build:plugin": "rimraf plugin/build && tsc --build plugin",
12+
"lint:plugin": "eslint plugin/src/*",
13+
"prepare": "yarn run build && yarn run build:plugin"
1214
},
1315
"repository": {
1416
"type": "git",
@@ -22,7 +24,16 @@
2224
"app-distribution"
2325
],
2426
"peerDependencies": {
25-
"@react-native-firebase/app": "21.6.2"
27+
"@react-native-firebase/app": "21.6.2",
28+
"expo": ">=47.0.0"
29+
},
30+
"devDependencies": {
31+
"expo": "^50.0.21"
32+
},
33+
"peerDependenciesMeta": {
34+
"expo": {
35+
"optional": true
36+
}
2637
},
2738
"publishConfig": {
2839
"access": "public"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Please see the `packages/app/plugin/__tests__/README.md`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`App distribution Plugin Android Tests applies app distribution classpath to project build.gradle 1`] = `
4+
"// Top-level build file where you can add configuration options common to all sub-projects/modules.
5+
6+
buildscript {
7+
ext {
8+
buildToolsVersion = "29.0.3"
9+
minSdkVersion = 21
10+
compileSdkVersion = 30
11+
targetSdkVersion = 30
12+
}
13+
repositories {
14+
google()
15+
jcenter()
16+
}
17+
dependencies {
18+
classpath 'com.google.firebase:firebase-appdistribution-gradle:5.0.0'
19+
classpath("com.android.tools.build:gradle:4.1.0")
20+
21+
// NOTE: Do not place your application dependencies here; they belong
22+
// in the individual module build.gradle files
23+
}
24+
}
25+
26+
allprojects {
27+
repositories {
28+
mavenLocal()
29+
maven {
30+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
31+
url("$rootDir/../node_modules/react-native/android")
32+
}
33+
maven {
34+
// Android JSC is installed from npm
35+
url("$rootDir/../node_modules/jsc-android/dist")
36+
}
37+
38+
google()
39+
jcenter()
40+
maven { url 'https://www.jitpack.io' }
41+
}
42+
}
43+
"
44+
`;
45+
46+
exports[`App distribution Plugin Android Tests applies app distribution plugin to app/build.gradle 1`] = `
47+
"/* Example build.gradle file from https://github.com/expo/expo/blob/6ab0274b5cb9a9c223e0d453787a522b438b4fcb/templates/expo-template-bare-minimum/android/app/build.gradle */
48+
49+
apply plugin: "com.android.application"
50+
51+
import com.android.build.OutputFile
52+
53+
54+
project.ext.react = [
55+
enableHermes: false
56+
]
57+
58+
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
59+
apply from: "../../node_modules/react-native/react.gradle"
60+
apply from: "../../node_modules/expo-constants/scripts/get-app-config-android.gradle"
61+
apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"
62+
63+
def enableSeparateBuildPerCPUArchitecture = false
64+
65+
def enableProguardInReleaseBuilds = false
66+
67+
def jscFlavor = 'org.webkit:android-jsc:+'
68+
69+
def enableHermes = project.ext.react.get("enableHermes", false);
70+
71+
android {
72+
compileSdkVersion rootProject.ext.compileSdkVersion
73+
74+
compileOptions {
75+
sourceCompatibility JavaVersion.VERSION_1_8
76+
targetCompatibility JavaVersion.VERSION_1_8
77+
}
78+
79+
defaultConfig {
80+
applicationId "com.helloworld"
81+
minSdkVersion rootProject.ext.minSdkVersion
82+
targetSdkVersion rootProject.ext.targetSdkVersion
83+
versionCode 1
84+
versionName "1.0"
85+
}
86+
splits {
87+
abi {
88+
reset()
89+
enable enableSeparateBuildPerCPUArchitecture
90+
universalApk false // If true, also generate a universal APK
91+
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
92+
}
93+
}
94+
signingConfigs {
95+
debug {
96+
storeFile file('debug.keystore')
97+
storePassword 'android'
98+
keyAlias 'androiddebugkey'
99+
keyPassword 'android'
100+
}
101+
}
102+
buildTypes {
103+
debug {
104+
signingConfig signingConfigs.debug
105+
}
106+
release {
107+
// Caution! In production, you need to generate your own keystore file.
108+
// see https://reactnative.dev/docs/signed-apk-android.
109+
signingConfig signingConfigs.debug
110+
minifyEnabled enableProguardInReleaseBuilds
111+
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
112+
}
113+
}
114+
115+
// applicationVariants are e.g. debug, release
116+
applicationVariants.all { variant ->
117+
variant.outputs.each { output ->
118+
// For each separate APK per architecture, set a unique version code as described here:
119+
// https://developer.android.com/studio/build/configure-apk-splits.html
120+
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
121+
def abi = output.getFilter(OutputFile.ABI)
122+
if (abi != null) { // null for the universal-debug, universal-release variants
123+
output.versionCodeOverride =
124+
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
125+
}
126+
127+
}
128+
}
129+
}
130+
131+
dependencies {
132+
implementation fileTree(dir: "libs", include: ["*.jar"])
133+
//noinspection GradleDynamicVersion
134+
implementation "com.facebook.react:react-native:+" // From node_modules
135+
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
136+
debugImplementation("com.facebook.flipper:flipper:\${FLIPPER_VERSION}") {
137+
exclude group:'com.facebook.fbjni'
138+
}
139+
debugImplementation("com.facebook.flipper:flipper-network-plugin:\${FLIPPER_VERSION}") {
140+
exclude group:'com.facebook.flipper'
141+
exclude group:'com.squareup.okhttp3', module:'okhttp'
142+
}
143+
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:\${FLIPPER_VERSION}") {
144+
exclude group:'com.facebook.flipper'
145+
}
146+
addUnimodulesDependencies()
147+
148+
if (enableHermes) {
149+
def hermesPath = "../../node_modules/hermes-engine/android/";
150+
debugImplementation files(hermesPath + "hermes-debug.aar")
151+
releaseImplementation files(hermesPath + "hermes-release.aar")
152+
} else {
153+
implementation jscFlavor
154+
}
155+
}
156+
157+
// Run this once to be able to run the application with BUCK
158+
// puts all compile dependencies into folder libs for BUCK to use
159+
task copyDownloadableDepsToLibs(type: Copy) {
160+
from configurations.compile
161+
into 'libs'
162+
}
163+
164+
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
165+
166+
apply plugin: 'com.google.firebase.appdistribution'"
167+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import fs from 'fs/promises';
2+
import path from 'path';
3+
import { beforeAll, describe, expect, it } from '@jest/globals';
4+
5+
import { applyPlugin } from '../src/android/applyPlugin';
6+
import { setBuildscriptDependency } from '../src/android/buildscriptDependency';
7+
8+
describe('App distribution Plugin Android Tests', function () {
9+
let appBuildGradle: string;
10+
let projectBuildGradle: string;
11+
12+
beforeAll(async function () {
13+
projectBuildGradle = await fs.readFile(
14+
path.resolve(__dirname, './fixtures/project_build.gradle'),
15+
{ encoding: 'utf-8' },
16+
);
17+
18+
appBuildGradle = await fs.readFile(path.resolve(__dirname, './fixtures/app_build.gradle'), {
19+
encoding: 'utf-8',
20+
});
21+
});
22+
23+
it('applies app distribution classpath to project build.gradle', async function () {
24+
const result = setBuildscriptDependency(projectBuildGradle);
25+
expect(result).toMatchSnapshot();
26+
});
27+
28+
it('applies app distribution plugin to app/build.gradle', async function () {
29+
const result = applyPlugin(appBuildGradle);
30+
expect(result).toMatchSnapshot();
31+
});
32+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* Example build.gradle file from https://github.com/expo/expo/blob/6ab0274b5cb9a9c223e0d453787a522b438b4fcb/templates/expo-template-bare-minimum/android/app/build.gradle */
2+
3+
apply plugin: "com.android.application"
4+
5+
import com.android.build.OutputFile
6+
7+
8+
project.ext.react = [
9+
enableHermes: false
10+
]
11+
12+
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
13+
apply from: "../../node_modules/react-native/react.gradle"
14+
apply from: "../../node_modules/expo-constants/scripts/get-app-config-android.gradle"
15+
apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"
16+
17+
def enableSeparateBuildPerCPUArchitecture = false
18+
19+
def enableProguardInReleaseBuilds = false
20+
21+
def jscFlavor = 'org.webkit:android-jsc:+'
22+
23+
def enableHermes = project.ext.react.get("enableHermes", false);
24+
25+
android {
26+
compileSdkVersion rootProject.ext.compileSdkVersion
27+
28+
compileOptions {
29+
sourceCompatibility JavaVersion.VERSION_1_8
30+
targetCompatibility JavaVersion.VERSION_1_8
31+
}
32+
33+
defaultConfig {
34+
applicationId "com.helloworld"
35+
minSdkVersion rootProject.ext.minSdkVersion
36+
targetSdkVersion rootProject.ext.targetSdkVersion
37+
versionCode 1
38+
versionName "1.0"
39+
}
40+
splits {
41+
abi {
42+
reset()
43+
enable enableSeparateBuildPerCPUArchitecture
44+
universalApk false // If true, also generate a universal APK
45+
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
46+
}
47+
}
48+
signingConfigs {
49+
debug {
50+
storeFile file('debug.keystore')
51+
storePassword 'android'
52+
keyAlias 'androiddebugkey'
53+
keyPassword 'android'
54+
}
55+
}
56+
buildTypes {
57+
debug {
58+
signingConfig signingConfigs.debug
59+
}
60+
release {
61+
// Caution! In production, you need to generate your own keystore file.
62+
// see https://reactnative.dev/docs/signed-apk-android.
63+
signingConfig signingConfigs.debug
64+
minifyEnabled enableProguardInReleaseBuilds
65+
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
66+
}
67+
}
68+
69+
// applicationVariants are e.g. debug, release
70+
applicationVariants.all { variant ->
71+
variant.outputs.each { output ->
72+
// For each separate APK per architecture, set a unique version code as described here:
73+
// https://developer.android.com/studio/build/configure-apk-splits.html
74+
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
75+
def abi = output.getFilter(OutputFile.ABI)
76+
if (abi != null) { // null for the universal-debug, universal-release variants
77+
output.versionCodeOverride =
78+
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
79+
}
80+
81+
}
82+
}
83+
}
84+
85+
dependencies {
86+
implementation fileTree(dir: "libs", include: ["*.jar"])
87+
//noinspection GradleDynamicVersion
88+
implementation "com.facebook.react:react-native:+" // From node_modules
89+
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
90+
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
91+
exclude group:'com.facebook.fbjni'
92+
}
93+
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
94+
exclude group:'com.facebook.flipper'
95+
exclude group:'com.squareup.okhttp3', module:'okhttp'
96+
}
97+
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
98+
exclude group:'com.facebook.flipper'
99+
}
100+
addUnimodulesDependencies()
101+
102+
if (enableHermes) {
103+
def hermesPath = "../../node_modules/hermes-engine/android/";
104+
debugImplementation files(hermesPath + "hermes-debug.aar")
105+
releaseImplementation files(hermesPath + "hermes-release.aar")
106+
} else {
107+
implementation jscFlavor
108+
}
109+
}
110+
111+
// Run this once to be able to run the application with BUCK
112+
// puts all compile dependencies into folder libs for BUCK to use
113+
task copyDownloadableDepsToLibs(type: Copy) {
114+
from configurations.compile
115+
into 'libs'
116+
}
117+
118+
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

0 commit comments

Comments
 (0)