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

android(feat):new arch support #4675

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0a0328f
Enabled fabric WIP
gosha212 Dec 19, 2024
9b4d3c6
Create isFabric implementation
gosha212 Dec 23, 2024
bc925ac
Fixed react native reloader to work with new arch.
gosha212 Dec 24, 2024
e86edb9
WIP
gosha212 Dec 24, 2024
8f379a9
Implemented fabric idling resources
gosha212 Dec 24, 2024
01aa325
Updated proguard to support fabric
gosha212 Dec 25, 2024
1fa2bbd
Fixed build for RN 75
gosha212 Dec 25, 2024
93ea9d7
Fixed tests
gosha212 Dec 25, 2024
47d36d4
Fixed tests
gosha212 Dec 25, 2024
3aa86fd
Fixed storage idling resources
gosha212 Dec 25, 2024
158f416
Fixed timer idling resources build on rn 75 and 74
gosha212 Dec 25, 2024
b0680d0
Fixed release builds for all rn versions
gosha212 Dec 25, 2024
1929161
Fixed timers idling resources reflection
gosha212 Dec 25, 2024
e83a829
Fixed timers idling resources reflection
gosha212 Dec 25, 2024
9694324
Fixed reflection in timers idling resources
gosha212 Dec 25, 2024
1f3f97a
Fixed timers idling resources reflection
gosha212 Dec 25, 2024
af2a963
Fixed timers idling resources reflection
gosha212 Dec 29, 2024
ac8a266
Fixed timers idling resources reflection
gosha212 Dec 29, 2024
d9e4ca0
Fixed timers idling resources reflection
gosha212 Dec 29, 2024
4f3564a
Fixed screenshot tests
gosha212 Dec 29, 2024
e58225f
Fixed tests
gosha212 Dec 29, 2024
41024a8
Fixed demo app to work with fabric
gosha212 Dec 29, 2024
c84e835
Fixed demo app to work with fabric
gosha212 Dec 29, 2024
85265eb
Fixed proguard to support release builds
gosha212 Dec 29, 2024
d3943bd
Updated gradle wrapper version
gosha212 Dec 29, 2024
178bec8
Changed pipeline names
gosha212 Dec 29, 2024
3de2795
Changed pipeline names
gosha212 Dec 29, 2024
36ccf80
Fixed scripts to support rn 73
gosha212 Dec 29, 2024
10a2877
Minor refacotring
gosha212 Jan 7, 2025
c7138bb
Run rn 73 with old arch only
gosha212 Jan 8, 2025
fef978d
Fixed React Native Loading Monitoring
gosha212 Jan 12, 2025
b21d9d1
Fixed idling resources raise condition
gosha212 Jan 12, 2025
3559343
Merge branch 'master' into feat/4175-new-arch
gosha212 Jan 13, 2025
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 .buildkite/jobs/pipeline.android_demo_app_rn_76.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- label: ":android::react: RN .76 + Android: Demo app"
- label: ":android::react: (New Arch) - RN .76 + Android: Demo app"
command:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not testing both new arch and old arch on .76?
Is that a breaking change?

- "nvm install"
- "./scripts/demo-projects.android.sh"
Expand Down
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
3 changes: 2 additions & 1 deletion .buildkite/jobs/pipeline.android_rn_75.yml
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 .75 + 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/jobs/pipeline.android_rn_76.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- label: ":android::detox: RN .76 + Android: Tests app"
- label: ":android::detox: (New Arch) - RN .76 + Android: Tests app"
command:
- "nvm install"
- "./scripts/ci.android.sh"
Expand Down
5 changes: 4 additions & 1 deletion detox/android/detox/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ 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.'
}
}

// Third-party/extension deps.
Expand Down Expand Up @@ -199,7 +202,7 @@ 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"
implementation "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
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,29 @@
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.getCurrentReactContextSafe(): ReactContext? {
return if (isFabricEnabled()) {
reactHost?.currentReactContext
} else {
getInstanceManagerSafe().currentReactContext
}
}

/**
* 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,11 @@ 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.ReactNativeReLoader
import com.wix.detox.reactnative.reloader.ReactNativeReloaderFactory

private const val LOG_TAG = "DetoxRNExt"

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

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

enableOrDisableSynchronization(reactContext)
enableOrDisableSynchronization(it)
}
}

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

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

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

enableOrDisableSynchronization(reactContext)
enableOrDisableSynchronization(it)
}
}

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

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

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

@JvmStatic
Expand All @@ -88,7 +85,7 @@ object ReactNativeExtension {
@JvmStatic
fun getRNActivity(applicationContext: Context): Activity? {
if (ReactNativeInfo.isReactNativeApp()) {
return getCurrentReactContextSafe(applicationContext as ReactApplication)?.currentActivity
return (applicationContext as ReactApplication).getCurrentReactContextSafe()?.currentActivity
}
return null
}
Expand All @@ -115,20 +112,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 +141,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 +154,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
Loading