Skip to content

Commit

Permalink
Merge pull request #4675 from wix/feat/4175-new-arch
Browse files Browse the repository at this point in the history
android(feat):new arch support
  • Loading branch information
gosha212 authored Jan 16, 2025
2 parents f5f64e7 + e5e1002 commit 0e77622
Show file tree
Hide file tree
Showing 59 changed files with 789 additions and 380 deletions.
3 changes: 2 additions & 1 deletion .buildkite/jobs/pipeline.android_rn_73.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
- label: ":android::detox: RN .73 + Android: Tests app"
- label: ":android::detox: (Old Arch) - RN .73 + Android: Tests app"
command:
- "nvm install"
- "./scripts/ci.android.sh"
env:
REACT_NATIVE_VERSION: 0.73.2
DETOX_DISABLE_POD_INSTALL: true
DETOX_DISABLE_POSTINSTALL: true
ENABLE_NEW_ARCH: false
artifact_paths:
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
- "/Users/builder/uibuilder/work/**/allure-report-*.html"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
- label: ":android::detox: RN .75 + Android: Tests app"
- label: ":android::detox: (Old Arch) - RN .76 + Android: Tests app"
command:
- "nvm install"
- "./scripts/ci.android.sh"
env:
REACT_NATIVE_VERSION: 0.75.4
DETOX_DISABLE_POD_INSTALL: true
DETOX_DISABLE_POSTINSTALL: true
ENABLE_NEW_ARCH: false
artifact_paths:
- "/Users/builder/uibuilder/work/coverage/**/*.lcov"
- "/Users/builder/uibuilder/work/**/allure-report-*.html"
Expand Down
2 changes: 1 addition & 1 deletion .buildkite/pipeline_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cat .buildkite/jobs/pipeline.ios_rn_76.yml
cat .buildkite/jobs/pipeline.ios_rn_73.yml
cat .buildkite/jobs/pipeline.ios_demo_app_rn_76_new_arch.yml
cat .buildkite/jobs/pipeline.android_rn_76.yml
cat .buildkite/jobs/pipeline.android_rn_75.yml
cat .buildkite/jobs/pipeline.android_rn_76_old_arch.yml
cat .buildkite/jobs/pipeline.android_rn_73.yml
cat .buildkite/jobs/pipeline.android_demo_app_rn_76.yml
cat .buildkite/pipeline.post_processing.yml
7 changes: 6 additions & 1 deletion detox/android/detox/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ dependencies {
api('androidx.test.uiautomator:uiautomator:2.2.0') {
because 'Needed by Detox but also makes UIAutomator seamlessly provided to Detox users with hybrid apps/E2E-tests.'
}
api('androidx.test:core-ktx:1.6.1') {
because 'Needed by Detox but also makes AndroidX test core seamlessly provided to Detox users with hybrid apps/E2E-tests.'
}
implementation("org.jetbrains.kotlin:kotlin-reflect:$_kotlinVersion") {
because('Needed by Detox for kotlin reflection')
}
}

// Third-party/extension deps.
Expand Down Expand Up @@ -199,7 +205,6 @@ if (rootProject.hasProperty('isOfficialDetoxLib') ||
dependencies {
testImplementation 'org.spekframework.spek2:spek-dsl-jvm:2.0.15'
testImplementation 'org.spekframework.spek2:spek-runner-junit5:2.0.15'
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$_kotlinVersion"
}
}

Expand Down
12 changes: 12 additions & 0 deletions detox/android/detox/proguard-rules-app.pro
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
-keepattributes InnerClasses, Exceptions

-keep class com.facebook.react.fabric.FabricUIManager { *; }
-keep class com.facebook.react.fabric.mounting.MountItemDispatcher { *; }
-keep class com.facebook.react.modules.** { *; }
-keep class com.facebook.react.uimanager.** { *; }
-keep class com.facebook.react.animated.** { *; }
-keep class com.facebook.react.ReactApplication { *; }
-keep class com.facebook.react.ReactNativeHost { *; }
-keep class com.facebook.react.ReactHost { *; }
-keep class com.facebook.react.runtime.ReactHostImpl { *; }
-keep class com.facebook.react.runtime.BridgelessReactContext { *; }
-keep class com.facebook.react.runtime.ReactInstance { *; }
-keep class com.facebook.react.modules.core.JavaTimerManager { *; }

-keep class com.facebook.react.ReactInstanceManager { *; }
-keep class com.facebook.react.ReactInstanceManager** { *; }
-keep class com.facebook.react.ReactInstanceEventListener { *; }
Expand All @@ -18,6 +26,10 @@
-keep class com.reactnativecommunity.asyncstorage.** { *; }

-keep class kotlin.reflect.** { *; }
-keep class kotlin.KotlinVersion { *; }
-keep class kotlin.sequences.** { *; }
-keep class kotlin.Triple { *; }
-keep class kotlin.properties.** { *; }
-keep class kotlin.coroutines.CoroutineDispatcher { *; }
-keep class kotlin.coroutines.CoroutineScope { *; }
-keep class kotlin.coroutines.CoroutineContext { *; }
Expand Down
7 changes: 4 additions & 3 deletions detox/android/detox/src/full/java/com/wix/detox/DetoxMain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ object DetoxMain {
* not by instrumentation itself, but based on the `AppWillTerminateWithError` message; In it's own, it is a good
* thing, but for a reason we're not sure of yet, it is ignored by the test runner at this point in the flow.
*/
@Synchronized
private fun launchActivityOnCue(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
awaitHandshake()
launchActivity(rnHostHolder, activityLaunchHelper)
synchronized(this) {
awaitHandshake()
launchActivity(rnHostHolder, activityLaunchHelper)
}
}

private fun awaitHandshake() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.wix.detox.reactnative

import android.annotation.SuppressLint
import com.facebook.react.ReactApplication
import com.facebook.react.ReactInstanceManager
import com.facebook.react.bridge.ReactContext
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint


fun ReactApplication.getInstanceManagerSafe(): ReactInstanceManager {
return reactNativeHost.reactInstanceManager
?: throw RuntimeException("ReactInstanceManager is null!")
}

@SuppressLint("VisibleForTests")
fun ReactApplication.getCurrentReactContext(): ReactContext? {
return if (isFabricEnabled()) {
reactHost?.currentReactContext
} else {
getInstanceManagerSafe().currentReactContext
}
}

fun ReactApplication.getCurrentReactContextSafe(): ReactContext {
return getCurrentReactContext()
?: throw RuntimeException("ReactContext is null!")
}

/**
* A method to check if Fabric is enabled in the React Native application.
*/
fun isFabricEnabled(): Boolean {
return DefaultNewArchitectureEntryPoint.fabricEnabled
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import android.content.Context
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.facebook.react.ReactApplication
import com.facebook.react.ReactInstanceManager
import com.facebook.react.bridge.ReactContext
import com.wix.detox.LaunchArgs
import com.wix.detox.reactnative.idlingresources.ReactNativeIdlingResources
import com.wix.detox.reactnative.reloader.ReactNativeReloaderFactory

private const val LOG_TAG = "DetoxRNExt"

Expand All @@ -34,9 +34,9 @@ object ReactNativeExtension {
}

(applicationContext as ReactApplication).let {
val reactContext = awaitNewReactNativeContext(it, null)
awaitNewReactNativeContext(it, null)

enableOrDisableSynchronization(reactContext)
enableOrDisableSynchronization(it)
}
}

Expand All @@ -59,12 +59,12 @@ object ReactNativeExtension {
(applicationContext as ReactApplication).let {
clearIdlingResources()

val previousReactContext = getCurrentReactContextSafe(it)
val previousReactContext = it.getCurrentReactContext()

reloadReactNativeInBackground(it)
val reactContext = awaitNewReactNativeContext(it, previousReactContext)
awaitNewReactNativeContext(it, previousReactContext)

enableOrDisableSynchronization(reactContext)
enableOrDisableSynchronization(it)
}
}

Expand All @@ -75,11 +75,7 @@ object ReactNativeExtension {

@JvmStatic
fun enableAllSynchronization(applicationContext: ReactApplication) {
val reactContext = getCurrentReactContextSafe(applicationContext)

if (reactContext != null) {
setupIdlingResources(reactContext)
}
setupIdlingResources(applicationContext)
}

@JvmStatic
Expand All @@ -88,7 +84,7 @@ object ReactNativeExtension {
@JvmStatic
fun getRNActivity(applicationContext: Context): Activity? {
if (ReactNativeInfo.isReactNativeApp()) {
return getCurrentReactContextSafe(applicationContext as ReactApplication)?.currentActivity
return (applicationContext as ReactApplication).getCurrentReactContext()?.currentActivity
}
return null
}
Expand All @@ -115,20 +111,27 @@ object ReactNativeExtension {
}

private fun reloadReactNativeInBackground(reactApplication: ReactApplication) {
val rnReloader = ReactNativeReLoader(InstrumentationRegistry.getInstrumentation(), reactApplication)
val rnReloader = ReactNativeReloaderFactory(InstrumentationRegistry.getInstrumentation(), reactApplication).create()
rnReloader.reloadInBackground()
}

private fun awaitNewReactNativeContext(reactApplication: ReactApplication, previousReactContext: ReactContext?): ReactContext {
val rnLoadingMonitor = ReactNativeLoadingMonitor(InstrumentationRegistry.getInstrumentation(), reactApplication, previousReactContext)
private fun awaitNewReactNativeContext(
reactApplication: ReactApplication,
previousReactContext: ReactContext?
): ReactContext {
val rnLoadingMonitor = ReactNativeLoadingMonitor(
InstrumentationRegistry.getInstrumentation(),
reactApplication,
previousReactContext
)
return rnLoadingMonitor.getNewContext()!!
}

private fun enableOrDisableSynchronization(reactContext: ReactContext) {
private fun enableOrDisableSynchronization(reactApplication: ReactApplication) {
if (shouldDisableSynchronization()) {
clearAllSynchronization()
} else {
setupIdlingResources(reactContext)
setupIdlingResources(reactApplication)
}
}

Expand All @@ -137,10 +140,10 @@ object ReactNativeExtension {
return launchArgs.hasEnableSynchronization() && launchArgs.enableSynchronization.equals("0")
}

private fun setupIdlingResources(reactContext: ReactContext) {
private fun setupIdlingResources(reactApplication: ReactApplication) {
val launchArgs = LaunchArgs()

rnIdlingResources = ReactNativeIdlingResources(reactContext, launchArgs).apply {
rnIdlingResources = ReactNativeIdlingResources(reactApplication, launchArgs).apply {
registerAll()
}
}
Expand All @@ -150,12 +153,4 @@ object ReactNativeExtension {
rnIdlingResources = null
}

private fun getInstanceManagerSafe(reactApplication: ReactApplication): ReactInstanceManager {
return reactApplication.reactNativeHost.reactInstanceManager
?: throw RuntimeException("ReactInstanceManager is null!")
}

private fun getCurrentReactContextSafe(reactApplication: ReactApplication): ReactContext? {
return getInstanceManagerSafe(reactApplication).currentReactContext
}
}
Loading

0 comments on commit 0e77622

Please sign in to comment.