问题描述:
1.在React-Native 项目首次安装App或者升级程序后,在安装程序界面点击“打开"按钮 启动APP
2.然后点击home键回到桌面
3.再次点击桌面图标启动应用
会发现再次启动APP
分析
看了网上很多帖子,基本可以确定是 Android系统问题,但是不是所有手机都可以复现这个问题(目前三星,小米都复现了,OPPO和魅族没有复现)
1.虽然已经基本确定是Android系统问题,由于涉及到React-Native 开发首先需要分析是不是JavaScript模块出了问题,经过分析,发现没有问题。那肯定是Android Native模块出了问题。
2.对比发现,只有首次在安装程序界面点击”打开"启动APP,才能触发这个问题,如果首次在Launcher界面启动App 不会出现这个问题。
- 从界面启动 是通过startActivity 通过特定的 Intent 向 ActivityManagerService 发起启动任务,Intent 具有特殊性,添加了特殊的拦截器(action,category,log等), 避免其他应用内或者应用
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
第一次从桌面启动Intent log信息
Hist #0:
ActivityRecord{4da2d2cd0 u0 cn/.MainActivity t7191}
Intent {
flg=0x10000000
cmp=cn/.MainActivity
launchParam=MultiScreenLaunchParams { mDisplayId=0 mFlags=0 } }
ProcessRecord{df85f68 8531:cn.homecredit.mysteryshop/u0a532}
通过查看AndroidManifest.xml这个文件,应用程序的入口Activity会包含一些过滤器(如:”action“, “category”, “flag”)通过Launcher启动已经存在后台的APP,应该是将后台的任务挪到前台而不是重新创建一个新的任务。即,每次启动 Intent 导致创建 Task 的时候,该 Task 都会记录导致其创建的 Intent ;而如果后续需要一个新的与创建 Intent 完全一致(启动类,action, category, flag 等等全部一样),那么该 Intent 并不会出发 Activity 的新建启动,而只会将已经存在的对应的 Task 移到前台;
- 从程序安装界面启动应用,每次创建的Intent flag与之前不同,每次都会重新创建activity,导致会每次重新启动。如果把栈清空后会恢复正常。查看当前任务栈可以通过
第一次从安装程序界面启动 Intent log信息
Hist #1:
ActivityRecord{3f67011d0 u0 cn/.MainActivity t7191}
Intent {
act=android.intent.action.MAIN
cat=[android.intent.category.LAUNCHER]
flg=0x10600000
cmp=cn.MainActivity
launchParam=MultiScreenLaunchParams { mDisplayId=0 mFlags=0 }
bnds=[440,1262][640,1522] (has extras) }
ProcessRecord{df85f68 8531:cn.homecredit.mysteryshop/u0a532}
解决方案
- Android Native项目在Root Activity 的 onCreate 方法中添加
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!this.isTaskRoot()) {
Intent mainIntent = getIntent();
String action = mainIntent.getAction();
if (mainIntent.hasCategory(Intent.CATEGORY_LAUNCHER) && action.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
}
//PS:记得在 super.onCreate() 方法之后执行有效
- React-Native 项目
方法1. 由于 RN 的Activity 继承自 ReactActivity ,所以需要修改源码,在ReactActivity 的 onCreate 的方法添加
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!this.isTaskRoot()) {
Intent mainIntent = getIntent();
String action = mainIntent.getAction();
if (mainIntent.hasCategory(Intent.CATEGORY_LAUNCHER) && action.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
}
mDelegate.onCreate(savedInstanceState);
//PS:记得在 super.onCreate() 方法之后,mDelegate.onCreate之前执行有效
}
方法2. 可以在AndroidManifest 中修改 MainActivity 的 launchMode为SingleTask
<activity
android:name="***.MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"
android:launchMode="singleTask">