Android 深层链接和多个应用程序实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25884954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:47:02  来源:igfitidea点击:

Deep linking and multiple app instances

androiddeep-linking

提问by HariRam

I have implemented deep linking in my app. I added this intent filter in my manifest file, and the deep linking is working.

我已经在我的应用中实现了深度链接。我在清单文件中添加了这个意图过滤器,并且深层链接正在工作。

<intent-filter>
    <action android:name="android.intent.action.VIEW" /> 
    <category android:name="android.intent.category.DEFAULT" /> 
    <category android:name="android.intent.category.BROWSABLE" /> 
    <category android:name="android.intent.category.VIEW" /> 
    <data
        android:host="www.mywebsite.com"
        android:pathPrefix="/something"
        android:scheme="http" />
</intent-filter>

The problem is that through deep linking, my app is launching on top of current app. If I am in Gmail and I click a link, then my app is launching on top of Gmail. I want to launch my app differently.

问题是通过深层链接,我的应用程序在当前应用程序之上启动。如果我在 Gmail 中并单击一个链接,则我的应用程序将在 Gmail 上启动。我想以不同的方式启动我的应用程序。

If my app is already running in background and I click on a link in Gmail which redirects to my app, I will have two instances of my app running at the same time; one in the background, and another on top of Gmail. I want to run only one instance of my app at a time, so it's not also on top of the current app (Gmail). How can I do that?

如果我的应用程序已经在后台运行并且我单击 Gmail 中重定向到我的应用程序的链接,我将有两个应用程序实例同时运行;一个在后台,另一个在 Gmail 上。我只想一次运行我的应用程序的一个实例,因此它不在当前应用程序 (Gmail) 之上。我怎样才能做到这一点?

采纳答案by user3453281

the accepted answer didn't work for me, here is what did:

接受的答案对我不起作用,这是做了什么:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();

from the official doc:

来自官方文档:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

如果设置,并且正在启动的活动已经在当前任务中运行,那么它不会启动该活动的新实例,而是将关闭它之上的所有其他活动,并且此 Intent 将被传递到(现在在顶部)旧活动作为新意图。

回答by Micky

You need to do following things for your Activity in your Manifest.

您需要在清单中为您的活动做以下事情。

android:launchMode="singleTask"

This tells the system to always launch the existing instance of the Activity if it is already created.

这告诉系统如果已经创建了 Activity 的现有实例,则始终启动它。

And you can handle the Intent then by overriding the method

然后您可以通过覆盖该方法来处理 Intent

onNewIntent 

See http://developer.android.com/guide/topics/manifest/activity-element.htmlfor more information.

有关更多信息,请参阅http://developer.android.com/guide/topics/manifest/activity-element.html

回答by Philipp Reddigau

Well we had several issues with deeplinks. Like:

好吧,我们在深层链接方面遇到了几个问题。喜欢:

  1. click on the same link twice only, first click triggered the correct view
  2. opened multiple instances
  3. Links in whatsapp or facebook opened a view in whatsapp itself because of their web browser.
  4. on android 6 opened only one instance, but was only handling the first intent, second and third opens app but no action because the intentdata did not changed somehow.
  1. 同一个链接只点击两次,第一次点击触发正确的视图
  2. 打开多个实例
  3. 由于他们的网络浏览器,whatsapp 或 facebook 中的链接在 whatsapp 本身中打开了一个视图。
  4. 在 android 6 上只打开一个实例,但只处理第一个意图,第二个和第三个打开应用程序但没有动作,因为意图数据没有以某种方式改变。

So the following is not an clear answer to the question more an allround solution for several issues we had.

因此,以下不是问题的明确答案,而是我们遇到的几个问题的全面解决方案。

Our solution:

我们的解决方案:

a) Created a new FragmentActivity

a) 创建了一个新的 FragmentActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2); //well can be anything some "loading screen"

    Intent intent = getIntent();
    String intentUrl = intent.getDataString();
    Intent newIntent = new Intent(this, MainActivity.class);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    newIntent.putExtra("intentUrl",intentUrl);
    newIntent.setAction(Long.toString(System.currentTimeMillis()));

    startActivity(newIntent);
    finish();
}

b) Manifest:

b) 清单:

    <activity
        android:name="YOUR.NEW.FRAGMENT.ACTIVITY"
        android:label="@string/app_name"
        android:launchMode="singleTop">
        <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="http" />
            <data android:scheme="https" />
            <data android:scheme="scheme1" /> <!-- sheme1://-->
            <data android:host="yourdomain.com" />
            <data android:host="www.yourdomain.com" />
        </intent-filter>
    </activity>

c) handle the passed new intent in your activities onCreate() and onResume() by calling the following example function:

c) 通过调用以下示例函数来处理活动 onCreate() 和 onResume() 中传递的新意图:

private void handleUrl(Intent i){
    String intentUrl = null;
    if (i != null) {
        intentUrl = i.getStringExtra("intentUrl");
        if (intentUrl == null){
            //hmm intent is damaged somehow
        } else {
            //because of onResume()
            if ( i.getBooleanExtra("used",false) ) {
                return;
            }
            i.putExtra("used", true);

           //DO SOMETHING WITH YOUR URL HERE
    }       
}

回答by etherton

I had this exact same problem, except I wanted the user to land back in the main task with the full back stack, as though they had just used the app switcher to move to my app. To accomplish this I had to reorder tasks.

我遇到了完全相同的问题,但我希望用户使用完整的返回堆栈返回主任务,就好像他们刚刚使用应用程序切换器移动到我的应用程序一样。为了做到这一点,我不得不重新排序任务。

1) Give my app permission to re-order tasks

1) 授予我的应用重新排序任务的权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.company.app">
     <uses-permission android:name="android.permission.REORDER_TASKS"/>
</manifest>

2) Keep track of what the maintask ID is

2)跟踪任务ID是什么

public class MainActivity {
    public static int mainTaskId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
         super(savedInstanceState);
         //set the main task ID
         taskId = getTaskId();
    } 
}

3) When my deep link activity is launched it saves some data for use later and then brings the main task to the front

3)当我的深层链接活动启动时,它会保存一些数据以备后用,然后将主要任务放在前面

public class DeepLinkActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super(savedInstanceState);

        //persist deep link data
        Uri uri = intent.getData();
        String action = intent.getAction();
        saveForLater(uri, action);

        if(isTaskRoot()){
            //I'm in my own task and not the main task
            final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            activityManager.moveTaskToFront(MainActivity.taskId, ActivityManager.MOVE_TASK_NO_USER_ACTION);
            }
        }
    }
}

4) When whatever activity is at the top of the main task's back stack starts, it checks if there's any saved data to work on, and works on it.

4) 当主任务后端堆栈顶部的任何活动启动时,它会检查是否有任何保存的数据要处理,并对其进行处理。

回答by bharat udasi

I solve these issue by just add android:launchMode="singleTask" in manifest file

我通过在清单文件中添加 android:launchMode="singleTask" 来解决这些问题

回答by tej shah

just solve this issue for only one Instance

只为一个实例解决这个问题

android:launchMode="singleInstance"

android:launchMode="singleInstance"

<activity
    android:name=".SplashScreen"
    android:screenOrientation="portrait"
    android:launchMode="singleInstance"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </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:scheme="nvd.abc" />
    </intent-filter>
</activity>

回答by SO 80

Consider using finish()when leaving the deep link Activity, so if the deep link is operated again the activity will be recreated. This can avoid errors and contradictions.

finish()离开深度链接时考虑使用Activity,所以如果再次操作深度链接,Activity会重新创建。这样可以避免错误和矛盾。

回答by meesha tyagi

(initialize at the starting of class)

(在课程开始时初始化)

String itemInfo == "";

String itemInfo == "";

Basically compare the package name.

基本上比较包名。

if(!itemInfo.equals(getItem(position).activityInfo.packageName)) 
{ 
    intent.setComponent(new ComponentName(getItem(position).activityInfo.packageName, 
                                          getItem(position).activityInfo.name));

    itemInfo = getItem(position).activityInfo.packageName;
    ((AxisUpiActivtiy) context).startActivityForResult(intent, RequestCodes.START_INTENT_RESPONSE);
}

this condition itemInfo.equals(getItem(position).activityInfo.packageName)is the important

这个条件itemInfo.equals(getItem(position).activityInfo.packageName)很重要