Android 生命周期监听器
编辑页面
了解一种机制,该机制允许你的库使用 Expo 模块 API 挂钩到 Android Activity 和 Application 函数。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
To respond to certain Android system events relevant to an app, such as inbound links and configuration changes, it is necessary to override the corresponding lifecycle callbacks in MainActivity.java and/or MainApplication.java.
React Native 模块 API 并没有提供任何机制来接入这些回调,因此 React Native 库的设置说明中经常会包含将代码复制到这些文件中的步骤。为了简化并自动化设置与维护,Expo Modules API 提供了一种机制,允许你的库接入 Activity 或 Application 的函数。
开始使用
首先,你需要已经创建了一个 Expo 模块,或者使用 React Native 模块 API 将 Expo Modules API 集成到该库中。了解更多。
在你的模块内部,创建一个实现 Package 接口的具体类。对于大多数情况,你只需要实现 createReactActivityLifecycleListeners 或 createApplicationLifecycleListeners 方法。
Activity 生命周期监听器
你可以使用 ReactActivityLifecycleListener 接入 Activity 生命周期。ReactActivityLifecycleListener 通过 ReactActivityDelegate 接入 React Native 的 ReactActivity 生命周期,并提供类似 Android Activity 生命周期的体验。
当前支持以下 Activity 生命周期回调:
onCreateonResumeonPauseonDestroyonNewIntentonBackPressed
要创建一个 ReactActivityLifecycleListener,你应该在派生的 Package 类中实现 createReactActivityLifecycleListeners。例如,MyLibPackage。
// android/src/main/java/expo/modules/mylib/MyLibPackage.kt package expo.modules.mylib import android.content.Context import expo.modules.core.interfaces.Package import expo.modules.core.interfaces.ReactActivityLifecycleListener class MyLibPackage : Package { override fun createReactActivityLifecycleListeners(activityContext: Context): List<ReactActivityLifecycleListener> { return listOf(MyLibReactActivityLifecycleListener()) } }
// android/src/main/java/expo/modules/mylib/MyLibPackage.java package expo.modules.mylib; import android.content.Context; import expo.modules.core.interfaces.Package; import expo.modules.core.interfaces.ReactActivityLifecycleListener; import java.util.Collections; import java.util.List; public class MyLibPackage implements Package { @Override public List<? extends ReactActivityLifecycleListener> createReactActivityLifecycleListeners(Context activityContext) { return Collections.singletonList(new MyLibReactActivityLifecycleListener()); } }
MyLibReactActivityLifecycleListener 是一个派生自 ReactActivityLifecycleListener 的类,你可以在其中接入各个生命周期。你只需要覆盖你需要的方法即可。
// android/src/main/java/expo/modules/mylib/MyLibReactActivityLifecycleListener.kt package expo.modules.mylib import android.app.Activity import android.os.Bundle import expo.modules.core.interfaces.ReactActivityLifecycleListener class MyLibReactActivityLifecycleListener : ReactActivityLifecycleListener { override fun onCreate(activity: Activity, savedInstanceState: Bundle?) { // 你在 `Activity.onCreate` 中的设置代码 doSomeSetupInActivityOnCreate(activity) } }
// android/src/main/java/expo/modules/mylib/MyLibReactActivityLifecycleListener.java package expo.modules.mylib; import android.app.Activity; import android.os.Bundle; import expo.modules.core.interfaces.ReactActivityLifecycleListener; public class MyLibReactActivityLifecycleListener implements ReactActivityLifecycleListener { @Override public void onCreate(Activity activity, Bundle savedInstanceState) { // 你在 `Activity.onCreate` 中的设置代码 doSomeSetupInActivityOnCreate(activity); } }
你也可以覆盖其他生命周期方法。下面的示例展示了如何在单个监听器类中覆盖多个生命周期方法。它基于 expo-linking 模块,该模块使用不同的生命周期方法来处理深度链接。你可以只实现你用例中需要的方法:
// android/src/main/java/expo/modules/mylib/MyLibReactActivityLifecycleListener.kt package expo.modules.mylib import android.app.Activity import android.content.Intent import android.os.Bundle import expo.modules.core.interfaces.ReactActivityLifecycleListener class MyLibReactActivityLifecycleListener : ReactActivityLifecycleListener { override fun onCreate(activity: Activity?, savedInstanceState: Bundle?) { // 当 activity 首次创建时调用 // 在这里初始化你的设置,例如处理深度链接 val deepLinkUrl = activity?.intent?.data if (deepLinkUrl != null) { handleDeepLink(deepLinkUrl.toString()) } } override fun onResume(activity: Activity) { // 当 activity 进入前台时调用 // 例如,跟踪用户何时返回应用 trackAppStateChange("active") } override fun onPause(activity: Activity) { // 当 activity 进入后台时调用 // 例如,暂停正在进行的操作,如分析跟踪 trackAppStateChange("inactive") } override fun onDestroy(activity: Activity) { // 当 activity 正在被销毁时调用 // 在这里清理资源 cleanup() } override fun onNewIntent(intent: Intent?): Boolean { // 当应用在已经运行时收到一个新的 intent 时调用 // 例如,当应用打开时处理新的深度链接 val newUrl = intent?.data if (newUrl != null) { handleDeepLink(newUrl.toString()) return true } return false } override fun onBackPressed(): Boolean { // 当用户按下返回按钮时调用 // 返回 true 以阻止默认返回行为 return handleCustomBackNavigation() } // 现在,你可以添加私有函数来处理 // 你的深度链接、应用状态跟踪、清理等逻辑。 }
// android/src/main/java/expo/modules/mylib/MyLibReactActivityLifecycleListener.java package expo.modules.mylib; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import expo.modules.core.interfaces.ReactActivityLifecycleListener; public class MyLibReactActivityLifecycleListener implements ReactActivityLifecycleListener { @Override public void onCreate(Activity activity, Bundle savedInstanceState) { // 当 activity 首次创建时调用 // 在这里初始化你的设置,例如处理深度链接 Uri deepLinkUrl = activity.getIntent().getData(); if (deepLinkUrl != null) { handleDeepLink(deepLinkUrl.toString()); } } @Override public void onResume(Activity activity) { // 当 activity 进入前台时调用 // 例如,跟踪用户何时返回应用 trackAppStateChange("active"); } @Override public void onPause(Activity activity) { // 当 activity 进入后台时调用 // 例如,暂停正在进行的操作,如分析跟踪 trackAppStateChange("inactive"); } @Override public void onDestroy(Activity activity) { // 当 activity 正在被销毁时调用 // 在这里清理资源 cleanup(); } @Override public boolean onNewIntent(Intent intent) { // 当应用在已经运行时收到一个新的 intent 时调用 // 例如,当应用打开时处理新的深度链接 Uri newUrl = intent.getData(); if (newUrl != null) { handleDeepLink(newUrl.toString()); return true; } return false; } @Override public boolean onBackPressed() { // 当用户按下返回按钮时调用 // 返回 true 以阻止默认返回行为 return handleCustomBackNavigation(); } // 现在,你可以添加私有函数来处理 // 你的深度链接、应用状态跟踪、清理等逻辑。 }
到 JavaScript 的生命周期监听器事件流
生命周期监听器是独立存在的单例类,与 Expo 模块实例彼此独立。要在生命周期监听器和你的模块之间通信(例如向应用的 JavaScript 代码发送事件),你需要从模块中观察事件,并在事件发生时通知生命周期监听器。一个典型流程可能包括以下步骤:
- 系统集成:生命周期监听器捕获带有 URL 数据的 Android intent
- 观察者模式:单例生命周期监听器与模块实例通信
- 事件桥接:模块向 JavaScript 发送结构化事件
- 内存管理:弱引用防止内存泄漏
- 类型安全与 React 集成:配合正确的事件类型和自定义 Hook 的 TypeScript 支持,便于访问深度链接事件
你的自定义模块实现可能并不需要事件流中的全部内容。不过,你可以将这种模式适配到其他系统事件,例如应用状态变化、配置变化,或者需要将 Android 生命周期事件桥接到 React Native 应用的自定义业务逻辑。
下面的示例演示如何使用生命周期监听器将 Android 系统事件桥接到你的 React Native 应用。它基于 expo-linking,该模块使用生命周期监听器创建一个深度链接处理器,在应用被打开或收到新 intent 时捕获 URL。
1
模块注册
首先创建一个模块类来注册你的生命周期监听器:
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerPackage.kt package expo.modules.deeplinkhandler import android.content.Context import expo.modules.core.interfaces.Package import expo.modules.core.interfaces.ReactActivityLifecycleListener class DeepLinkHandlerPackage : Package { override fun createReactActivityLifecycleListeners(activityContext: Context?): List<ReactActivityLifecycleListener> { return listOf(DeepLinkHandlerActivityLifecycleListener()) } }
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerPackage.java package expo.modules.deeplinkhandler; import android.content.Context; import expo.modules.core.interfaces.Package; import expo.modules.core.interfaces.ReactActivityLifecycleListener; import java.util.Collections; import java.util.List; public class DeepLinkHandlerPackage implements Package { @Override public List<? extends ReactActivityLifecycleListener> createReactActivityLifecycleListeners(Context activityContext) { return Collections.singletonList(new DeepLinkHandlerActivityLifecycleListener()); } }
2
带有观察者通知的 Activity 生命周期监听器
创建一个生命周期监听器来捕获深度链接并通知模块观察者:
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerActivityLifecycleListener.kt package expo.modules.deeplinkhandler import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle import expo.modules.core.interfaces.ReactActivityLifecycleListener class DeepLinkHandlerActivityLifecycleListener : ReactActivityLifecycleListener { override fun onCreate(activity: Activity?, savedInstanceState: Bundle?) { handleIntent(activity?.intent) } override fun onNewIntent(intent: Intent?): Boolean { handleIntent(intent) return true } private fun handleIntent(intent: Intent?) { val url = intent?.data if (url != null) { // 保存初始 URL 以便稍后获取 DeepLinkHandlerModule.initialUrl = url // 通知所有观察者新的深度链接 DeepLinkHandlerModule.urlReceivedObservers.forEach { observer -> observer(url) } } } }
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerActivityLifecycleListener.java package expo.modules.deeplinkhandler; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import expo.modules.core.interfaces.ReactActivityLifecycleListener; public class DeepLinkHandlerActivityLifecycleListener implements ReactActivityLifecycleListener { @Override public void onCreate(Activity activity, Bundle savedInstanceState) { handleIntent(activity.getIntent()); } @Override public boolean onNewIntent(Intent intent) { handleIntent(intent); return true; } private void handleIntent(Intent intent) { if (intent == null) return; Uri url = intent.getData(); if (url != null) { // 保存初始 URL 以便稍后获取 DeepLinkHandlerModule.initialUrl = url; // 通知所有观察者新的深度链接 for (java.util.function.Consumer<Uri> observer : DeepLinkHandlerModule.urlReceivedObservers) { observer.accept(url); } } } }
3
带事件发送的 Expo 模块
创建一个维护观察者并向 JavaScript 发送事件的模块:
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerModule.kt package expo.modules.deeplinkhandler import android.net.Uri import androidx.core.os.bundleOf import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import java.lang.ref.WeakReference class DeepLinkHandlerModule : Module() { companion object { var initialUrl: Uri? = null var urlReceivedObservers: MutableSet<((Uri) -> Unit)> = mutableSetOf() } private var urlReceivedObserver: ((Uri) -> Unit)? = null override fun definition() = ModuleDefinition { Name("DeepLinkHandler") Events("onUrlReceived") Function("getInitialUrl") { initialUrl?.toString() } OnStartObserving("onUrlReceived") { val weakModule = WeakReference(this@DeepLinkHandlerModule) val observer: (Uri) -> Unit = { uri -> weakModule.get()?.sendEvent( "onUrlReceived", bundleOf( "url" to uri.toString(), "scheme" to uri.scheme, "host" to uri.host, "path" to uri.path ) ) } urlReceivedObservers.add(observer) urlReceivedObserver = observer } OnStopObserving("onUrlReceived") { urlReceivedObservers.remove(urlReceivedObserver) } } }
// android/src/main/java/expo/modules/deeplinkhandler/DeepLinkHandlerModule.java package expo.modules.deeplinkhandler; import android.net.Uri; import androidx.core.os.Bundle; import expo.modules.kotlin.modules.Module; import expo.modules.kotlin.modules.ModuleDefinition; import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; public class DeepLinkHandlerModule extends Module { public static Uri initialUrl = null; public static Set<Consumer<Uri>> urlReceivedObservers = new HashSet<>(); private Consumer<Uri> urlReceivedObserver; @Override public ModuleDefinition definition() { return ModuleDefinition.create() .name("DeepLinkHandler") .events("onUrlReceived") .function("getInitialUrl", () -> { return initialUrl != null ? initialUrl.toString() : null; }) .onStartObserving("onUrlReceived", () -> { WeakReference<DeepLinkHandlerModule> weakModule = new WeakReference<>(this); Consumer<Uri> observer = uri -> { DeepLinkHandlerModule module = weakModule.get(); if (module != null) { Bundle bundle = new Bundle(); bundle.putString("url", uri.toString()); bundle.putString("scheme", uri.getScheme()); bundle.putString("host", uri.getHost()); bundle.putString("path", uri.getPath()); module.sendEvent("onUrlReceived", bundle); } }; urlReceivedObservers.add(observer); urlReceivedObserver = observer; }) .onStopObserving("onUrlReceived", () -> { urlReceivedObservers.remove(urlReceivedObserver); }); } }
4
TypeScript 接口和 React 用法
为你的模块定义一个 TypeScript 接口,以便将 Android 生命周期事件桥接到 JavaScript:
import { requireNativeModule, NativeModule } from 'expo-modules-core'; export type DeepLinkEvent = { url: string; scheme?: string; host?: string; path?: string; }; type DeepLinkHandlerModuleEvents = { onUrlReceived(event: DeepLinkEvent): void; }; declare class DeepLinkHandlerNativeModule extends NativeModule<DeepLinkHandlerModuleEvents> { getInitialUrl(): string | null; } const DeepLinkHandler = requireNativeModule<DeepLinkHandlerNativeModule>('DeepLinkHandler'); export default DeepLinkHandler;
创建一个 React Hook 以便轻松访问深度链接事件:
import { useEffect, useState } from 'react'; import DeepLinkHandler, { DeepLinkEvent } from './DeepLinkHandler'; export function useDeepLinkHandler(): { initialUrl: string | null; url: string | null; event: DeepLinkEvent | null; } { const [initialUrl] = useState<string | null>(DeepLinkHandler.getInitialUrl()); const [event, setEvent] = useState<DeepLinkEvent | null>(null); useEffect(() => { const subscription = DeepLinkHandler.addListener('onUrlReceived', event => { setEvent(event); }); return () => subscription.remove(); }, []); return { initialUrl, url: event?.url ?? initialUrl, event, }; }
在你的 React 组件中使用它:
import { Text, View, StyleSheet } from 'react-native'; import { useDeepLinkHandler } from './useDeepLinkHandler'; export function App() { const { initialUrl, url, event } = useDeepLinkHandler(); return ( <View style={styles.container}> <Text>Initial URL: {initialUrl || 'None'}</Text> <Text>Current URL: {url || 'None'}</Text> {event && ( <View style={styles.textContainer}> <Text>Latest Deep Link:</Text> <Text>Scheme: {event.scheme}</Text> <Text>Host: {event.host}</Text> <Text>Path: {event.path}</Text> </View> )} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, textContainer: { marginTop: 20, }, });
5
Application 生命周期监听器
你可以使用 ApplicationLifecycleListener 挂钩到 Application 生命周期。
当前支持以下 Application 生命周期回调:
onCreateonConfigurationChanged
要创建一个 ApplicationLifecycleListener,你应该在派生的 Package 类中实现 createApplicationLifecycleListeners。例如,MyLibPackage。
// android/src/main/java/expo/modules/mylib/MyLibPackage.kt package expo.modules.mylib import android.content.Context import expo.modules.core.interfaces.ApplicationLifecycleListener import expo.modules.core.interfaces.Package class MyLibPackage : Package { override fun createApplicationLifecycleListeners(context: Context): List<ApplicationLifecycleListener> { return listOf(MyLibApplicationLifecycleListener()) } }
// android/src/main/java/expo/modules/mylib/MyLibPackage.java import android.content.Context; import java.util.Collections; import java.util.List; import expo.modules.core.interfaces.ApplicationLifecycleListener; import expo.modules.core.interfaces.Package; public class MyLibPackage implements Package { @Override public List<? extends ApplicationLifecycleListener> createApplicationLifecycleListeners(Context context) { return Collections.singletonList(new MyLibApplicationLifecycleListener()); } }
MyLibApplicationLifecycleListener 是一个派生自 ApplicationLifecycleListener 的类,它可以挂钩到 Application 生命周期回调。你应该只重写你需要的方法(由于可能的维护成本)。
// android/src/main/java/expo/modules/mylib/MyLibApplicationLifecycleListener.kt package expo.modules.mylib import android.app.Application import expo.modules.core.interfaces.ApplicationLifecycleListener class MyLibApplicationLifecycleListener : ApplicationLifecycleListener { override fun onCreate(application: Application) { // 你的 `Application.onCreate` 中的初始化代码。 doSomeSetupInApplicationOnCreate(application) } }
// android/src/main/java/expo/modules/mylib/MyLibApplicationLifecycleListener.java package expo.modules.mylib; import android.app.Application; import expo.modules.core.interfaces.ApplicationLifecycleListener; public class MyLibApplicationLifecycleListener implements ApplicationLifecycleListener { @Override public void onCreate(Application application) { // 你的 `Application.onCreate` 中的初始化代码。 doSomeSetupInApplicationOnCreate(application); } }
已知问题
为什么没有 onStart 和 onStop 的 Activity 监听器
在当前实现中,我们不是从 MainActivity,而是从 ReactActivityDelegate 设置这些钩子。MainActivity 和 ReactActivityDelegate 之间存在一些细微差异。由于 ReactActivityDelegate 没有 onStart 和 onStop,因此我们目前不支持它们。
接口稳定性
这些监听器接口在 Expo SDK 的不同版本之间可能会时不时发生变化。我们对向后兼容性的策略始终是新增接口,并为我们计划移除的接口添加 @Deprecated 注解。我们的接口都基于 Java 8 接口默认方法;你不需要也不应该实现所有方法。这样做将有利于降低你的模块在不同 Expo SDK 之间的维护成本。