IntentFilter匹配

QuibblerQuibbler 2020-03-09 约 10 分钟 1777 次阅读

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

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w