因项目需要,经常碰到我们的 APP 需要跳转到(唤醒)外部 APP,或者外部 APP 需要跳转到(唤醒)我们的 APP。
一、引言
在开发的过程中,我们经常会遇到需要从一个应用程序跳转到另一个应用程序的场景。这就需要我们掌握 APP 之间的相互跳转知识。
APP 间跳转应用场景:
- 使用第三方用户登录,跳转到需授权的 APP。如 QQ 登录,微信登录等。需要用户授权,还需要"返回到调用的程序,同时返回授权的用户名、密码"
- 应用程序推广,跳转到另一个应用程序(本机已经安装),或者跳转到 应用商店(如苹果的 iTunes及 Android 的Google play store)并显示应用程序下载页面(本机没有安装)
- 第三方支付,跳转到第三方支付 APP,如支付宝支付,微信支付
- 内容分享,跳转到分享 APP 的对应页面,如分享给微信好友、分享给微信朋友圈、分享到微博
- 显示位置、地图导航,跳转到地图应用
- 使用系统内置程序,跳转到打电话、发短信、发邮件、浏览器 打开网页等内置 APP 中
二、iOS APP 间跳转实现
iOS 有个特性就是应用将其自身”绑定”到一个自定义 URL scheme 上,该 scheme 用于从浏览器或其他应用中启动本应用。常见的分享到第三方之间的跳转都是基于 Scheme 的。
2.1 info.plist 参数配置或获取
如果目标 APP 是第三方 APP,则需要知道 URL Schemes(可通过文档或联系对方获取)。
如果目标是本方 APP,那么需要在项目中的 info.plist 文件中添加 URL Types,并告之对方,如下图所示:
说明:
- URL identifier只是一个标示符,是项目的 bundle id,随意填写,建议写成:com.. 反转域名的方法保证该名字的唯一性。
- URL Scheme 就是用来通信的命令前缀,用来定位一个应用,应用的唯一标志,通过它来确定打开那个应用。例子使用 “btamaota”。
一定要分清哪些配置,在哪方配置,被唤醒与唤醒。
2.2 在项目中添加跳转代码
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"btamaota://"]];
这里的 URL 的命令前缀必须和之前定义的一致。
2.3 本方 APP 跳转 Amazon Alexa APP
项目中,我方 APP 需跳到 Amazon Alexa APP,跳转代码如下:
//手机有安装 Amazon alexa,跳转到Amazon alexa
NSURL *schemeUrl = [NSURL URLWithString:@"alexa:"];
//手机没有安装 Amazon alexa,跳到苹果应用商店 Amazon alexa 页面
NSURL *appStoreUrl = [NSURL URLWithString:@"https://itunes.apple.com/app/amazon-alexa/id944011620?mt=8"];
[UIApplication sharedApplication] canOpenURL:schemeUrl;
三、Android APP 间跳转实现
Android APP 间跳转实现方式比较多样化,并不像 iOS 那么单一。
3.1 通过 PackageManager 唤起
只需知道目标 APP 的包名即可。
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage("com.cchip.cchipamaota");
if (intent != null) {
startActivity(intent);
}
3.2 通过 ComponentName 唤起
使用 ComponentName 唤起目标 APP 也很简单,需要注意的是目标 APP 的 Activity 需要在 manifest 配置中设置 exported 为 true
<activity android:name="com.cchip.cchipamaota.MainActivity"
android:exported="true"/>
调用代码如下:
Intent intent = new Intent();
ComponentName componentName = new ComponentName("com.cchip.cchipamaota", "com.cchip.cchipamaota.MainActivity");
intent.setComponent(componentName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
另一种写法:
Intent intent = new Intent();
intent.setClassName("com.cchip.cchipamaota", "com.cchip.cchipamaota.MainActivity");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
带参数的调用:
Intent intent = new Intent();
ComponentName componentName = new ComponentName("com.cchip.cchipamaota", "com.cchip.cchipamaota.MainActivity");
intent.setComponent(componentName);
Bundle bundle = new Bundle();
bundle.putString("key", "value");
intent.putExtras(bundle);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
3.3 通过 scheme 唤起
通过定义自己的scheme协议,可以非常方便跳转 APP 中的各个页面;它是通过 URL 的形式进行跳转的。
Android 通过隐式跳转到拨号页面(其实就是用 Uri 的形式唤起目标 APP,并传递数据):
Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + phoneNumber));
startActivity(intent);
scheme协议的主要结构:
- scheme: 具体的协议,这里可以自定义,只要双方约定好就行
- host:端口号,这里也是要双方约定好即可
- appId: 需要被唤起的应用的 ID(这里注重说一下,最好不要用包名而是用 APPID 否则可能唤起不了)
$scheme$://$host$#Intent;scheme=$scheme$;package=$appId$;end
<activity
android:name="com.cchip.cchipamaota.MainActivity"
android:exported="true">
<intent-filter>
<!--可以根据用户的数据类型,打开相应的Activity-->
<action android:name="android.intent.action.VIEW" />
<!--界面可以被隐式调用-->
<category android:name="android.intent.category.DEFAULT" />
<!--界面可以通过浏览器的连接启动-->
<category android:name="android.intent.category.BROWSABLE" />
<!--协议部分,主要是配置scheme和host-->
<data
android:host="home1234"
android:scheme="host1234" />
</intent-filter>
</activity>
用下面的方法即可:
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.parse("host0712://home0712#Intent;scheme=host0712;package=com.cchip.cchipamaota;end"));
startActivity(intent);
另一种写法:
<activity android:name="com.cchip.cchipamaota.SecondActivity">
<intent-filter>
<action android:name="name.foo" />
<data
android:host="home1234"
android:scheme="host1234" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
调用方法:
Intent intent = new Intent("name.foo");
Uri uri = Uri.parse("host1234://home1234?key=value");
intent.setData(uri);
startActivity(intent);