From f45c9004bb4b84457a337e24b0a46c58ab3822d9 Mon Sep 17 00:00:00 2001 From: Georgy Steshin Date: Tue, 1 Apr 2025 16:08:10 +0300 Subject: [PATCH 1/6] Implemented turbo modules for android --- lib/android/app/build.gradle | 5 +- .../react/NavigationPackage.kt | 40 ++- .../react/NavigationTurboModule.kt | 276 ++++++++++++++++++ lib/android/build.gradle | 42 ++- package.json | 2 +- 5 files changed, 335 insertions(+), 30 deletions(-) create mode 100644 lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index 669e84e2024..4f1f6c8e65a 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -3,6 +3,9 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat apply plugin: 'com.android.library' apply plugin: 'kotlin-android' +apply plugin: "com.facebook.react" + + def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback @@ -193,7 +196,7 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesCore" implementation "androidx.constraintlayout:constraintlayout:2.0.4" - implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.annotation:annotation:1.2.0' implementation 'com.google.android.material:material:1.2.0-alpha03' diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt index 2796d689227..5702dbf1c30 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt @@ -1,27 +1,41 @@ package com.reactnativenavigation.react +import com.facebook.react.BaseReactPackage import com.facebook.react.ReactApplication -import com.facebook.react.ReactHost -import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.uimanager.ViewManager import com.reactnativenavigation.options.LayoutFactory import com.reactnativenavigation.react.modal.ModalViewManager -class NavigationPackage() : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - val reactApp = reactContext.applicationContext as ReactApplication - return listOf( - NavigationModule( - reactContext, - LayoutFactory(reactApp.reactHost) - ) - ) +class NavigationPackage() : BaseReactPackage() { + + override fun getModule(name: String, context: ReactApplicationContext): NativeModule? { + val reactApp = context.applicationContext as ReactApplication + return when (name) { + NavigationTurboModule.NAME -> { + NavigationTurboModule(context, LayoutFactory(reactApp.reactHost)) + } + else -> { + null + } + } } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { + override fun getReactModuleInfoProvider() = ReactModuleInfoProvider { + mapOf(NavigationTurboModule.NAME to ReactModuleInfo( + _name = NavigationTurboModule.NAME, + _className = NavigationTurboModule.NAME, + _canOverrideExistingModule = false, + _needsEagerInit = false, + isCxxModule = false, + isTurboModule = true + )) + } - return listOf(ModalViewManager(reactContext)) + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return mutableListOf(ModalViewManager(reactContext)) } } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt new file mode 100644 index 00000000000..6f33f56f6cc --- /dev/null +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt @@ -0,0 +1,276 @@ +package com.reactnativenavigation.react + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableMap +import com.reactnativenavigation.NavigationActivity +import com.reactnativenavigation.NavigationApplication +import com.reactnativenavigation.options.LayoutFactory +import com.reactnativenavigation.options.Options +import com.reactnativenavigation.options.parsers.JSONParser +import com.reactnativenavigation.options.parsers.LayoutNodeParser +import com.reactnativenavigation.options.parsers.TypefaceLoader +import com.reactnativenavigation.react.events.EventEmitter +import com.reactnativenavigation.utils.LaunchArgsParser +import com.reactnativenavigation.utils.Now +import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarHeight +import com.reactnativenavigation.utils.UiThread +import com.reactnativenavigation.utils.UiUtils +import com.reactnativenavigation.viewcontrollers.navigator.Navigator +import java.util.Objects + +class NavigationTurboModule( + reactContext: ReactApplicationContext, + private val layoutFactory: LayoutFactory +) : NativeRNNTurboModuleSpec(reactContext) { + + private val now = Now() + private val jsonParser: JSONParser = JSONParser() + private lateinit var eventEmitter: EventEmitter + + init { + reactContext.addLifecycleEventListener(object : LifecycleEventListenerAdapter() { + override fun onHostPause() { + super.onHostPause() + UiUtils.runOnMainThread { + navigator().onHostPause() + } + } + + override fun onHostResume() { + eventEmitter = EventEmitter(reactContext) + navigator().setEventEmitter(eventEmitter) + layoutFactory.init( + activity(), + eventEmitter, + navigator().getChildRegistry(), + (activity().application as NavigationApplication).externalComponents + ) + UiUtils.runOnMainThread { navigator().onHostResume() } + } + }) + } + + override fun getTypedExportedConstants(): MutableMap { + val constants = mutableMapOf() + constants[Constants.BACK_BUTTON_JS_KEY] = Constants.BACK_BUTTON_ID + constants[Constants.BOTTOM_TABS_HEIGHT_KEY] = + UiUtils.pxToDp( + reactApplicationContext, + UiUtils.getBottomTabsHeight(reactApplicationContext).toFloat() + ).toDouble() + constants[Constants.STATUS_BAR_HEIGHT_KEY] = + UiUtils.pxToDp(reactApplicationContext, getStatusBarHeight(currentActivity).toFloat()) + .toDouble() + constants[Constants.TOP_BAR_HEIGHT_KEY] = UiUtils.pxToDp( + reactApplicationContext, + UiUtils.getTopBarHeight(reactApplicationContext).toFloat() + ).toDouble() + return constants + } + + override fun setRoot(commandId: String, layout: ReadableMap, promise: Promise) { + val layoutTree = LayoutNodeParser.parse( + Objects.requireNonNull( + jsonParser.parse(layout).optJSONObject("root") + ) + ) + handle { + val viewController = layoutFactory.create(layoutTree) + navigator().setRoot( + viewController, + NativeCommandListener("setRoot", commandId, promise, eventEmitter, now) + ) + } + } + + override fun setDefaultOptions(options: ReadableMap?) { + handle { + val defaultOptions = parse(options) + layoutFactory.defaultOptions = defaultOptions + navigator().defaultOptions = defaultOptions + } + } + + override fun mergeOptions(componentId: String?, options: ReadableMap?) { + handle { navigator().mergeOptions(componentId, parse(options)) } + } + + override fun push( + commandId: String, + componentId: String, + layout: ReadableMap, + promise: Promise + ) { + val layoutTree = LayoutNodeParser.parse(jsonParser.parse(layout)) + handle { + val viewController = layoutFactory.create(layoutTree) + navigator().push( + componentId, + viewController, + NativeCommandListener("push", commandId, promise, eventEmitter, now) + ) + } + } + + override fun pop( + commandId: String, + componentId: String, + options: ReadableMap, + promise: Promise + ) { + handle { + navigator().pop( + componentId, + parse(options), + NativeCommandListener("pop", commandId, promise, eventEmitter, now) + ) + } + } + + override fun popTo( + commandId: String, + componentId: String, + options: ReadableMap, + promise: Promise + ) { + handle { + navigator().popTo( + componentId, + parse(options), + NativeCommandListener("popTo", commandId, promise, eventEmitter, now) + ) + } + } + + override fun popToRoot( + commandId: String, + componentId: String, + options: ReadableMap, + promise: Promise + ) { + handle { + navigator().popToRoot( + componentId, + parse(options), + NativeCommandListener("popToRoot", commandId, promise, eventEmitter, now) + ) + } + } + + override fun setStackRoot( + commandId: String, + componentId: String, + children: ReadableMap, + promise: Promise + ) { + TODO("Not yet implemented") + + } + + override fun showModal(commandId: String, layout: ReadableMap, promise: Promise) { + val layoutTree = LayoutNodeParser.parse(jsonParser.parse(layout)) + handle { + val viewController = layoutFactory.create(layoutTree) + navigator().showModal( + viewController, + NativeCommandListener("showModal", commandId, promise, eventEmitter, now) + ) + } + } + + override fun dismissModal( + commandId: String, + componentId: String, + options: ReadableMap, + promise: Promise + ) { + handle { + navigator().mergeOptions(componentId, parse(options)) + navigator().dismissModal( + componentId, + NativeCommandListener("dismissModal", commandId, promise, eventEmitter, now) + ) + } + } + + override fun dismissAllModals(commandId: String, options: ReadableMap, promise: Promise) { + handle { + navigator().dismissAllModals( + parse(options), + NativeCommandListener("dismissAllModals", commandId, promise, eventEmitter, now) + ) + } + } + + override fun showOverlay(commandId: String, layout: ReadableMap, promise: Promise) { + val layoutTree = LayoutNodeParser.parse(jsonParser.parse(layout)) + handle { + val viewController = layoutFactory.create(layoutTree) + navigator().showOverlay( + viewController, + NativeCommandListener("showOverlay", commandId, promise, eventEmitter, now) + ) + } + } + + override fun dismissOverlay(commandId: String, componentId: String, promise: Promise) { + handle { + navigator().dismissOverlay( + componentId, + NativeCommandListener("dismissOverlay", commandId, promise, eventEmitter, now) + ) + } + } + + override fun dismissAllOverlays(commandId: String, promise: Promise) { + handle { + navigator().dismissAllOverlays( + NativeCommandListener( + "dismissAllOverlays", + commandId, + promise, + eventEmitter, + now + ) + ) + } + } + + override fun getLaunchArgs(commandId: String, promise: Promise) { + promise.resolve(LaunchArgsParser.parse(activity())) + + } + + private fun parse(mergeOptions: ReadableMap?): Options { + val ctx = reactApplicationContext + return if (mergeOptions == + null + ) Options.EMPTY else Options.parse( + ctx, + TypefaceLoader(activity()), + jsonParser.parse(mergeOptions) + ) + } + + private fun navigator(): Navigator { + return activity().navigator + } + + private fun handle(task: Runnable) { + UiThread.post { + if (currentActivity != null && !activity().isFinishing) { + task.run() + } + } + } + + private fun activity(): NavigationActivity { + return currentActivity as NavigationActivity + } + + companion object { + const val NAME = "RNNTurboModule" + } + +} diff --git a/lib/android/build.gradle b/lib/android/build.gradle index f50281142e7..f851a530228 100644 --- a/lib/android/build.gradle +++ b/lib/android/build.gradle @@ -2,20 +2,25 @@ buildscript { ext { - RNNKotlinVersion = '1.4.31' - appCompatVersion = '1.6.0-alpha05' + kotlinVersion = "1.9.24" + RNNKotlinVersion = kotlinVersion + detoxKotlinVersion = kotlinVersion + compileSdkVersion = 35 + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + targetSdkVersion = 34 + ndkVersion = "26.1.10909125" } repositories { - mavenLocal() - mavenCentral() google() - jcenter() + mavenCentral() } - dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31" + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath("com.facebook.react:react-native-gradle-plugin") + classpath 'com.android.tools.build:gradle' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -23,13 +28,20 @@ buildscript { allprojects { repositories { - mavenLocal() - mavenCentral() - google() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../../node_modules/react-native/android" + maven { url "$rootDir/../../node_modules/detox/Detox-android" } + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } + flatDir { + dirs "$rootProject.projectDir/libs" + } + } +} + +subprojects { + afterEvaluate { p -> + if (p.hasProperty('android')) { + android { + buildToolsVersion rootProject.ext.buildToolsVersion + } } } } diff --git a/package.json b/package.json index 988b23c10de..a025b5d976d 100644 --- a/package.json +++ b/package.json @@ -260,7 +260,7 @@ "type": "all", "jsSrcsDir": "./lib/src", "android": { - "javaPackageName": "wix.rnn.specs" + "javaPackageName": "com.reactnativenavigation.react" } } } \ No newline at end of file From 2f6f069f41992fb4c4a2d06c1fc2718cbd189cc6 Mon Sep 17 00:00:00 2001 From: Georgy Steshin Date: Sun, 6 Apr 2025 14:17:10 +0300 Subject: [PATCH 2/6] Implemented missing method --- .../react/NavigationTurboModule.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt index 6f33f56f6cc..37efdcf9042 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt @@ -1,7 +1,9 @@ package com.reactnativenavigation.react +import android.util.Log import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.reactnativenavigation.NavigationActivity import com.reactnativenavigation.NavigationApplication @@ -17,6 +19,7 @@ import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarHeight import com.reactnativenavigation.utils.UiThread import com.reactnativenavigation.utils.UiUtils import com.reactnativenavigation.viewcontrollers.navigator.Navigator +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController import java.util.Objects class NavigationTurboModule( @@ -70,12 +73,14 @@ class NavigationTurboModule( } override fun setRoot(commandId: String, layout: ReadableMap, promise: Promise) { + Log.d("NavigationTurboModule", "setRoot ${Thread.currentThread()}") val layoutTree = LayoutNodeParser.parse( Objects.requireNonNull( jsonParser.parse(layout).optJSONObject("root") ) ) handle { + Log.d("NavigationTurboModule", "setRoot handle ${Thread.currentThread()}") val viewController = layoutFactory.create(layoutTree) navigator().setRoot( viewController, @@ -161,11 +166,21 @@ class NavigationTurboModule( override fun setStackRoot( commandId: String, componentId: String, - children: ReadableMap, + children: ReadableArray, promise: Promise ) { - TODO("Not yet implemented") - + handle { + val _children = ArrayList>() + for (i in 0.. Date: Mon, 14 Apr 2025 15:14:49 +0300 Subject: [PATCH 3/6] Complete Android Turbo module implementation --- .../react/NavigationTurboModule.kt | 10 ++--- lib/src/adapters/NativeCommandsSender.ts | 24 +++++----- lib/src/adapters/NativeRNNTurboModule.ts | 44 ++++++++++--------- lib/src/commands/Commands.test.ts | 4 +- package-lock.json | 4 +- 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt index 37efdcf9042..ac132fb5a7a 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationTurboModule.kt @@ -121,7 +121,7 @@ class NavigationTurboModule( override fun pop( commandId: String, componentId: String, - options: ReadableMap, + options: ReadableMap?, promise: Promise ) { handle { @@ -136,7 +136,7 @@ class NavigationTurboModule( override fun popTo( commandId: String, componentId: String, - options: ReadableMap, + options: ReadableMap?, promise: Promise ) { handle { @@ -151,7 +151,7 @@ class NavigationTurboModule( override fun popToRoot( commandId: String, componentId: String, - options: ReadableMap, + options: ReadableMap?, promise: Promise ) { handle { @@ -197,7 +197,7 @@ class NavigationTurboModule( override fun dismissModal( commandId: String, componentId: String, - options: ReadableMap, + options: ReadableMap?, promise: Promise ) { handle { @@ -209,7 +209,7 @@ class NavigationTurboModule( } } - override fun dismissAllModals(commandId: String, options: ReadableMap, promise: Promise) { + override fun dismissAllModals(commandId: String, options: ReadableMap?, promise: Promise) { handle { navigator().dismissAllModals( parse(options), diff --git a/lib/src/adapters/NativeCommandsSender.ts b/lib/src/adapters/NativeCommandsSender.ts index e82f40bafca..f98ba21d08a 100644 --- a/lib/src/adapters/NativeCommandsSender.ts +++ b/lib/src/adapters/NativeCommandsSender.ts @@ -1,5 +1,5 @@ import { NavigationConstants } from './Constants'; -import RNNCommandsModule from './NativeRNNTurboModule'; +import RNNCommandsModule, { Spec } from './NativeRNNTurboModule'; interface NativeCommandsModule { setRoot(commandId: string, layout: { root: any; modals: any[]; overlays: any[] }): Promise; @@ -9,7 +9,7 @@ interface NativeCommandsModule { pop(commandId: string, componentId: string, options?: object): Promise; popTo(commandId: string, componentId: string, options?: object): Promise; popToRoot(commandId: string, componentId: string, options?: object): Promise; - setStackRoot(commandId: string, onComponentId: string, layout: object): Promise; + setStackRoot(commandId: string, onComponentId: string, layout: object[]): Promise; showModal(commandId: string, layout: object): Promise; dismissModal(commandId: string, componentId: string, options?: object): Promise; dismissAllModals(commandId: string, options?: object): Promise; @@ -17,16 +17,20 @@ interface NativeCommandsModule { dismissOverlay(commandId: string, componentId: string): Promise; dismissAllOverlays(commandId: string): Promise; getLaunchArgs(commandId: string): Promise; - getNavigationConstants(): Promise; - getNavigationConstantsSync(): NavigationConstants; // Turbo getConstants?: () => NavigationConstants; } -export class NativeCommandsSender { - private readonly nativeCommandsModule: NativeCommandsModule; +export class NativeCommandsSender implements NativeCommandsModule { + private readonly nativeCommandsModule: Spec; constructor() { - this.nativeCommandsModule = RNNCommandsModule; + const commands = RNNCommandsModule; + if (!commands) { + throw new Error( + 'RNNCommandsModule is not available. Make sure you are using the new architecture.' + ); + } + this.nativeCommandsModule = commands; } setRoot(commandId: string, layout: { root: any; modals: any[]; overlays: any[] }) { @@ -57,7 +61,7 @@ export class NativeCommandsSender { return this.nativeCommandsModule.popToRoot(commandId, componentId, options); } - setStackRoot(commandId: string, onComponentId: string, layout: object) { + setStackRoot(commandId: string, onComponentId: string, layout: object[]) { return this.nativeCommandsModule.setStackRoot(commandId, onComponentId, layout); } @@ -90,10 +94,10 @@ export class NativeCommandsSender { } getNavigationConstants() { - return this.nativeCommandsModule.getNavigationConstants(); + return Promise.resolve(this.nativeCommandsModule.getConstants()); } getNavigationConstantsSync() { - return this.nativeCommandsModule.getNavigationConstantsSync(); + return this.nativeCommandsModule.getConstants(); } } diff --git a/lib/src/adapters/NativeRNNTurboModule.ts b/lib/src/adapters/NativeRNNTurboModule.ts index 808a9d71faa..026e8bf8b1e 100644 --- a/lib/src/adapters/NativeRNNTurboModule.ts +++ b/lib/src/adapters/NativeRNNTurboModule.ts @@ -1,4 +1,4 @@ -import { TurboModule, TurboModuleRegistry, NativeModules, Platform } from 'react-native'; +import { TurboModule, TurboModuleRegistry } from 'react-native'; import { UnsafeObject, Double } from 'react-native/Libraries/Types/CodegenTypes'; export interface Spec extends TurboModule { @@ -6,42 +6,44 @@ export interface Spec extends TurboModule { topBarHeight: Double; statusBarHeight: Double; bottomTabsHeight: Double; + backButtonId: string; }; setRoot(commandId: string, layout: UnsafeObject): Promise; + setDefaultOptions(options: UnsafeObject): void; + mergeOptions(componentId: string, options: UnsafeObject): void; + push(commandId: string, componentId: string, layout: UnsafeObject): Promise; - pop(commandId: string, componentId: string, options: UnsafeObject): Promise; - popTo(commandId: string, componentId: string, options: UnsafeObject): Promise; - popToRoot(commandId: string, componentId: string, options: UnsafeObject): Promise; + + pop(commandId: string, componentId: string, options?: UnsafeObject): Promise; + + popTo(commandId: string, componentId: string, options?: UnsafeObject): Promise; + + popToRoot(commandId: string, componentId: string, options?: UnsafeObject): Promise; + setStackRoot( commandId: string, componentId: string, layout: Array ): Promise; + showModal(commandId: string, layout: UnsafeObject): Promise; - dismissModal(commandId: string, componentId: string, options: UnsafeObject): Promise; - dismissAllModals(commandId: string, options: UnsafeObject): Promise; + + dismissModal(commandId: string, componentId: string, options?: UnsafeObject): Promise; + + dismissAllModals(commandId: string, options?: UnsafeObject): Promise; + showOverlay(commandId: string, layout: UnsafeObject): Promise; - dismissOverlay(commandId: string, componentId: string): Promise; - dismissAllOverlays(commandId: string): Promise; - getLaunchArgs(commandId: string): Promise>; -} -const isTurboModuleEnabled = (globalThis as any).__turboModuleProxy != null; + dismissOverlay(commandId: string, componentId: string): Promise; -const commands = - isTurboModuleEnabled && Platform.OS === 'ios' - ? TurboModuleRegistry.get('RNNTurboModule') - : NativeModules.RNNBridgeModule; + dismissAllOverlays(commandId: string): Promise; -const isNewArchWithBridgeless = isTurboModuleEnabled; + getLaunchArgs(commandId: string): Promise>; +} -export const RCTAssertNewArchEnabled = () => { - if (!isNewArchWithBridgeless) - throw new Error('Allowed only in New Architecture with Bridgeless!'); -}; +const commands = TurboModuleRegistry.get('RNNTurboModule'); -export const isRNNTurboModuleAvailable = isNewArchWithBridgeless; export default commands; diff --git a/lib/src/commands/Commands.test.ts b/lib/src/commands/Commands.test.ts index 3f8c3febea7..f03b9d87560 100644 --- a/lib/src/commands/Commands.test.ts +++ b/lib/src/commands/Commands.test.ts @@ -634,10 +634,10 @@ describe('Commands', () => { describe('dismissOverlay', () => { it('check promise returns true', async () => { - when(mockedNativeCommandsSender.dismissOverlay(anyString(), anyString())).thenResolve(true); + when(mockedNativeCommandsSender.dismissOverlay(anyString(), anyString())).thenResolve('true'); const result = await uut.dismissOverlay('Component1'); verify(mockedNativeCommandsSender.dismissOverlay(anyString(), anyString())).called(); - expect(result).toEqual(true); + expect(result).toEqual('true'); }); it('send command to native with componentId', () => { diff --git a/package-lock.json b/package-lock.json index a404aa05ac0..bdebe3125ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-navigation", - "version": "8.0.0", + "version": "8.1.0-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-navigation", - "version": "8.0.0", + "version": "8.1.0-alpha", "license": "MIT", "dependencies": { "hoist-non-react-statics": "3.x.x", From 97ebc4a1c5743fc9afec13ae076d5dbb784c8fa1 Mon Sep 17 00:00:00 2001 From: Georgy Steshin Date: Mon, 14 Apr 2025 17:05:42 +0300 Subject: [PATCH 4/6] Complete Android Turbo module implementation --- lib/android/app/build.gradle | 4 ++++ lib/src/adapters/NativeCommandsSender.ts | 8 +------- lib/src/adapters/NativeRNNTurboModule.ts | 2 +- package.json | 7 ++----- playground/android/app/build.gradle | 5 +++++ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index 4f1f6c8e65a..3f348f7e537 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -6,6 +6,10 @@ apply plugin: 'kotlin-android' apply plugin: "com.facebook.react" +react { + codegenJavaPackageName = "com.reactnativenavigation.react" +} + def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback diff --git a/lib/src/adapters/NativeCommandsSender.ts b/lib/src/adapters/NativeCommandsSender.ts index f98ba21d08a..3801f8206bb 100644 --- a/lib/src/adapters/NativeCommandsSender.ts +++ b/lib/src/adapters/NativeCommandsSender.ts @@ -24,13 +24,7 @@ interface NativeCommandsModule { export class NativeCommandsSender implements NativeCommandsModule { private readonly nativeCommandsModule: Spec; constructor() { - const commands = RNNCommandsModule; - if (!commands) { - throw new Error( - 'RNNCommandsModule is not available. Make sure you are using the new architecture.' - ); - } - this.nativeCommandsModule = commands; + this.nativeCommandsModule = RNNCommandsModule; } setRoot(commandId: string, layout: { root: any; modals: any[]; overlays: any[] }) { diff --git a/lib/src/adapters/NativeRNNTurboModule.ts b/lib/src/adapters/NativeRNNTurboModule.ts index 026e8bf8b1e..1942edc2239 100644 --- a/lib/src/adapters/NativeRNNTurboModule.ts +++ b/lib/src/adapters/NativeRNNTurboModule.ts @@ -44,6 +44,6 @@ export interface Spec extends TurboModule { getLaunchArgs(commandId: string): Promise>; } -const commands = TurboModuleRegistry.get('RNNTurboModule'); +const commands = TurboModuleRegistry.get('RNNTurboModule')!; export default commands; diff --git a/package.json b/package.json index a025b5d976d..9d403179e69 100644 --- a/package.json +++ b/package.json @@ -258,9 +258,6 @@ "codegenConfig": { "name": "rnnavigation", "type": "all", - "jsSrcsDir": "./lib/src", - "android": { - "javaPackageName": "com.reactnativenavigation.react" - } + "jsSrcsDir": "./lib/src" } -} \ No newline at end of file +} diff --git a/playground/android/app/build.gradle b/playground/android/app/build.gradle index 0382536bb1b..ff1328ad09a 100644 --- a/playground/android/app/build.gradle +++ b/playground/android/app/build.gradle @@ -5,6 +5,7 @@ react { root = file("../../../") reactNativeDir = file("../../../node_modules/react-native") codegenDir = file("../../../node_modules/@react-native/codegen") + codegenJavaPackageName = "com.reactnativenavigation.playground" autolinkLibrariesWithApp() } @@ -47,6 +48,10 @@ android { signingConfig signingConfigs.release } } + packagingOptions { + exclude "**/NativeRNNTurboEventEmitterSpec.**" + exclude "**/NativeRNNTurboModuleManagerSpec.**" + } } dependencies { From 160d8694116b7470a7e9737e6f58da03dae4e347 Mon Sep 17 00:00:00 2001 From: Georgy Steshin Date: Mon, 14 Apr 2025 17:14:08 +0300 Subject: [PATCH 5/6] Undo some unneeded fixes --- lib/src/adapters/NativeCommandsSender.ts | 2 ++ playground/android/app/build.gradle | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/adapters/NativeCommandsSender.ts b/lib/src/adapters/NativeCommandsSender.ts index 3801f8206bb..f442e3e292d 100644 --- a/lib/src/adapters/NativeCommandsSender.ts +++ b/lib/src/adapters/NativeCommandsSender.ts @@ -17,6 +17,8 @@ interface NativeCommandsModule { dismissOverlay(commandId: string, componentId: string): Promise; dismissAllOverlays(commandId: string): Promise; getLaunchArgs(commandId: string): Promise; + getNavigationConstants(): Promise; + getNavigationConstantsSync(): NavigationConstants; // Turbo getConstants?: () => NavigationConstants; } diff --git a/playground/android/app/build.gradle b/playground/android/app/build.gradle index ff1328ad09a..e950fed9345 100644 --- a/playground/android/app/build.gradle +++ b/playground/android/app/build.gradle @@ -48,10 +48,6 @@ android { signingConfig signingConfigs.release } } - packagingOptions { - exclude "**/NativeRNNTurboEventEmitterSpec.**" - exclude "**/NativeRNNTurboModuleManagerSpec.**" - } } dependencies { From 912b03557938aab58a5c7b5490015394db96cb71 Mon Sep 17 00:00:00 2001 From: Georgy Steshin Date: Sun, 20 Apr 2025 15:33:29 +0300 Subject: [PATCH 6/6] Fixed build on ios --- lib/ios/Constants.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/ios/Constants.mm b/lib/ios/Constants.mm index 74bbd440354..bbc89da6590 100644 --- a/lib/ios/Constants.mm +++ b/lib/ios/Constants.mm @@ -16,7 +16,8 @@ + (NSDictionary *)getConstants { JS::NativeRNNTurboModule::Constants::Builder::Input input = { [self topBarHeight], [self statusBarHeight], - [self bottomTabsHeight] + [self bottomTabsHeight], + [self backButtonId] }; return input; @@ -35,4 +36,9 @@ + (CGFloat)bottomTabsHeight { return [UIApplication.sharedApplication.delegate.window.rootViewController getBottomTabsHeight]; } ++ (NSString*)backButtonId { + // This property is used only in android but we have to add it for compatability in turbo modules + return @""; +} + @end