[关闭]
@linux1s1s 2019-02-14T07:05:59.000000Z 字数 6320 阅读 2023

Intent Filters

AndroidMechanism 2015-05


先来看一下Google 官方文档关于intent-filter的说明 或者 intent 的官方说明
看完上面的官方文档,我们来回答几个问题:

好了,看完上面的官方文档,如果你觉得回答不了上面的几个问题,那么有必要继续往下看了

场景

在了解Intent-Filter之前先来考虑这样一个场景,用过Android手机的人应该都知道,比如说我在某个App例如新浪微博中点击拍照,会跳转到照相机的界面。但是当我新装了camer360或之类的第三方照相app的时候在微博中点击照相就会先弹出一个Dialog来让我选择是使用默认camer还是camer360.

对于上面的场景,我们来看一下Android官方文档是如何解释上面一系列动作的。

此处输入图片的描述

为了看懂这张图,有必要说明一下Android生成Intent的两种方式:

显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应程序的组件名称。因此,显式Intent更多用于在应用程序内部传递消息。

Intent intent = new Intent(MainActivity.this,SubActivity.class);

隐式Intent它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。如果要跳转到一个未知路径,但是已知功能的Activity就要用到隐式intent。

Intent intent = new Intent(Intent.ACTION_SEND);

接下来我们把上面的情景模拟一下

  1. <activity
  2. android:name=".MainActivity"
  3. android:label="@string/title_activity_main" >
  4. <intent-filter>
  5. <action android:name="android.intent.action.MAIN" />
  6. <category android:name="android.intent.category.LAUNCHER" />
  7. </intent-filter>
  8. </activity>
  9. <activity
  10. android:name=".BActivity"
  11. android:label="@string/title_activity_main"
  12. android:launchMode="singleTask" >
  13. <intent-filter>
  14. <action android:name="com.h3c.intent.ACTION_VIEW"/>
  15. <category android:name="android.intent.category.DEFAULT"/>
  16. </intent-filter>
  17. </activity>
  18. <activity
  19. android:name=".CActivity"
  20. android:label="@string/title_activity_main" >
  21. <intent-filter>
  22. <action android:name="com.h3c.intent.ACTION_VIEW"/>
  23. <category android:name="android.intent.category.DEFAULT"/>
  24. </intent-filter>
  25. </activity>

然后在MainActivity代码中这样启动一个Activity会发生什么?

  1. //隐式声明Intent实例
  2. Intent intent = new Intent("com.h3c.intent.ACTION_VIEW");
  3. startActivity(intent);

这时就会重现上面的情景,出现一个供用户可以选择的界面,让用户去决定选择哪个Activity。

如果不想让用户去选择怎么办,很简单,直接通过显示Intent来做即可

  1. //显式声明Intent实例
  2. Intent intent = new Intent(MainActivity.this,BActivity.class);
  3. startActivity(intent);

接下来我们回到一开始的Document,看一看这些属性的含义

Action

先来说一下必须包含的属性,action属性。
翻译成中文就是动作测试

  1. <activity android:name="com.x210.intentfilters.OneActivity" android:label="oneActivity">
  2. <intent-filter>
  3. <action android:name="myapp.action.test1" />
  4. <category android:name="android.intent.category.DEFAULT" />
  5. </intent-filter>
  6. </activity>
  1. <activity android:name="com.x210.intentfilters.OtherActivity" android:label="otherActivity">
  2. <intent-filter>
  3. <category android:name="cate1"/>
  4. <category android:name="cate2"/>
  5. <category android:name="android.intent.category.DEFAULT" />
  6. </intent-filter>
  7. </activity>

只能得到一个悲催的结局:任何Intent请求都无法与该匹配

  1. <activity android:name="com.x210.intentfilters.OneActivity" android:label="oneActivity">
  2. <intent-filter>
  3. <action android:name="myapp.action.test1" />
  4. <action android:name="myapp.action.test2" />
  5. <action android:name="myapp.action.test3" />
  6. <category android:name="android.intent.category.DEFAULT" />
  7. </intent-filter>
  8. </activity> <span style="color:#ff0000">

凡是隐式声明中含有上面其中一个action都满足匹配要求,比如:

  1. //action = myapp.action.test1
  2. Intent intent = new Intent("myapp.action.test1");
  3. startActivity(intent);
  4. //action = myapp.action.test2
  5. Intent intent = new Intent("myapp.action.test2");
  6. startActivity(intent);

关于action说到这里,接下来说另外一个重要的属性category

Category

接着说一下另外一个很重要的属性,类别测试,这个属性不是必须的,下面解释一下为什么不是必须的。

理论上来说,如果intent不指定category,那么无论intent filter的内容是什么都应该是匹配的。但是,如果是implicit intent,android默认给加上一个CATEGORY_DEFAULT,这样的话如果intent filter中没有android.intent.category.DEFAULT这个category的话,匹配测试就会失败。所以,如果你的 activity支持接收implicit intent的话就一定要在intent filter中加入android.intent.category.DEFAULT。

当然了,也不是所有的隐式申明都得加这个DEFAULT,比如下面这个:

  1. <intent-filter>
  2. <action android:name="android.intent.action.MAIN" />
  3. <category android:name="android.intent.category.LAUNCHER" />
  4. </intent-filter>

这个是启动主Activity,所以隐式申明的时候不用这个DEFAULT值。

除此之外,category的用途还有很多
比如做个桌面,按home键时启动自己做的应用

  1. <activity
  2. android:name=".MainActivity"
  3. android:label="@string/app_name" >
  4. <intent-filter>
  5. <action android:name="android.intent.action.MAIN" />
  6. <category android:name="android.intent.category.LAUNCHER"/>
  7. <category android:name="android.intent.category.HOME" />
  8. </intent-filter>
  9. </activity>

另外顺便说一下,显试声明Intent,就是在代码里面生成Intent实例如何做,这个跟隐式声明没有啥区别,像下面这样

  1. intent.setAction(action);intent.setData(data);intent.addCategory(category);
  2. intent.setAction(action);
  3. intent.setData(data);
  4. intent.addCategory(category);

接下来说最后一个属性:data,数据测试

Data

开始之前,我们先说一个比较意思的事情:假如主Activity这么声明会发生什么事情?

  1. <intent-filter>
  2. <action android:name="android.intent.action.MAIN" />
  3. <category android:name="android.intent.category.LAUNCHER" />
  4. <data android:scheme="gametime" />
  5. </intent-filter>

如果感兴趣的话可以自己动手做个试验,不感兴趣的话只需要知道结果就可以了:程序虽然能正常跑起来,却找不到App 在桌面上的快捷方式。究其原因,自己考虑一下。这里提示一下Android官方文档对于ACTION_MAIN
http://developer.android.com/guide/components/intents-filters.html
The ACTION_MAIN action indicates this is the main entry point and does not expect any intent data.
解释一下:ACTION_MAIN 行动测试代表这是App的主入口,并不期望带有数据的任何意图。

好了说完上面比较有趣的事情,接下来我们切入正题:

元素指定了希望接受的Intent请求的数据URI和数据类型,URI被分成三部分来进行匹配:scheme、 authority和path
。其中,用setData()设定的Inteat请求的URI数据类型和scheme必须与IntentFilter中所指定的一致。若IntentFilter中还指定了authority或path,它们也需要相匹配才会通过测试。

  1. <intent-filter>
  2. <data android:type="video/mpeg" android:scheme="http"/>
  3. <data android:type="audio/mpeg" android:scheme="http"/>
  4. </intent-filter>

data有一个比较重要的功能就是deepLink,所以这里说一下如何配置deepLink
- 配置build.gradle

  1. productFlavors {
  2. //flavor name
  3. trunk {
  4. applicationId project.hasProperty('flavorPackageName') ? flavorPackageName : 'com.nel.nevideo'
  5. manifestPlaceholders = [deeplinkScheme: project.hasProperty('schemeName') ? schemeName : 'nevideo']
  6. }
  7. }

上面的配置可以通过gradlew -P 参数传进来,这个不再扩展开了,我们主要看一下deeplinkScheme这个占位符,这个占位符将在Manifest中占位,如下所示
- 配置AndroidManifest

  1. <intent-filter>
  2. <action android:name="android.intent.action.VIEW" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. <category android:name="android.intent.category.BROWSABLE" />
  5. <data android:scheme="${deeplinkScheme}" />
  6. </intent-filter>

当然了,如果主Activity需要这么一个deepLink怎么办,好办,就再加一个 intent-filter 即可,如下

  1. <intent-filter>
  2. <action android:name="android.intent.action.MAIN" />
  3. <category android:name="android.intent.category.LAUNCHER" />
  4. </intent-filter>
  5. <intent-filter>
  6. <action android:name="android.intent.action.VIEW" />
  7. <category android:name="android.intent.category.DEFAULT" />
  8. <category android:name="android.intent.category.BROWSABLE" />
  9. <data android:scheme="${deeplinkScheme}" />
  10. </intent-filter>

上面的配置,存在多个intent-filter 这些intent-filter是或的关系,只要其中一个满足,即可通过测试

参考文档:
http://blog.csdn.net/h3c4lenovo/article/details/7722259
http://my.oschina.net/hadescen/blog/90286
http://blog.csdn.net/andie_guo/article/details/9271973
http://blog.csdn.net/jason0539/article/details/10049899

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注