Skip to content
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

feat(app-distribution): add Expo config plugin for App Distribution #8211

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app-distribution/usage/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ cd ios/ && pod install

## Add the App Distribution Plugin

> 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!
> 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.

On Android, you need to install the Google App Distribution Plugin.

Expand Down
1 change: 1 addition & 0 deletions packages/app-distribution/app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./plugin/build');
15 changes: 13 additions & 2 deletions packages/app-distribution/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"scripts": {
"build": "genversion --semi lib/version.js",
"build:clean": "rimraf android/build && rimraf ios/build",
"prepare": "yarn run build"
"build:plugin": "rimraf plugin/build && tsc --build plugin",
"lint:plugin": "eslint plugin/src/*",
"prepare": "yarn run build && yarn run build:plugin"
},
"repository": {
"type": "git",
Expand All @@ -22,7 +24,16 @@
"app-distribution"
],
"peerDependencies": {
"@react-native-firebase/app": "21.6.2"
"@react-native-firebase/app": "21.6.2",
"expo": ">=47.0.0"
},
"devDependencies": {
"expo": "^50.0.21"
},
"peerDependenciesMeta": {
"expo": {
"optional": true
}
},
"publishConfig": {
"access": "public"
Expand Down
1 change: 1 addition & 0 deletions packages/app-distribution/plugin/__tests__/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Please see the `packages/app/plugin/__tests__/README.md`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`App distribution Plugin Android Tests applies app distribution classpath to project build.gradle 1`] = `
"// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext {
buildToolsVersion = "29.0.3"
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
}
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.google.firebase:firebase-appdistribution-gradle:5.0.0'
classpath("com.android.tools.build:gradle:4.1.0")

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}

google()
jcenter()
maven { url 'https://www.jitpack.io' }
}
}
"
`;

exports[`App distribution Plugin Android Tests applies app distribution plugin to app/build.gradle 1`] = `
"/* Example build.gradle file from https://github.com/expo/expo/blob/6ab0274b5cb9a9c223e0d453787a522b438b4fcb/templates/expo-template-bare-minimum/android/app/build.gradle */

apply plugin: "com.android.application"

import com.android.build.OutputFile


project.ext.react = [
enableHermes: false
]

apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/expo-constants/scripts/get-app-config-android.gradle"
apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"

def enableSeparateBuildPerCPUArchitecture = false

def enableProguardInReleaseBuilds = false

def jscFlavor = 'org.webkit:android-jsc:+'

def enableHermes = project.ext.react.get("enableHermes", false);

android {
compileSdkVersion rootProject.ext.compileSdkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
applicationId "com.helloworld"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}

// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}

}
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:\${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:\${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:\${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
addUnimodulesDependencies()

if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

apply plugin: 'com.google.firebase.appdistribution'"
`;
32 changes: 32 additions & 0 deletions packages/app-distribution/plugin/__tests__/androidPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import fs from 'fs/promises';
import path from 'path';
import { beforeAll, describe, expect, it } from '@jest/globals';

import { applyPlugin } from '../src/android/applyPlugin';
import { setBuildscriptDependency } from '../src/android/buildscriptDependency';

describe('App distribution Plugin Android Tests', function () {
let appBuildGradle: string;
let projectBuildGradle: string;

beforeAll(async function () {
projectBuildGradle = await fs.readFile(
path.resolve(__dirname, './fixtures/project_build.gradle'),
{ encoding: 'utf-8' },
);

appBuildGradle = await fs.readFile(path.resolve(__dirname, './fixtures/app_build.gradle'), {
encoding: 'utf-8',
});
});

it('applies app distribution classpath to project build.gradle', async function () {
const result = setBuildscriptDependency(projectBuildGradle);
expect(result).toMatchSnapshot();
});

it('applies app distribution plugin to app/build.gradle', async function () {
const result = applyPlugin(appBuildGradle);
expect(result).toMatchSnapshot();
});
});
118 changes: 118 additions & 0 deletions packages/app-distribution/plugin/__tests__/fixtures/app_build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* Example build.gradle file from https://github.com/expo/expo/blob/6ab0274b5cb9a9c223e0d453787a522b438b4fcb/templates/expo-template-bare-minimum/android/app/build.gradle */

apply plugin: "com.android.application"

import com.android.build.OutputFile


project.ext.react = [
enableHermes: false
]

apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/expo-constants/scripts/get-app-config-android.gradle"
apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"

def enableSeparateBuildPerCPUArchitecture = false

def enableProguardInReleaseBuilds = false

def jscFlavor = 'org.webkit:android-jsc:+'

def enableHermes = project.ext.react.get("enableHermes", false);

android {
compileSdkVersion rootProject.ext.compileSdkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
applicationId "com.helloworld"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}

// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}

}
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
addUnimodulesDependencies()

if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
Loading
Loading