原生开发 APP 唤醒(跳转)外部 APP 的方法

因项目需要,经常碰到我们的 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);