Expo安卓应用关闭后点击通知启动崩溃问题求助
React Native Expo安卓应用冷启动点击通知崩溃问题
- 生产构建版本中,应用关闭/未运行时点击通知会崩溃:启动后显示闪屏,几秒后崩溃
- 应用已打开时点击通知运行正常
- Bugsnag未上报任何错误,尝试用Logcat查看但无法理解错误含义及修复方法
背景:导航器结构调整
原本有三个导航器:
- InitNavigator - 仅包含闪屏页
- AuthNavigator - 认证页面
- AppNavigator - 用户登录后可见页面
最初实现中,AppNavigator仅在用户登录(通过AsyncStorage的JWT判断)时条件挂载,应用启动需先从AsyncStorage取信息。出现问题后修改为启动时挂载所有导航器,代码如下:
<AppStack.Navigator screenOptions={{ headerShown: false }} // initialRouteName={routes.APP_NAVIGATOR.SINGLE_POST} > {/* Initial/Splash Screen */} <AppStack.Group> <AppStack.Screen name="splashScreen" component={SplashScreen} /> </AppStack.Group> {/* Authentication Screen */} <AppStack.Group> <AppStack.Screen name={routes.AUTH_STACK_NAVIGATOR.SIGNUP_NAVIGATOR} component={UserProvider} /> </AppStack.Group> <AppStack.Group> {/* <AppStack.Screen name="demo" component={ViewCommunityProfile} /> */} <AppStack.Screen name={routes.APP_NAVIGATOR.COMMUNITY_NAVIGATOR} component={SideDrawer} /> <AppStack.Screen name={routes.APP_NAVIGATOR.SET_LOCATION} component={Location} /> <AppStack.Screen name="EditCommunityProfile" component={EditCommunityProfile} /> <AppStack.Screen name={routes.APP_NAVIGATOR.CREATE_POST_NAVIGATOR} component={CreatePostNavigator} /> <AppStack.Screen name={routes.APP_NAVIGATOR.PROFILE_NAVIGATOR} component={ProfileNavigator} /> <AppStack.Screen name={routes.APP_NAVIGATOR.CHAT_NAVIGATOR} component={ChatNavigator} /> <AppStack.Screen name={routes.APP_NAVIGATOR.SINGLE_POST} component={SinglePost} /> </AppStack.Group> </AppStack.Navigator>
通知处理代码
通知在包裹整个应用的Context中处理:
responseListener.current = Notifications.addNotificationResponseReceivedListener((response) => { const notificatonContent = response.notification.request.content; if (notificatonContent.data?.url) { openUsingDefaultUrl(notificatonContent.data.url); } else { openUsingDefaultUrl("/notification"); } });
后台通知任务代码
import * as TaskManager from "expo-task-manager"; const BACKGROUND_NOTIFICATION_TASK = "BACKGROUND-NOTIFICATION-TASK"; TaskManager.defineTask( BACKGROUND_NOTIFICATION_TASK, ({ data, error, executionInfo }) => { if (error) { Bugsnag.notify(error); } if (data) { if (data?.url) { openUsingDefaultUrl(data.url); } else { openUsingDefaultUrl("/notification"); } } } );
修复方案
1. 禁止在后台任务中执行路由跳转
TaskManager的后台任务运行在非UI线程,无法直接调用导航跳转方法,这是冷启动崩溃的核心原因之一:
- 修改后台任务逻辑,仅存储通知的跳转URL到AsyncStorage:
TaskManager.defineTask( BACKGROUND_NOTIFICATION_TASK, ({ data, error }) => { if (error) { Bugsnag.notify(error); return; } if (data?.url) { AsyncStorage.setItem('pendingDeepLink', data.url); } else { AsyncStorage.setItem('pendingDeepLink', "/notification"); } } ); - 在SplashScreen的初始化逻辑中,读取
pendingDeepLink并执行跳转,完成后删除该存储项
2. 等待应用初始化完成后再处理通知跳转
冷启动时应用未完成初始化,直接跳转路由会导致导航器状态异常:
- 在根Context或SplashScreen中设置
appReady状态标记,在AsyncStorage读取、导航器初始化完成后设为true - 修改通知响应监听逻辑,等待
appReady为true后再执行跳转:responseListener.current = Notifications.addNotificationResponseReceivedListener(async (response) => { // 等待应用就绪 while (!appReady) { await new Promise(resolve => setTimeout(resolve, 100)); } const notificatonContent = response.notification.request.content; const targetUrl = notificatonContent.data?.url || "/notification"; openUsingDefaultUrl(targetUrl); });
3. 优化导航器初始化逻辑
恢复导航器的条件渲染,避免未登录状态下加载依赖用户信息的组件:
- 在SplashScreen中完成JWT验证,直接跳转到对应导航器的初始页面:
// SplashScreen组件内 useEffect(() => { const initApp = async () => { const token = await AsyncStorage.getItem('jwt'); await AsyncStorage.removeItem('pendingDeepLink'); // 清理旧的跳转记录 const pendingUrl = await AsyncStorage.getItem('pendingDeepLink'); if (token) { if (pendingUrl) { navigation.navigate(pendingUrl); } else { navigation.navigate(routes.APP_NAVIGATOR.COMMUNITY_NAVIGATOR); } } else { navigation.navigate(routes.AUTH_STACK_NAVIGATOR.SIGNUP_NAVIGATOR); } }; initApp(); }, [navigation]); - 根导航器仅保留必要的初始路由,其他导航器作为子页面按需加载
4. 提取Logcat关键错误信息
连接安卓设备后运行以下命令获取错误日志:
adb logcat *:E | grep -E "AndroidRuntime|ReactNative|Exception"
重点查看NullPointerException、组件初始化失败等信息,定位崩溃的具体组件或逻辑。
内容的提问来源于stack exchange,提问作者Austin Ezeh
相关产品推荐
相关产品推荐

