深度链接和多个应用实例
Posted
技术标签:
【中文标题】深度链接和多个应用实例【英文标题】:Deep linking and multiple app instances 【发布时间】:2014-11-11 03:47:53 【问题描述】:我在我的应用中实现了深度链接。我在清单文件中添加了这个意图过滤器,并且深度链接正在工作。
<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>
问题在于,通过深度链接,我的应用在当前应用之上启动。如果我在 Gmail 中并单击一个链接,那么我的应用程序将在 Gmail 之上启动。我想以不同的方式启动我的应用。
如果我的应用程序已经在后台运行,并且我点击了 Gmail 中重定向到我的应用程序的链接,我将同时运行我的应用程序的两个实例;一个在后台,另一个在 Gmail 之上。我想一次只运行我的应用程序的一个实例,因此它不在当前应用程序(Gmail)之上。我该怎么做?
【问题讨论】:
@commonsware 奇怪的是,当您的应用从 Gmail 启动时,它是在与 Gmail 相同的进程中运行还是为它创建了一个新进程?那么,如果你的应用有两个实例,会不会有两个新进程? 【参考方案1】:您需要在 Manifest 中为您的 Activity 执行以下操作。
android:launchMode="singleTask"
这告诉系统如果 Activity 的现有实例已经创建,则始终启动它。
然后你可以通过重写方法来处理 Intent
onNewIntent
更多信息请参见http://developer.android.com/guide/topics/manifest/activity-element.html。
【讨论】:
如果应用已打开且当前显示在活动 A 中,但深层链接指向活动 B,该怎么办? 如果活动 B 设置了singleTask
,如果 B 已经创建,堆栈中的所有活动都将被销毁。因此活动 A 将被销毁。如果活动 B 尚未在堆栈中,它将在活动 A 之上打开。
感谢您的提示! :-)
它可以工作,但是如果在后台打开打开,然后如果我尝试使用启动器图标启动应用程序,那么它会再次重新启动而不是恢复,这是一个缺点。【参考方案2】:
接受的答案对我不起作用,这就是:
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
来自官方文档:
如果设置了,并且正在启动的 Activity 已经在当前任务中运行,那么不会启动该 Activity 的新实例,而是关闭它之上的所有其他 Activity,并且此 Intent 将被传递到(现在在顶部)作为新意图的旧活动。
【讨论】:
不工作...它仍在创建我的应用活动的两个实例 遇到了同样的问题。你可以在***.com/questions/35776907/…看到我的回答【参考方案3】:我们在深度链接方面遇到了几个问题。 喜欢:
-
同一个链接只点击两次,第一次点击触发正确的视图
打开了多个实例
whatsapp 或 facebook 中的链接由于其网络浏览器而在 whatsapp 本身中打开了一个视图。
在 android 6 上只打开了一个实例,但只处理了第一个
意图,第二个和第三个打开应用程序但没有操作,因为意图数据没有以某种方式发生变化。
因此,以下不是对问题的明确答案,而是针对我们遇到的几个问题的全面解决方案。
我们的解决方案:
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) 清单:
<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) 通过调用以下示例函数来处理您的活动 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
【讨论】:
当 MainActivity 由 NavHost 管理时效果很好(从另一个应用程序启动时似乎忽略了 singleTask/singleInstance)【参考方案4】:我遇到了同样的问题,除了我希望用户使用完整的后台堆栈返回主任务,就好像他们刚刚使用应用程序切换器移动到我的应用程序一样。为此,我不得不重新排序任务。
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) 跟踪 main 任务 ID 是什么
public class MainActivity
public static int mainTaskId;
@Override
protected void onCreate(Bundle savedInstanceState)
super(savedInstanceState);
//set the main task ID
taskId = getTaskId();
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) 当主任务的后台堆栈顶部的任何活动启动时,它会检查是否有任何已保存的数据要处理,并对其进行处理。
【讨论】:
【参考方案5】:我只需添加 android:launchMode="singleTask"
即可解决这些问题
在AndroidManifest.xml
文件中
【讨论】:
它可以工作,但是如果在后台打开打开,然后如果我尝试使用启动器图标启动应用程序,那么它会再次重新启动而不是恢复,这是一个缺点。【参考方案6】:只为一个实例解决这个问题
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>
【讨论】:
SingleTask 并不总是正确的。请阅读 singleInstance 的定义。如果您的应用程序没有公开单个活动,您应该使用单任务而不是单实例。请参阅下面 Alf 的 aswer【参考方案7】:在离开深度链接Activity时考虑使用finish()
,这样如果再次操作深度链接,Activity将被重新创建。
这样可以避免错误和矛盾。
【讨论】:
【参考方案8】:在经历了多个平台上可用的不同解决方案之后。这是我在您的应用中处理深层链接的最佳实践解决方案。
首先创建一个单独的 Activity 来处理您的深层链接意图,例如。 DeepLinkHandlerActivity。
确保您在清单中指定此 Activity,如下所示:
<activity android:name=".DeepLinkHandlerActivity"
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:host="www.xyz.com"
android:pathPrefix="/abc"
android:scheme="https" />
</intent-filter>
将此活动作为“单个任务”。
下一步:设置这个新的活动如下:
class DeepLinkHandlerActivity : BaseActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.whaterever_your_layout)
handelIntent(intent)
override fun onNewIntent(intent: Intent?)
super.onNewIntent(intent)
handelIntent(intent)
private fun handelIntent(intent: Intent?)
intent?.setClass(this,SplashActivity::class.java)
startActivity(intent)
注意:SplashActivity 是您的默认活动,即您的启动器活动。
启动器活动代码,例如。
<activity
android:name=".splash.SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
就是这样!您的深层链接处理问题已解决!
【讨论】:
【参考方案9】:(在课程开始时初始化)
String itemInfo == "";
基本比较包名。
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);
这个条件itemInfo.equals(getItem(position).activityInfo.packageName)
很重要
【讨论】:
以上是关于深度链接和多个应用实例的主要内容,如果未能解决你的问题,请参考以下文章
来自深度链接意图时如何仅打开 1 个 android 应用程序实例?
带有“App”协议深度链接的 SwiftUI macOS 应用程序打开了新的应用程序实例