使用 scheme 的方式去实现跳转,先整理一下思路,首先如果要外部能唤醒 App ,
那么 App 肯定要先注册一个全局的事件监听吧。然后,应该有一个页面来处理接受事件,
然后解析出具体的参数,根据参数跳转具体的页面,就是这么简单。
这里需要使用到 Android Activity中的 <intent-filter> ,现在可以创建
一个解析跳转的IntentSkipActivity,然后在清单文件中配置具体的 <intent-filter>。
<data>里面可以配置scheme host path等字段
<intent-filter>
<data android:scheme="test" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
intent-filter>
目标App有三个页面,主页A,假设起名MainActivity,点击主页按钮去
第一个测试页面B,起名为TestActivity1,点击测试页面B上的按钮去测试页面C,
起名为TestActivity2,需求是外部App是点击外部App页面的一个按钮跳转到目标App的页面C
1.当前手机中么有启动目标APP,即进程不存在
简单说就是外部APP或者浏览器链接地址点击要直接跳到目标APP的C 页面,然后回退的时候,要回退到
目标APP的A页面,然后点击A按钮可以进入B页面。这里就是需要我们自己去创建一个堆栈,把
A、C 按顺序都放进去,所以 C 回退到 A,A 然后可以启动 B。知识点就TaskStackBuilder ,配合它的
就是在 Manifest 中可以指定 Parent 的属性。
具体代码
(1)首先是在清单文件中配置B,C页面的Parent属性当然B页面可以不配置 让C页面直接返回A页面
指定C页面parentActivityName为A页面,value改为A页面
B页面
".TestActivity1"
android:parentActivityName=".MainActivity">
"android.support.PARENT_ACTIVITY"
android:value=".MainActivity"
/>
C页面
".TestActivity2"
android:parentActivityName=".TestActivity1">
"android.support.PARENT_ACTIVITY"
android:value=".TestActivity1"
/>
(2)解析跳转的IntentSkipActivity中写跳转代码
TaskStackBuilder.create(this)
.addParentStack(resultIntent.getComponent())
.addNextIntent(resultIntent)
.startActivities();
2.目标APP已经启动,在后台运行着,并且指定的 C 页面并没有打开,上面的方式,
不管你App启动没,它都是会重新启动的,这个让人也有点儿不爽,看看启动的方法就知道
public void startActivities(Bundle options) {
if (mIntents.isEmpty()) {
throw new IllegalStateException(
"No intents added to TaskStackBuilder; cannot startActivities");
}
Intent[] intents = mIntents.toArray(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,不然就在浏览器所在的堆栈里面了。
具体代码
1.判断当前APP是否开启过了
public static boolean isLaunchedActivity(Context context, Class> clazz) {
try {
Intent intent = new Intent(context, clazz);
ComponentName cmpName = intent.resolveActivity(context.getPackageManager());
boolean flag = false;
if (cmpName != null) { // 说明系统中存在这个activity
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List taskInfoList = am.getRunningTasks(10);
for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) {
if (taskInfo.baseActivity.equals(cmpName)) { // 说明它已经启动了
flag = true;
break;
}
}
}
return flag;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
2.解析跳转的IntentSkipActivity中写跳转代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TAG = this.getClass().getSimpleName();
Uri data = getIntent().getData();
try {
if (data != null) {
Log.e(TAG, "url: " + data.toString());
Intent resultIntent = JumpUtils.parseIntent(this, data.toString(), null);
if (resultIntent == null) {
finish();
return;
}
if (JumpUtils.isLaunchedActivity(this, MainActivity.class)){
resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(resultIntent);
} else {
TaskStackBuilder.create(this)
.addParentStack(resultIntent.getComponent())
.addNextIntent(resultIntent)
.startActivities();
}
finish();
}
} catch (Exception Exception) {
Exception.printStackTrace();
finish();
}
}
3.第三种情况,目标App已经启动,在后台运行着,指定的 C 页面打开着的。
这个其实就是启动模式的问题,C 已经打开,又一次打开,如果是正经的启动模式,这里肯定重复出现多个 C 页面的,
所以设置一个 SingleTop 应该是可以解决问题的。当然,如果设置了该模式,你需要去处理 onNewIntent() 的方法了。
比如说我的url:test://test1/user?userId=0001
@Nullable
public static Intent parseIntent(Context context, String url, String title) {
if (!isKnownSchemes(url)) {
return null;
}
try {
//Uri uri = getIntent().getData();
Uri data = Uri.parse(url);
//获取协议名称
String scheme = data.getScheme();
//获取主机名称
String host = data.getHost();
//获取路径
String path = data.getPath();
//获取参数为userId的值
String userId = data.getQueryParameter("userId");
//获取所有参数的集合
Set<String> parameterNames = data.getQueryParameterNames();
HashMap<String, String> map = null;
if (!parameterNames.isEmpty()) {
map = new HashMap<>();
for (String name : parameterNames) {
map.put(name, data.getQueryParameter(name));
}
}
Log.e(TAG, "host: " + host); //test
Log.e(TAG, "path: " + path); //user
Log.e(TAG, "scheme: " + scheme); //test
Log.e(TAG, "userId: " + userId); //0001
if (map != null) {
Log.e(TAG, "query: " + map.toString());
}
return parseSchemes(context, host, path, map);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Nullable
private static Intent parseSchemes(Context context, String host, String path, Map queryies) {
Log.e(TAG, "parse: host:" + host);
Log.e(TAG, "parse: path:" + path);
Log.e(TAG, "parse: queryies:" + queryies);
Intent intent;
switch (host) {
case "test1":
intent = new Intent(context, TestActivity1.class);
try {
intent.putExtra(Constants.TITLE, queryies.get("title"));
} catch (Exception e) {
e.printStackTrace();
}
return intent;
case "test2":
intent = new Intent(context, TestActivity2.class);
try {
intent.putExtra(Constants.TITLE, queryies.get("title"));
} catch (Exception e) {
e.printStackTrace();
}
return intent;
default:
}
intent = new Intent(context, MainActivity.class);
return intent;
}
解析跳转的IntentSkipActivity中的跳转代码参考上面
scheme方式跳转适用一个APP的一个页面跳转目标APP的目标页面,
WebView的一个链接地址跳转目标APP的目标页面,
适用浏览器的链接地址跳转目标APP的目标页面
Notification 的方式也是一样的
又get一个新的跳页面的方式startActivities()
qq: 1509815887
email:[email protected]
点击去下载