From 403feb9bc25226120daf1daa1ec401b263b7e833 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Mon, 28 Apr 2025 01:53:11 -0700 Subject: [PATCH] Migrate ReactActivity (#50871) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50871 # Changelog: [Android][Changed] - ReactActivity has been migrated to Kotlin. Reviewed By: cortinico Differential Revision: D73507044 fbshipit-source-id: 936263100ca93dafd643a53e5cb799fd5ed7e584 --- .../main/java/com/helloworld/MainActivity.kt | 3 +- .../com/facebook/react/ReactActivity.java | 162 ------------------ .../java/com/facebook/react/ReactActivity.kt | 136 +++++++++++++++ .../facebook/react/ReactActivityDelegate.java | 2 +- .../defaults/DefaultReactActivityDelegate.kt | 2 +- .../facebook/react/uiapp/RNTesterActivity.kt | 9 +- 6 files changed, 145 insertions(+), 169 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.kt diff --git a/packages/helloworld/android/app/src/main/java/com/helloworld/MainActivity.kt b/packages/helloworld/android/app/src/main/java/com/helloworld/MainActivity.kt index 07c47370090..ab901fe5f1c 100644 --- a/packages/helloworld/android/app/src/main/java/com/helloworld/MainActivity.kt +++ b/packages/helloworld/android/app/src/main/java/com/helloworld/MainActivity.kt @@ -18,7 +18,8 @@ class MainActivity : ReactActivity() { * Returns the name of the main component registered from JavaScript. This is used to schedule * rendering of the component. */ - override fun getMainComponentName(): String = "HelloWorld" + override val mainComponentName: String? + get() = "HelloWorld" /** * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java deleted file mode 100644 index 757ba90d5be..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react; - -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.KeyEvent; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.modules.core.PermissionAwareActivity; -import com.facebook.react.modules.core.PermissionListener; -import org.jetbrains.annotations.NotNull; - -/** Base Activity for React Native applications. */ -public abstract class ReactActivity extends AppCompatActivity - implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { - - private final ReactActivityDelegate mDelegate; - - protected ReactActivity() { - mDelegate = createReactActivityDelegate(); - } - - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. e.g. "MoviesApp" - */ - protected @Nullable String getMainComponentName() { - return null; - } - - /** Called at construction time, override if you have a custom delegate implementation. */ - protected ReactActivityDelegate createReactActivityDelegate() { - return new ReactActivityDelegate(this, getMainComponentName()); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mDelegate.onCreate(savedInstanceState); - } - - @Override - protected void onPause() { - super.onPause(); - mDelegate.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - mDelegate.onResume(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mDelegate.onDestroy(); - } - - public @Nullable ReactDelegate getReactDelegate() { - return mDelegate.getReactDelegate(); - } - - public ReactActivityDelegate getReactActivityDelegate() { - return mDelegate; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - mDelegate.onActivityResult(requestCode, resultCode, data); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return mDelegate.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return mDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - return mDelegate.onKeyLongPress(keyCode, event) || super.onKeyLongPress(keyCode, event); - } - - @Override - public void onBackPressed() { - if (!mDelegate.onBackPressed()) { - super.onBackPressed(); - } - } - - @Override - public void invokeDefaultOnBackPressed() { - super.onBackPressed(); - } - - @Override - public void onNewIntent(Intent intent) { - if (!mDelegate.onNewIntent(intent)) { - super.onNewIntent(intent); - } - } - - @Override - public void onUserLeaveHint() { - super.onUserLeaveHint(); - mDelegate.onUserLeaveHint(); - } - - @Override - public void requestPermissions( - String[] permissions, int requestCode, PermissionListener listener) { - mDelegate.requestPermissions(permissions, requestCode, listener); - } - - @Override - public void onRequestPermissionsResult( - int requestCode, @NotNull String[] permissions, @NotNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - mDelegate.onWindowFocusChanged(hasFocus); - } - - @Override - public void onConfigurationChanged(@NotNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mDelegate.onConfigurationChanged(newConfig); - } - - protected final ReactNativeHost getReactNativeHost() { - return mDelegate.getReactNativeHost(); - } - - protected ReactHost getReactHost() { - return mDelegate.getReactHost(); - } - - protected final ReactInstanceManager getReactInstanceManager() { - return mDelegate.getReactInstanceManager(); - } - - protected final void loadApp(String appKey) { - mDelegate.loadApp(appKey); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.kt new file mode 100644 index 00000000000..4eb90518da1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.kt @@ -0,0 +1,136 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react + +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.view.KeyEvent +import androidx.appcompat.app.AppCompatActivity +import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler +import com.facebook.react.modules.core.PermissionAwareActivity +import com.facebook.react.modules.core.PermissionListener + +/** Base Activity for React Native applications. */ +public abstract class ReactActivity protected constructor() : + AppCompatActivity(), DefaultHardwareBackBtnHandler, PermissionAwareActivity { + + public open val reactActivityDelegate: ReactActivityDelegate = createReactActivityDelegate() + + public open val reactDelegate: ReactDelegate? + get() = reactActivityDelegate.reactDelegate + + protected open val reactHost: ReactHost? + get() = reactActivityDelegate.reactHost + + protected val reactNativeHost: ReactNativeHost + get() = reactActivityDelegate.reactNativeHost + + protected val reactInstanceManager: ReactInstanceManager + get() = reactActivityDelegate.reactInstanceManager + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. e.g. "MoviesApp" + */ + protected open val mainComponentName: String? + get() = null + + /** Called at construction time, override if you have a custom delegate implementation. */ + protected open fun createReactActivityDelegate(): ReactActivityDelegate { + return ReactActivityDelegate(this, mainComponentName) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + reactActivityDelegate.onCreate(savedInstanceState) + } + + override fun onPause() { + super.onPause() + reactActivityDelegate.onPause() + } + + override fun onResume() { + super.onResume() + reactActivityDelegate.onResume() + } + + override fun onDestroy() { + super.onDestroy() + reactActivityDelegate.onDestroy() + } + + override public fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + reactActivityDelegate.onActivityResult(requestCode, resultCode, data) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean = + reactActivityDelegate.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event) + + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean = + reactActivityDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event) + + override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean = + reactActivityDelegate.onKeyLongPress(keyCode, event) || super.onKeyLongPress(keyCode, event) + + @Suppress("DEPRECATION") + @Deprecated("Deprecated in Java") + override fun onBackPressed() { + if (!reactActivityDelegate.onBackPressed()) { + super.onBackPressed() + } + } + + override fun invokeDefaultOnBackPressed() { + @Suppress("DEPRECATION") super.onBackPressed() + } + + override public fun onNewIntent(intent: Intent) { + if (!reactActivityDelegate.onNewIntent(intent)) { + super.onNewIntent(intent) + } + } + + override public fun onUserLeaveHint() { + super.onUserLeaveHint() + reactActivityDelegate.onUserLeaveHint() + } + + override fun requestPermissions( + permissions: Array, + requestCode: Int, + listener: PermissionListener? + ) { + reactActivityDelegate.requestPermissions(permissions, requestCode, listener) + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + reactActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults) + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + reactActivityDelegate.onWindowFocusChanged(hasFocus) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + reactActivityDelegate.onConfigurationChanged(newConfig) + } + + protected fun loadApp(appKey: String?) { + reactActivityDelegate.loadApp(appKey) + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index 13892ad72b0..3b15b287b07 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -110,7 +110,7 @@ public class ReactActivityDelegate { return mReactDelegate.getReactInstanceManager(); } - public String getMainComponentName() { + public @Nullable String getMainComponentName() { return mMainComponentName; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt index 4cb4263c41c..2c2ee7e8d0a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt @@ -21,7 +21,7 @@ import com.facebook.react.ReactActivityDelegate */ public open class DefaultReactActivityDelegate( activity: ReactActivity, - mainComponentName: String, + mainComponentName: String?, private val fabricEnabled: Boolean = false, ) : ReactActivityDelegate(activity, mainComponentName) { diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt index 13ed22d2e6c..0b453b32b7e 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterActivity.kt @@ -22,7 +22,7 @@ import java.io.FileDescriptor import java.io.PrintWriter internal class RNTesterActivity : ReactActivity() { - class RNTesterActivityDelegate(val activity: ReactActivity, mainComponentName: String) : + class RNTesterActivityDelegate(val activity: ReactActivity, mainComponentName: String?) : DefaultReactActivityDelegate(activity, mainComponentName, fabricEnabled) { private val PARAM_ROUTE = "route" private lateinit var initialProps: Bundle @@ -43,6 +43,9 @@ internal class RNTesterActivity : ReactActivity() { if (this::initialProps.isInitialized) initialProps else Bundle() } + override val mainComponentName: String? + get() = "RNTesterApp" + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -52,7 +55,7 @@ internal class RNTesterActivity : ReactActivity() { this.window?.setBackgroundDrawable(ColorDrawable(Color.BLACK)) // register insets listener to update margins on the ReactRootView to avoid overlap w/ system // bars - getReactDelegate()?.getReactRootView()?.let { rootView -> + reactDelegate?.getReactRootView()?.let { rootView -> val insetsType: Int = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() @@ -71,8 +74,6 @@ internal class RNTesterActivity : ReactActivity() { override fun createReactActivityDelegate() = RNTesterActivityDelegate(this, mainComponentName) - override fun getMainComponentName() = "RNTesterApp" - override fun dump( prefix: String, fd: FileDescriptor?,