安卓端唤起App多开窗口问题

937 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

问题

上次我们讲到如何从H5或者短信链接中调起ReactNative开发的App,其中有个问题是如果调起了多次,App可能会打开多个窗口,每点一次链接就会新开一个App窗口,像应用双开一样的效果,如下图唤起了三次App:

STN7RLB}N$46I}LXLX[_Z]D.bmp

这样会导致在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:launchModesingleTop,如图:

QQ图片20220614230119.png

我们的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标签,这次我们直接设置launchModesingleTaskandroid: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多开窗口的问题就解决了,有错误的地方欢迎大家指出。

参考文章:

www.cnblogs.com/ltl1532/p/5…

www.cnblogs.com/chenxibobo/…

blog.csdn.net/rainbowcode…