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

A mechanism for listening to lifecycle events in RNTA #275

Merged
merged 16 commits into from
Feb 5, 2021
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
25 changes: 12 additions & 13 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@ def hermesEngineDir =
def hermesAndroidDir = "$hermesEngineDir/android"

buildscript {
ext.kotlinVersion = "1.4.20"

def buildscriptDir = buildscript.sourceFile.getParent()
apply from: "$buildscriptDir/../test-app-util.gradle"
def androidDir = "${buildscript.sourceFile.getParent()}/../"
apply from: "$androidDir/test-app-util.gradle"
apply from: "$androidDir/dependencies.gradle"

repositories {
google()
jcenter()
}

dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "com.android.tools.build:gradle:4.0.2"
}
}

Expand All @@ -45,15 +42,15 @@ apply from: file("${testAppDir}/test-app.gradle")
applyTestAppModule(project, "com.microsoft.reacttestapp")

project.ext.react = [
appName: getAppName(),
appName : getAppName(),
applicationId: getApplicationId(),
enableFlipper: getFlipperVersion(rootDir),
enableHermes : true,
]

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
compileSdkVersion sdk.version
buildToolsVersion sdk.buildToolsVersion

// TODO: Remove this block when minSdkVersion >= 24. See
// https://stackoverflow.com/q/53402639 for details.
Expand All @@ -69,10 +66,10 @@ android {

defaultConfig {
applicationId project.ext.react.applicationId
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
minSdkVersion sdk.minVersion
targetSdkVersion sdk.version
versionCode rntaVersion.code
versionName rntaVersion.label

resValue "string", "app_name", project.ext.react.appName

Expand All @@ -94,6 +91,8 @@ android {
}

dependencies {
implementation project(":support")

implementation "com.google.dagger:dagger:2.28.3"
implementation "com.google.dagger:dagger-android:2.28.3"
implementation "com.google.dagger:dagger-android-support:2.28.3"
Expand Down
18 changes: 16 additions & 2 deletions android/app/src/main/java/com/microsoft/reacttestapp/TestApp.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.microsoft.reacttestapp

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.microsoft.reacttestapp.di.DaggerTestAppComponent
import com.microsoft.reacttestapp.react.TestAppReactNativeHost
import com.microsoft.reacttestapp.support.ReactTestAppLifecycleEvents
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
Expand All @@ -20,13 +22,25 @@ class TestApp : Application(), HasAndroidInjector, ReactApplication {
override fun onCreate() {
super.onCreate()

val eventConsumers = PackageList(this).packages
.filter { it is ReactTestAppLifecycleEvents }
.map { it as ReactTestAppLifecycleEvents }

eventConsumers.forEach { it.onTestAppInitialized() }

val testAppComponent = DaggerTestAppComponent.builder()
.binds(this)
.build()

testAppComponent.inject(this)

reactNativeHostInternal.init()
reactNativeHostInternal.init(
beforeReactNativeInit = {
eventConsumers.forEach { it.onTestAppWillInitializeReactNative() }
},
afterReactNativeInit = {
eventConsumers.forEach { it.onTestAppDidInitializeReactNative() }
},
)
}

override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,24 @@ class TestAppReactNativeHost @Inject constructor(

var onBundleSourceChanged: ((newSource: BundleSource) -> Unit)? = null

fun init() {
fun init(beforeReactNativeInit: () -> Unit, afterReactNativeInit: () -> Unit) {
if (BuildConfig.DEBUG && hasInstance()) {
error("init() can only be called once on startup")
}

val reactInstanceListener = object : ReactInstanceManager.ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext?) {
afterReactNativeInit()

// proactively removing the listener to avoid leaking memory
// and to avoid dupe calls to afterReactNativeInit()
reactInstanceManager.removeReactInstanceEventListener(this)
}
}

reactInstanceManager.addReactInstanceEventListener(reactInstanceListener)

beforeReactNativeInit()
SoLoader.init(application, false)
reactInstanceManager.createReactContextInBackground()

Expand Down
13 changes: 13 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
buildscript {
arazabishov marked this conversation as resolved.
Show resolved Hide resolved
repositories {
jcenter()
google()
}

def buildscriptDir = buildscript.sourceFile.getParent()
apply from: "$buildscriptDir/dependencies.gradle"

dependencies {
classpath "com.android.tools.build:gradle:$androidPluginVersion"
}
}
15 changes: 15 additions & 0 deletions android/dependencies.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ext {
androidPluginVersion = "4.0.2"
kotlinVersion = "1.4.20"

rntaVersion = [
code : 1,
label: "1.0"
]

sdk = [
version : 29,
minVersion : 21,
buildToolsVersion: "29.0.3"
]
}
6 changes: 5 additions & 1 deletion android/react-native-build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
buildscript {
def buildscriptDir = buildscript.sourceFile.getParent()
apply from: "$buildscriptDir/dependencies.gradle"

repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "com.android.tools.build:gradle:$androidPluginVersion"
classpath 'de.undercouch:gradle-download-task:4.1.1'
}
}
Expand Down
2 changes: 1 addition & 1 deletion android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name='react-test-app'
include ':app'
include ':app', ':support'
26 changes: 26 additions & 0 deletions android/support/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
repositories {
jcenter()
google()
}

apply plugin: "com.android.library"

def androidDir = "${buildscript.sourceFile.getParent()}/../"
apply from: "$androidDir/dependencies.gradle"

android {
compileSdkVersion sdk.version
buildToolsVersion sdk.buildToolsVersion

defaultConfig {
minSdkVersion sdk.minVersion
targetSdkVersion sdk.version
versionCode rntaVersion.code
versionName rntaVersion.label
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
2 changes: 2 additions & 0 deletions android/support/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.microsoft.reacttestapp.support" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.microsoft.reacttestapp.support;

public interface ReactTestAppLifecycleEvents {
void onTestAppInitialized();
void onTestAppWillInitializeReactNative();
void onTestAppDidInitializeReactNative();
}
13 changes: 12 additions & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
arazabishov marked this conversation as resolved.
Show resolved Hide resolved
apply from: file("../node_modules/react-native-test-app/android/dependencies.gradle")

repositories {
jcenter()
arazabishov marked this conversation as resolved.
Show resolved Hide resolved
google()
}

dependencies {
classpath "com.android.tools.build:gradle:$androidPluginVersion"
}
}
2 changes: 2 additions & 0 deletions example/ios/ExampleTests/DevSupportTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ @implementation DevSupportTests
- (void)testDevSupportIsLinked
{
XCTAssertNotNil(ReactTestAppDidInitializeNotification);
XCTAssertNotNil(ReactTestAppWillInitializeReactNativeNotification);
XCTAssertNotNil(ReactTestAppDidInitializeReactNativeNotification);
XCTAssertNotNil(ReactTestAppSceneDidOpenURLNotification);
}

Expand Down
8 changes: 8 additions & 0 deletions ios/ReactTestApp/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
self.application = application

defer {
NotificationCenter.default.post(
name: .ReactTestAppDidInitialize,
object: nil
)
}

return true
}

Expand Down
2 changes: 2 additions & 0 deletions ios/ReactTestApp/Public/ReactTestApp-DevSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
NS_ASSUME_NONNULL_BEGIN

extern NSNotificationName const ReactTestAppDidInitializeNotification;
extern NSNotificationName const ReactTestAppWillInitializeReactNativeNotification;
extern NSNotificationName const ReactTestAppDidInitializeReactNativeNotification;
extern NSNotificationName const ReactTestAppSceneDidOpenURLNotification;

NS_ASSUME_NONNULL_END
9 changes: 8 additions & 1 deletion ios/ReactTestApp/ReactInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ final class ReactInstance: NSObject, RCTBridgeDelegate {
}

func initReact(onDidInitialize: @escaping () -> Void) {
if bridge == nil {
NotificationCenter.default.post(
name: .ReactTestAppWillInitializeReactNative,
object: nil
)
}

if let bridge = bridge {
if remoteBundleURL == nil {
// When loading the embedded bundle, we must disable remote
Expand All @@ -109,7 +116,7 @@ final class ReactInstance: NSObject, RCTBridgeDelegate {
self.bridge = bridge

NotificationCenter.default.post(
name: .ReactTestAppDidInitialize,
name: .ReactTestAppDidInitializeReactNative,
object: bridge
)

Expand Down
4 changes: 4 additions & 0 deletions ios/ReactTestApp/ReactTestApp-DevSupport.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@

NSNotificationName const ReactTestAppDidInitializeNotification =
@"ReactTestAppDidInitializeNotification";
NSNotificationName const ReactTestAppWillInitializeReactNativeNotification =
@"ReactTestAppWillInitializeReactNativeNotification";
NSNotificationName const ReactTestAppDidInitializeReactNativeNotification =
@"ReactTestAppDidInitializeReactNativeNotification";
NSNotificationName const ReactTestAppSceneDidOpenURLNotification =
@"ReactTestAppSceneDidOpenURLNotification";
5 changes: 5 additions & 0 deletions plopfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ module.exports = (/** @type {import("plop").NodePlopAPI} */ plop) => {
path: `${prefix}gradlew.bat`,
templateFile: path.join(androidTemplateDir, "gradlew.bat"),
});
actions.push({
type: "add",
path: `${prefix}build.gradle`,
templateFile: path.join(androidTemplateDir, "build.gradle"),
});
actions.push({
type: "add",
path: `${prefix}settings.gradle`,
Expand Down
4 changes: 4 additions & 0 deletions test-app.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ private static void apply(Settings settings) {
}

settings.include(":app")
settings.include(":support")
arazabishov marked this conversation as resolved.
Show resolved Hide resolved

settings.project(":app")
.projectDir = new File("${projectDir}/android/app")
settings.project(":support")
.projectDir = new File("${projectDir}/android/support")
}

def scriptDir = buildscript.sourceFile.getParent()
Expand Down