Android进阶之Intent Filter匹配规则与隐式启动Activity

时间:2021-08-03 18:29:25

1 Intent Filter匹配规则

  Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行匹配判断的。一个过滤列表中的action、type、category可以有多个,所有的action、type、category分别构成不同类别,同一类别信息共同约束当前类别的匹配过程。只有一个Intent同时匹配action、type、category这三个类别才算完全匹配,才能启动Activity。另外一个组件若声明了多个Intent Filter,只需要匹配任意一个即可启动该组件。

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
<data android:mimeType="image/*" />
</intent-filter>

1.1 action的匹配规则

  action是一个字符串,如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配。一个Intent Filter中可声明多个action,Intent中的action与其中的任一个action在字符串形式上完全相同(注意:区分大小写),action方面才能匹配成功。

<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_TO"/>
</intent-filter>

  只要Intent的action为“SEND”或“SEND_TO”,那么这个Intent在action方面就能和上面那个Activity匹配成功。  

Intent intent = new Intent("android.intent.action.SEND") ;
startActivity(intent);

  Android系统预定义了许多action,这些action代表了一些常见的操作。常见action如下(Intent类中的常量)

Intent.ACTION_VIEW
Intent.ACTION_DIAL
Intent.ACTION_SENDTO
Intent.ACTION_SEND
Intent.ACTION_WEB_SEARCH

1.2 data的匹配规则

  如果Intent没有提供type,系统将从data中得到数据类型。和action一样,同action类似,只要Intent的data只要与Intent Filter中的任一个data声明完全相同,data方面就完全匹配成功。
  
  data由两部分组成:mimeType和URI。Intent的uri可通过setData方法设置,mimetype可通过setType方法设置。
  MineType指的是媒体类型:例如imgage/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式
  URI由scheme、host、port、path | pathPattern | pathPrefix、queryString这5部分组成,例如:

scheme://host:port/path?qureyParameter=queryString
http://www.orangecpp.com:80/tucao?id=hello

  Intent Filter中指定data的语法:

<data android:host="" // 指定数据的主机名,如www.baidu.com
android:mimeType="" // 指定可以处理的数据类型,允许使用通配符的方式进行指定
android:path="" // 主机名和端口之后的部分
android:pathPattern=""
android:pathPrefix=""
android:port="" // 指定数据端口部分
android:scheme="" // 指定数据的协议部分,如http
android:ssp=""
android:sspPattern=""
android:sspPrefix=""/>

  案例1:根据URI,传递数据的获取

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("svmplayer://player?name=" + name + "&url=" + url));
context.startActivity(intent);
if (intent != null) {
videoUrl = URLDecoder.decode(intent.getData().getQueryParameter("url"), "UTF-8");
title = URLDecoder.decode(intent.getData().getQueryParameter("name"), "UTF-8");
}

  案例2:如果我们想要匹配 http 以 “.pdf” 结尾的路径,使得别的程序想要打开网络 pdf 时,用户能够可以选择我们的程序进行下载查看。
我们可以将 scheme 设置为 “http”,pathPattern 设置为 “.*//.pdf”,整个 intent-filter 设置为:

<intent-filter>  
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="http" android:pathPattern=".*//.pdf"></data>
</intent-filter>

  如果只想处理某个站点的 pdf,那么在 data 标签里增加 android:host=”yoursite.com” 则只会匹配 http://yoursite.com/xxx/xxx.pdf,但这不会匹配 www.yoursite.com,如果也想匹配这个站点的话,你就需要再添加一个 data 标签,除了 android:host 改为 “www.yoursite.com”,其他都一样。

1.3 category的匹配规则

  category也是一个字符串,但是它与action的过滤规则不同,它要求Intent中个如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。也就是说,Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中的定义了的category。
  当然,Intent中也可以没有category(若Intent中未指定category,系统会自动为它带上“android.intent.category.DEFAULT”),如果没有,仍然可以匹配成功。
  特别说明:这二者共同出现,标明该Activity是一个入口Activity,并且会出现在系统应用列表中,二者缺一不可。

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

1.4 Intent Filter常见问题汇总

(1)path、pathPrefix、pathPattern 之间的区别
  path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
  pathPrefix 用来匹配路径的开头部分,拿上来的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
  pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。

(2)关于隐式intent
  每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败.
  例如:说一个activity组件要想被其他组件通过隐式intent调用, 则其在manifest.xml中的声明如下。

<activity android:name="com.wooyun.org.MainActivity">
<intent-filter>
<action android:name="com.google.test" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

(3)于intent-filter匹配优先级
  首先查看Intent的过滤器(intent-filter),按照以下优先关系查找:action->data->category。

2 自定义隐式Intent

(1)比如有一个Activity名称为SecondActivity,在AndroidManifest.xml中配置:

<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.ACTION_SECOND"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

(2)启动的时候

Intent intent = new Intent("com.example.ACTION_SECOND");
StartActivity(intent);

(3)只有action和category中的内容同时匹配上Intent中指定的action和category时,该Activity才能响应该Intent。android.intent.category.DEFAULT是默认的category,在调用startActivity方法时会自动将这个category添加到Intent中。可以为一个Activity指定多个category,即在SecondActivity中多添加一个category。

<category android:name="com.zjq.activity.CUSTOM_CATEGORY"/>

(4)则在启动SecondActivity时:

Intent intent = new Intent("com.zjq.activity.ACTION_SECOND");
intent.addCategory("com.zjq.activity.CUSTOM_CATEGORY");
startActivity(intent);

3 系统定义的Action

(1)启动浏览器并打开某个网页

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

(2)跳转到拨号界面

Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"));

4 参考链接

你必须弄懂的Intent Filter匹配规则

Android隐式启动Activity