Android 生命周期监听器

编辑

了解机制,使您的库能够通过 Expo 模块 API 挂钩 Android Activity 和 Application 功能。


为了响应与应用相关的某些 Android 系统事件,例如传入链接和配置更改,必须覆盖 MainActivity.java 和/或 MainApplication.java 中相应的生命周期回调。

React Native 模块 API 没有提供任何机制来挂钩这些事件,因此 React Native 库的设置说明通常包括将代码复制到这些文件的步骤。为了简化和自动化设置和维护,Expo Modules API 提供了一种机制,允许您的库挂钩 ActivityApplication 函数。

开始使用

首先,您需要创建一个 Expo 模块或使用 React Native 模块 API 集成 Expo 模块 API。 了解更多

在您的模块中,创建一个实现 Package 接口的具体类。在大多数情况下,您只需要实现 createReactActivityLifecycleListenerscreateApplicationLifecycleListeners 方法。

Activity 生命周期监听器

您可以使用 ReactActivityLifecycleListener 挂钩 Activity 生命周期。ReactActivityLifecycleListener 使用其 ReactActivityDelegate 挂钩 React Native 的 ReactActivity 生命周期,并提供与 Android Activity 生命周期类似的体验。

当前支持以下 Activity 生命周期回调:

  • onCreate
  • onResume
  • onPause
  • onDestroy
  • onNewIntent
  • onBackPressed

要创建 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?) { // 当活动首次创建时调用 // 在这里初始化您的设置,例如处理深链接 val deepLinkUrl = activity?.intent?.data if (deepLinkUrl != null) { handleDeepLink(deepLinkUrl.toString()) } } override fun onResume(activity: Activity) { // 当活动进入前台时调用 // 例如,跟踪用户何时返回到应用程序 trackAppStateChange("active") } override fun onPause(activity: Activity) { // 当活动进入后台时调用 // 例如,暂停正在进行的操作,例如跟踪分析 trackAppStateChange("inactive") } override fun onDestroy(activity: Activity) { // 当活动被销毁时调用 // 在这里清理资源 cleanup() } override fun onNewIntent(intent: Intent?): Boolean { // 当应用程序在运行时接收到新的意图时调用 // 例如,在应用程序打开时处理新的深链接 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) { // 当活动首次创建时调用 // 在这里初始化您的设置,例如处理深链接 Uri deepLinkUrl = activity.getIntent().getData(); if (deepLinkUrl != null) { handleDeepLink(deepLinkUrl.toString()); } } @Override public void onResume(Activity activity) { // 当活动进入前台时调用 // 例如,跟踪用户何时返回到应用程序 trackAppStateChange("active"); } @Override public void onPause(Activity activity) { // 当活动进入后台时调用 // 例如,暂停正在进行的操作,例如跟踪分析 trackAppStateChange("inactive"); } @Override public void onDestroy(Activity activity) { // 当活动被销毁时调用 // 在这里清理资源 cleanup(); } @Override public boolean onNewIntent(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 意图
  • 观察者模式:单例生命周期监听器与模块实例通信
  • 事件桥接:模块将结构化事件发送到 JavaScript
  • 内存管理:弱引用防止内存泄漏
  • 类型安全和 React 集成:通过适当的事件类型和自定义钩子提供 TypeScript 支持,便于访问深链接事件

您的自定义模块实现可能不需要上述所有内容。不过,您可以将此模式调整为其他系统事件,例如应用状态更改、配置更改或需要将 Android 生命周期事件桥接到 React Native 应用程序的自定义业务逻辑。

以下示例演示如何使用生命周期监听器将 Android 系统事件桥接到您的 React Native 应用程序。该示例基于 expo-linking,该模块使用生命周期监听器创建一个深链接处理程序,当应用程序打开或接收新意图时捕获 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:

DeepLinkHandler.ts
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 钩子:

useDeepLinkHandler.ts
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 组件中使用它:

App.tsx
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

模块配置

最后,在 expo-module.config.json 中配置您的模块,以连接模块到生命周期监听器:

expo-module.config.json
{ "platforms": ["android"], "android": { "modules": ["expo.modules.deeplinkhandler.DeepLinkHandlerModule"] } }

Application 生命周期监听器

您可以使用 ApplicationLifecycleListener 挂钩 Application 生命周期。

当前支持以下 Application 生命周期回调:

  • onCreate
  • onConfigurationChanged

要创建 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); } }

已知问题

为什么没有 onStartonStop Activity 监听器

在当前实现中,我们没有从 MainActivity 设置钩子,而是从 ReactActivityDelegate 设置。MainActivityReactActivityDelegate 之间存在一些细微的差异。由于 ReactActivityDelegate 没有 onStartonStop,我们在这里尚不支持它们。

接口稳定性

监听器接口可能会在 Expo SDK 发布之间发生变化。我们的向后兼容性策略始终是添加新的接口,并对我们计划删除的接口添加 @Deprecated 注释。我们的接口均基于 Java 8 接口默认方法;您不必也不应实现所有方法。这样做将有利于在不同的 Expo SDK 之间降低模块的维护成本。