You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native监听应用从最近列表移除(Android/iOS)并存储数据

嘿,这个需求在React Native跨平台开发里挺常见的——毕竟得确保用户把应用从最近列表清掉时,数据能稳妥保存下来。我分Android和iOS两个平台给你拆解具体实现,都是经过实践验证的方案:

Android平台:监听onTaskRemoved事件

Android系统在应用被从最近列表移除时,会触发onTaskRemoved回调。因为React Native没有直接暴露这个事件,我们需要通过原生模块把事件传递到JS层。

1. 自定义Application类

首先在Android原生代码里创建自定义的Application子类,重写onTaskRemoved方法来发送事件:

import android.app.Application;
import android.content.Intent;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.util.Arrays;
import java.util.List;

public class MyApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.asList(new MainReactPackage());
    }

    @Override
    protected String getJSMainModuleName() {
      return "index";
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);
    // 获取当前React上下文,确保事件能发送到JS层
    ReactInstanceManager reactInstanceManager = getReactNativeHost().getReactInstanceManager();
    ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
    if (reactContext != null) {
      reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
          .emit("AppRemovedFromRecent", null);
    }
  }
}

2. 修改AndroidManifest.xml

把AndroidManifest.xml里的application标签指定为我们自定义的类:

<application
  android:name=".MyApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher">
  <!-- 其他原有配置 -->
</application>

3. JS层监听事件

在React Native代码里通过NativeEventEmitter监听事件,触发时执行数据存储:

import { NativeEventEmitter, NativeModules, AsyncStorage } from 'react-native';
import { useEffect } from 'react';

// 创建事件发射器
const appEventEmitter = new NativeEventEmitter(NativeModules.DeviceEventManagerModule);

function App() {
  useEffect(() => {
    // 监听应用从最近列表移除的事件
    const subscription = appEventEmitter.addListener(
      'AppRemovedFromRecent',
      async () => {
        console.log('Android应用已从最近列表移除');
        // 执行数据存储逻辑,比如用AsyncStorage
        try {
          await AsyncStorage.setItem('userSession', JSON.stringify({ lastActive: Date.now() }));
        } catch (err) {
          console.error('存储数据失败:', err);
        }
      }
    );

    // 组件卸载时取消订阅,避免内存泄漏
    return () => subscription.remove();
  }, []);

  // 其他组件逻辑...
}

export default App;
iOS平台:监听应用终止事件

iOS没有直接对应"从最近列表移除"的专属事件,但用户手动划掉应用时,系统会触发applicationWillTerminate回调。我们可以利用这个回调来处理数据存储。

1. 修改AppDelegate.m

在iOS原生的AppDelegate.m里重写applicationWillTerminate方法,发送事件到JS层(或直接在原生存储数据):

#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // 原有初始化代码...
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"YourAppName" initialProperties:nil];
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application {
  // 发送事件到JS层
  RCTBridge *bridge = self.window.rootViewController.bridge;
  [bridge.eventDispatcher sendAppEventWithName:@"AppRemovedFromRecent" body:nil];

  // 也可以直接在原生存储数据(推荐,因为JS层异步操作可能来不及完成)
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  [defaults setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]] forKey:@"lastActive"];
  [defaults synchronize];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

@end

2. JS层监听事件

和Android类似,在JS层监听事件并处理存储(注意iOS系统留给应用的终止时间很短,尽量用同步操作或在原生处理):

import { NativeEventEmitter, NativeModules, AsyncStorage } from 'react-native';
import { useEffect } from 'react';

const appEventEmitter = new NativeEventEmitter(NativeModules.DeviceEventManagerModule);

function App() {
  useEffect(() => {
    const subscription = appEventEmitter.addListener(
      'AppRemovedFromRecent',
      () => {
        console.log('iOS应用即将终止(从最近列表移除)');
        // 这里尽量用快速的存储操作,或者直接依赖原生层的存储
        AsyncStorage.setItem('userSession', JSON.stringify({ lastActive: Date.now() }))
          .catch(err => console.error('存储失败:', err));
      }
    );

    return () => subscription.remove();
  }, []);

  // 其他组件逻辑...
}

export default App;

关键注意事项

  • Android:onTaskRemoved仅在应用处于前台/后台运行状态时被触发,如果应用已经被系统杀掉,不会触发这个回调。
  • iOS:applicationWillTerminate在用户手动移除应用时会触发,但如果应用在后台被系统回收(比如内存不足),这个方法可能不会调用。建议结合applicationDidEnterBackground回调,在应用进入后台时先保存一次数据,做双重保障。
  • 存储效率:iOS的终止回调留给应用的时间非常有限(通常几秒),异步存储可能来不及完成,更推荐在原生层用同步方式存储(比如NSUserDefaults的synchronize)。

内容的提问来源于stack exchange,提问作者AE0011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:42:39