Android实现外部唤起应⽤跳转指定页⾯的⽅法
前⾔
通常有这么⼀个场景,就是分享内容到朋友圈等,然后点击内容中的某个按钮就可以唤起⾃家应⽤。
这⾥要讲的也是使⽤ scheme 的⽅式去实现跳转,先捋⼀捋思路,⾸先如果要外部能唤醒 App ,那么 App 肯定要先注册⼀个全局的事件监听吧。然后,应该有⼀个页⾯来处理接受事件然后解析出具体的参数然后跳转具体的页⾯。就是这么简单。
思路捋好来,那么就来⼀⼀实现吧。
注册事件监听
这⾥需要使⽤到 Android Activity中的 <intent-filter> ,现在可以创建⼀个解析跳转的 Activity,名字随便取了,然后需要在Manifest ⽂件中配置具体的 <intent-filter>。
<intent-filter>
<data
android:scheme="test"
android:host="lovejjfg"
/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
如上配置,现在这个 Activity 就具备外部唤醒的能⼒了,注意下 <data> 中的相关配置,如上配置,外部的链接形式应该就是这样的了:test://lovejjfg/xxx 。<data> ⾥⾯还可以定义其他内容,这⾥就不展开说了。
页⾯跳转
咳咳,这⾥要注意下了,⽐如说你有⼀个启动页 A,主页是 B,现在要跳到指定的 C 页⾯。那么外部
唤起 App 的时候,其实有⼏种情况,这都是需要我们去考虑的。
先决考虑,这个看产品的需求了,那就是打开具体的页⾯,是仅启动该页⾯,回退直接返回浏览器,还是需要启动 App。如果就是仅仅打开页⾯就⾏,那么很简单,直接跳转页⾯就好,不⽤考虑新建任务栈什么情况。如果回退要启动⽬标App,不然⽤户直接回到浏览器,这⾥就要再区分⼏种情况了。
第⼀种情况,就是当前⼿机中并没有启动过⽬标 App。
简单说就是浏览器要直接跳到 C 页⾯,然后回退的时候,是显⽰ A 页⾯,然后进⼊ B 页⾯。这⾥就是需要我们⾃⼰去创建⼀个堆栈,把 A、C 按顺序都放进去,所以 C 回退到 A,A 然后可以启动 B。知识点就是 TaskStackBuilder ,配合它的就是在Manifest 中可以指定 Parent 的属性。
Activity 逻辑⽗项的类名称。此处的名称必须与为相应元素的 android:name 属性指定的类名称⼀致。系统会读取
该属性,以确定当⽤户按下操作栏中的“向上”按钮时应该启动哪⼀个 Activity。系统还可以利⽤这些信息通
过 TaskStackBuilder 合成 Activity 的返回栈。
要⽀持 API 级别 4 - 16,您还可以使⽤为 "android.support.PARENT_ACTIVITY"
指定值的元素来声明⽗ Activity。
所以这⾥就看你的适配情况了。接下来看看这个 TaskStackBuilder 的使⽤,其实并不难,抄抄就会了。哈哈。详细的参照官⽅⽂档只是这⾥说的是 PendingIntent 的开启⽅式,我们这⾥其实是直接 startActivity() 的⽅法,这个要怎么操作呢?
TaskStackBuilder stackBuilder = ate(this);
stackBuilder.Component());
stackBuilder.addNextIntent(resultIntent);
stackBuilder.startActivities();
其实我⼀开始是不知道直接开启 Activity 需要怎么操作,因为抄的那⾥没有这么写,没有抄的就⾃⼰去看看⽅法咯。⼀开始我是看到了Intents() 的⽅法,然后机智的我赶紧试了下,调⽤context.startActivities() 果然有效果,后⾯才发现⼈家builder 直接就有开启Activity 的⽅法,没错就是上⾯的写法。
等等,Builder 怎么被我写成这样了?这不是在侮辱Builder模式吗?
.Component())
.addNextIntent(resultIntent)
.startActivities();
这才是最正确的操作嘛。接下来说第⼆种情况,⽬标 App 已经启动,在后台运⾏着,并且指定的 C 页⾯并没有打开。上⾯的⽅式,不管你App启动没,它都是会重新启动的,这个让⼈也有点⼉不爽啊,那么为什么会每次都重新启动呢?看看启动的⽅法就知道咯。
public void startActivities(Bundle options) {
if (mIntents.isEmpty()) {
throw new IllegalStateException(
"No intents added to TaskStackBuilder; cannot startActivities");
}
Intent[] intents = Array(new Intent[mIntents.size()]);
intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
if (!ContextCompat.startActivities(mSourceContext, intents, options)) {
Intent topIntent = new Intent(intents[intents.length - 1]);
topIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mSourceContext.startActivity(topIntent);
}
}
看重点,这个⽅法每次都会给第⼀个Intent添加了
Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK | IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME 这三个Flag,因为有IntentCompat.FLAG_ACTIVITY_CLEAR_TASK 所以就成这个样⼦咯,那么怎么解决呢?其实很简单的,我们在跳转的时候先判断下当前App是否已经开启过了嘛,,没有的话,那就直接上⾯的代码,有的话,那就不⽤再去创建堆栈了,直接开启就好了。直接开启的时候记得要加上Intent.FLAG_ACTIVITY_NEW_TASK的Flag,不然就在浏览器所在的堆栈⾥⾯了。
if (ViewUtils.isLaunchedActivity(this, HomeActivity.class)) {
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(resultIntent);
} else {
.Component())
.addNextIntent(resultIntent)
.startActivities();
}
public static boolean isLaunchedActivity(@NonNull Context context, Class<?> clazz) {
Intent intent = new Intent(context, clazz);
ComponentName cmpName = PackageManager());
boolean flag = false;
if (cmpName != null) {
ActivityManager am = (ActivityManager) SystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfoList = am.getRunningTasks(10);
for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {
if (taskInfo.baseActivity.equals(cmpName)) {
flag = true;
break;
}
}
}
return flag;
}
第三种情况,⽬标 App 已经启动,在后台运⾏这,指定的 C 页⾯打开着的。
这个其实就是启动模式的问题,C 已经打开,⼜⼀次打开,如果是正经的启动模式,这⾥肯定重复出现多个 C 页⾯的,所以呢,设置⼀个 SingleTop 就是可以解决问题的。当然,如果设置了该模式,你需要去处理onNewIntent() 的⽅法了。
参数解析
参数这⼀块看⾃⼰怎么定义的,⽐如说我定义的就是 test://lovejjfg/C?10086
Uri data = getIntent().getData();
String host = Host();
String path = Path();
String id = QueryParameter("id")
安卓intent用法String scheme = Scheme();
Log.i(TAG, "host: " + host);//lovejjfg
Log.i(TAG, "path: " + path);//C
Log.i(TAG, "scheme: " + scheme);//test
Log.i(TAG, "id: " + id);//'10086'
上⾯的思路不局限于 scheme 跳转应⽤的使⽤,Notification 的⽅式也是⼀样的。另外 startActivities() 的姿势是不是很帅?
PS:没事就多看看官⽅⽂档吧,很多都已经了。
-2017 12 28 更新-
因为有很多⼩伙伴⼉也有类似的需求,有些问题已经在评论回复中解决。增加测试 Demo 和测试链接,新增通知跳转,⽅便⼤家测试。
总结
以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论