持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
问题
上次我们讲到如何从H5或者短信链接中调起ReactNative开发的App,其中有个问题是如果调起了多次,App可能会打开多个窗口,每点一次链接就会新开一个App窗口,像应用双开一样的效果,如下图唤起了三次App:
这样会导致在App的监听外部调起事件有时不生效,因为它有可能在第一个窗口响应,有可能在第二个响应,这样导致偶发的业务错误。
原因
由于对原生安卓也是不太了解,查询了一堆原因之后发现是安卓启动activity的方式有几种,也就是AndroidManifest.xml
文件下的activity
的属性android:launchMode
,他们的值分别有
(1)standard
:每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;这个是系统默认的启动模式;
(2)singleTop
:如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例);
(3)singleTask
:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop(弹出销毁);这个模式可以用来退出整个应用;
(4)singleInstance
:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例。
在我们的App里面主程序MainActivity
里面的android:launchMode
为singleTop
,如图:
我们的Scheme
也是写在里面,所以导致了启动了多个Activity
,一个解决方法是直接把这个singleTop
改为singleTask
,这样多次唤起App就不会产生多的窗口了,不过我们的其他业务需要到singleTop
的启动模式,故不能直接修改。
解决方案
既然不能直接修改主程序的启动模式,那我们就自己新建一个Activity
并设置android:launchMode=singleTask
,再由这个Activity
启动主程序。
(1)、新建自己Activity的文件
在目录android\app\src\main\java
下新建一个文件夹applink
,文件夹下载新建一个java文件,命名为AppActivity.java
,具体代码如下:
package 你们的包路劲.applink;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import 你们的包路劲.MainActivity;
import android.net.Uri;
public class AppActivity extends Activity {
private static final String TAG = "AppActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
initRouteData();
Intent mIntent = getIntent(); // 拿到当前Intent
String path = mIntent.getDataString(); // 拿到唤起App的url
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(path)); // 新建一个把url参数放进去
intent.setClass(this, MainActivity.class); // 设置主应用为intent的类
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 设置Intent的标志位为FLAG_ACTIVITY_CLEAR_TOP(相当于launchMode中的singleTask)
startActivity(intent); // 启动这个intent(主程序)
finish();
super.onCreate(savedInstanceState);
}
@Override
protected void onResume(){
super.onResume();
}
void initRouteData(){
String action = getIntent().getData().getQueryParameter("action");
PushActionData.action = action;
}
protected void onNewIntent(Intent intent) {
Log.d(TAG,"onNewIntent");
super.onNewIntent(intent);
setIntent(intent); // must store the new intent unless getIntent() will return the old one
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
这行代码是必须的,如果不设置的话,主程序还是按照singleTop启动。
(2)、增加Activity配置
同样在AndroidManifest.xml
增加一个activity
标签,这次我们直接设置launchMode
为singleTask
,android:name
为上面新建的AppActivity.java的类名,然后把之前的设置的scheme配置放进去,代码如下:
<activity
android:name=".applink.AppActivity"
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="test" android:host="testHost" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="xxx.com"
android:pathPattern=".*"
android:scheme="https"/>
</intent-filter>
</activity>
这样我们的唤起App多开窗口的问题就解决了,有错误的地方欢迎大家指出。
参考文章: