IntentFilter匹配
通过Intent隐式启动Activity通过IntentFilter匹配合适的Activity进行启动。参考《启动Activity的几种方式》。其中主要通过action、category、data进行匹配,在Intent源码中可以查看到三个私有成员变量的定义:
...
private String mAction;
private Uri mData;
...
private ArraySet<String> mCategories;1、action
Intent必须且只能设置一个action。从源码可以看到,action定义为String类型的mAction成员变量。必须给Intent定义action,否则无法匹配。
//Intent构造函数设置action
Intent intent = new Intent("com.quibbler.action");
//setAction()设置action
Intent intent = new Intent();
intent.setAction("com.quibbler.action")匹配规则:
Intent中的action与Activity的intent-filter中的任何一个action相同即可。一个Activity intent-filter下可以定义多个action进行匹配:
<activity android:name=".Activity">
<intent-filter>
<action android:name="com.quibbler.actionA" />
<action android:name="com.quibbler.actionB" />
<action android:name="com.quibbler.actionC" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>2、category
category在Intent中的定义是一个String集合:
private ArraySet<String> mCategories;意味着可以给一个Intent添加很多category
intent.addCategory(Intent.CATEGORY_DEFAULT);
//addCategory源码
public @NonNull Intent addCategory(String category) {
if (mCategories == null) {
mCategories = new ArraySet<String>();
}
mCategories.add(category.intern());
return this;
}匹配规则:
①Intent可以不定义category,因为调用startActivity()的时候会自动加上"android.intent.category.DEFAULT"
②由于第①条,Activity intent-filter中必须要加上"android.intent.category.DEFAULT"
③Intent有多少个category,全部都要和Activity intent-filter下的category匹配才行
④上一条可以认为:Intent中的category集合是 intent-filter下category集合的子集
3、data
Intent中只有一个data,也就是Uri。
private Uri mData;3.1、data属性
intent-filter中data的一共有如下几个属性:
<data
android:host="string"
android:mimeType="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:port="string"
android:scheme="string"
android:ssp="string"
android:sspPattern="string"
android:sspPrefix="string" />3.2、data组成
data由两个部分组成,mimeType和Uri:
mimeType:媒体类型,可以表示数据是文本、视频、图片等类型。
Uri:包含的数据比较多,Uri的结构如下:
<scheme>://<host>:<port>/[<path>|<pathPattern>|<pathPrefix>]通过data可以实现网页跳转到APP指定Activity的DeepLink,参考《Android DeepLink跳转》。
4、注意
4.1、不存在匹配
通过Intent启动Activity等组件,如果没有匹配的将会奔溃:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.easyicon.learnglide, PID: 22700
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.quibbler.action cat=[android.intent.category.DEFAULT] }
所以在用Intent启动前最好先判断是否存在可以处理Intent的Activity。通过PackageManager下面的两个方法查询是否有Activity的intent-filter匹配Intent,返回结果不为null,则一定可以启动Activity。PackageManager.MATCH_DEFAULT_ONLY标志位仅在intent-filter中添加了"android.intent.category.DEFAULT"的Activity中进行匹配。
①最佳匹配:ResolveInfo resolveActivity(Intent intent,int flags)
PackageManager packageManager = getPackageManager();
ResolveInfo resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);②所有能匹配的:List<ResolveInfo> queryIntentActivities(Intent intent,int flags)
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);4.2、组件exported
四大组件的默认android:exported属性就是true,设置为false第三方再试图启动将会报错。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.easyicon.learnglide, PID: 23104
java.lang.SecurityException: Permission Denial: starting Intent { act=com.quibbler.action cat=[android.intent.category.DEFAULT] cmp=com.easyicon.client/.BaseActivity } from ProcessRecord{55dce8a 23104:com.easyicon.learnglide/u0a123} (pid=23104, uid=10123) not exported from uid 10153

