您的位置:首页 > 移动开发 > Android开发

有关Android的外部拉起

2017-01-24 00:11 1246 查看

背景介绍

由于自己做的是TV端的视频APP,需要和各个厂商对接,也涉及到很多从厂商的Launcher直接拉起到APP里的各个界面的场景,例如在Launcher的某部影片海报上点击直接拉起这部影片的详情页而不是我们应用的首页。所以在这里对Android的外部拉起相关的做一个总结。

拉起方式

通过隐式调用startActivity的方式。

启动Activity分为显式调用和隐式调用,相信这个大家都有所了解。显式调用是明确地指定了启动对象的包名和类名;而隐式调用则通过指定Intent的一些信息,例如action、category、data,匹配这些信息的Activity就会被启动,如果有多个匹配,则系统会弹出一个窗口给用户选择,这里有个注意的地方,我们平常看到的是可以选择“总是”打开某个选项,如果在某些场景下想每次都弹出窗口,不想用户设置默认的选项,我们可以调用

Intent.createChooser(Intent target, CharSequence title))


这个方法将返回一个Intent,传入的参数是目标Intent和窗口标题,这样就会每次都弹出窗口来让用户选择,并且可以设置窗口的标题。

IntentFilter匹配规则

前面说到Activity去匹配Intent的action、data等,那是怎么个匹配法呢?下面就说说Activity是怎么通过IntentFilter来匹配的。

在Manifest文件中的 Activity 标签添加 IntentFilter 属性, IntentFilter 中的过滤信息有action、category、data,一个IntentFilter可以有多个action、category和data, Activity 中同样可以有多个 IntentFilter ,只要有能匹配其中一个便可以启动这个Activity。

Action 一个想要执行的动作的名称。通常是系统已经定义的值,不过我们也可以在应用中定义自己的action,在这里我们就是自己来定义的。IntentFilter中可以有多个action,但是Intent只能set一个action,多次set则会替换掉前面。所以Intent的action只需要匹配IntentFilter中的任意一个action,如果IntentFilter里没有包含任何action,则任何隐式Intent都无法启动这个Activity;如果隐式Intent没有setAction,正常来说这个隐式Intent应该无法启动任何Activity,但是我尝试了下发现:如果IntentFilter中有action和data,其中data若是匹配成功,则IntentFilter有action而Intent没有setAction仍然可以启动这个Activity,如果IntentFilter中没有data则无法启动。

Category 和Action不同的地方是,Intent提供的方法是 addCategory,这意味着Intent中同样可以有多个category,Intent中所有的category都必须能在IntentFilter中找到才算匹配,IntentFilter有多余的category的话则不会有影响。而且,所有隐式Intent都会默认加上 android.intent.category.DEFAULT,所以如果Activity想被隐式Intent启动,都必须在IntentFilter中添加 CATEGORY_DEFAULT 类型的category,而如果我们不在代码中做任何addCategory也同样可以匹配,因为系统会给我们默认加上 android.intent.category.DEFAULT。

data data在Intent中同样只能设置一个,在IntentFilter中可以有多个,在Action匹配成功的情况下,Intent和IntentFilter的data均为空也可以匹配,Intent为空而IntentFilter不为空则不能匹配。data比前面两个要稍微复杂一些,由 mimeType 和 Uri 两种属性组成,mimeType指的是媒体类型,例如 text/plain, image/jpeg,而我们的应用在这里主要是通过 Uri 来传递数据,Uri由多scheme、host等多个部分组成,我们这里用scheme来匹配,后面加上各个参数信息,Activity中通过下面的方法即可获得传入的Uri,然后再统一解析处理跳转界面。

intent.getDataString();


IntentFilter如下所示:

<intent-filter>
<action android:name="com.intent.myaction" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="wsy" />
</intent-filter>


启动的代码示例:

private void handleIntent(Intent intent) {
intent.setAction("com.intent.myaction");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
if (isIntentSafe) {
startActivity(intent);
} else {
Toast.makeText(this, "未安装xxx,无法跳转", Toast.LENGTH_SHORT).show();
}
}
private void openWithDetailPageUri() {
Intent intent = new Intent();
intent.setData(Uri.parse("wsy://?action=1&cover_id=xxxxxx"));
handleIntent(intent);
}


这里还要注意,当通过隐式Intent启动Activity时,如果没有Activity能够匹配的话就会报错,所以我们必须加一个判断,可以用PackageManager提供的 queryIntentActivities 来查询是否存在能够匹配该隐式Intent的Activity。

最后

因为外部拉起的场景较多,为了便于管理,不需要 putExtra 的话用adb shell am 命令调试也很方便 ,所以采用这种方式统一拉起到一个Activity,再解析处理传入的Intent数据,最后再执行跳转操作,当然实际的逻辑还要再复杂一些,像按返回键时是否直接退出应用,已经打开我们应用情况再执行外部拉起的场景等等,这些暂时不再赘述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android