Android中隐式Intent的匹配规则

Android中系统组件的启动方式有显式启动和隐式启动,我们今天主要就了解一下隐式启动中的匹配规则。

1、Intent Filter匹配规则
只有action、category、data三方都匹配,Intent才算是匹配成功,进而才能打开相应的Component。一个Component若声明了多个Intent Filter,只需要匹配任意一个即可启动该组件。

 <activity
      android:name="PagerActivity"
      android:label="@string/title_activity_view_pager"
      android:theme="@style/AppTheme.NoActionBar">
      <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER"/>
      intent-filter>
      <intent-filter>
          <action android:name="com.angcyo.activity" />
          <category android:name="com.angcyo"/>
      intent-filter>
      <intent-filter>
          <action android:name="com.angcyo.activity" />
          <category android:name="com.angcyo"/>
          <data android:mimeType="image/*"/>
      intent-filter>
  activity>

其中 intent-filter 声明的部分就是此Activity匹配规则,每声明一个 intent-filter , 就定义了一组匹配规则,匹配的时候,只要匹配其中任意一组,就能启动此Activity。

action的匹配规则
一个Intent Filter中可声明多个action,Intent中的action与其中的任一个action在字符串形式上完全相同(区分大小写),action方面就匹配成功。可通过setAction方法为Intent设置action,也可在构造Intent时传入action。需要注意的是,隐式Intent必须指定action(如不指定action则必须指定data或mimetype,这种情况下,只要IntentFilter至少含有一个action就可以匹配)。

category的匹配规则
Intent中的category必须都在Intent Filter中出现才算匹配成功。Intent可以不指定category,若Intent中未指定category,系统会自动为它带上“android.intent.category.DEFAULT”。所以,想要接收隐式Intent的Component都必须在manifest文件中的Intent Filter声明中带上“android.intent.category.DEFAULT”,我们可以通过addCategory方法为Intent添加category。

data的匹配规则
data可进一步分为uri(由scheme、host、port、path | pathPattern | pathPrefix这4部分组成)和mimetype。
Intent的uri可通过setData方法设置,mimetype可通过setType方法设置。同action类似,只要Intent的data只要与Intent Filter中的任一个data声明完全相同,data方面就匹配成功。
需要注意的是:若Intent Filter的data声明部分未指定uri,则缺省uri为content或file,Intent中的uri的scheme部分需为content或file才能匹配,若要为Intent指定完整的data,必须用setDataAndType方法。

首先我们先来看一下Intent Filter中指定data的语法:

<data android:scheme="...“ 
      android:host="..." 
      android:port="..." 
      android:path="..." 
      android:pathPattern="..." 
      android:pathPrefix="..." 
      android:mimeType="..." />

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
  • Scheme:URI的模式,如果URI中没有指定Scheme,那么整个URI无效。默认值为content 和 file;
  • Host:URI的host,比如www.dxf.com。如果指定了scheme和port,path等其他参数,但是host未指定,那么整个URI无效。如果只指定了scheme,没有指定host和其他参数,URI是有效的;
  • Port:URI端口,当URI指定了scheme 和 host 参数时port参数才有意义;
  • path:用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path设置为/blog/abc.html 才能够进行匹配;
  • pathPrefix:用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
  • pathPattern: 用表达式来匹配整个路径;

2、示例

(1)只匹配scheme

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:scheme="dxf"/>
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setData(Uri.parse("dxf://adc"));
startActivity(intent);

(2)匹配 scheme host port

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:scheme="dxf" android:host="www.dxf.com" android:port="8888" />
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setData(Uri.parse("dxf://www.dxf.com:8888"));
startActivity(intent);

(3)匹配 scheme host path

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:scheme="dxf" android:host="www.dxf.com" android:path="/mypath" />
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setData(Uri.parse("dxf://www.dxf.com:8080/mypath"));
startActivity(intent);

(4)匹配 scheme host port path

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:scheme="dxf" android:host="www.dxf.com" android:port="8888" android:path="/mypath" />
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setData(Uri.parse("dxf://www.dxf.com:8888/mypath"));
startActivity(intent);

(5)mimetype匹配

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:mimeType="image/*" />
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setType("image/png");
//Scheme的默认值content/file
//intent.setDataAndType(Uri.parse("content://adc"),"image/png");
startActivity(intent);

(6)全匹配

<activity android:name=".SecondActivity">
	<intent-filter>
		<action android:name="android.intent.action.a"/>
		<action android:name="android.intent.action.b"/>
		<category android:name="android.intent.category.a"/>
		<category android:name="android.intent.category.b"/>
		<category android:name="android.intent.category.c"/>
		<category android:name="android.intent.category.DEFAULT"/>
		<data android:scheme="dxf" android:host="www.dxf.com" android:port="8888" android:path="/mypath" android:mimeType="dxf/adc"/>
	</intent-filter>
</activity>

Intent intent = new Intent();
intent.setAction("android.intent.action.a");
intent.addCategory("android.intent.category.a");
intent.setDataAndType(Uri.parse("dxf://www.dxf.com:8888/mypath"),"dxf/adc");
startActivity(intent);

3、其他注意点
(1)存在多个data匹配

一个Activity只要能匹配任何一组data,并且每个data都指定了完整的属性。

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

 <category android:name="android.intent.category.DEFAULT" />
 
 <data
 android:mimeType="dxf/abc"
 android:host="www.dxf.com"
 android:path="/mypath"
 android:port="8888"
 android:scheme="dxf" />

 <data
 android:mimeType="dxf/ddd"
 android:host="www.dxf.com"
 android:path="/mypath"
 android:port="8888"
 android:scheme="dxf_dxf" />
 intent-filter>

但有时匹配不上,暂不知其规律,建议只使用一个data。如果有多个规则需要匹配,那就添加intent-filter。

(2)多个intent-filter匹配

<intent-filter>
 <action android:name="xx" />
 <category android:name="android.intent.category.DEFAULT" />
 <data
 android:mimeType="dxf/abc"
 android:host="www.dxf.com"
 android:path="/mypath"
 android:port="8888"
 android:scheme="dxf" />
 intent-filter>

 <intent-filter>
 <action android:name="xx" />
 <category android:name="android.intent.category.DEFAULT" />
 <data
 android:mimeType="dxf/ddd"
 android:host="www.dxf.com"
 android:path="/mypath"
 android:port="8888"
 android:scheme="dxf_dxf" />
 intent-filter>

一个Activity只要能匹配任何一组intent-filter,即可成功启动对应的Activity。

(3)无法匹配时的crash log

Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { cat=[android.intent.category.DEFAULT] }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1781)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1501)
at android.app.Activity.startActivityForResult(Activity.java:3804)
at android.app.Activity.startActivityForResult(Activity.java:3765)

(4)LAUNCHER启动的Activity都需要配置

<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

4、判断是否有匹配的Intent

(1)intent.resolveActivity()

ComponentName name = intent.resolveActivity(getPackageManager());

(2)getPackageManager().resolveActivity()

ResolveInfo info = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);

(3)getPackageManager().queryIntentActivities()

List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);

5、附件
常用的schema有http、ftp、file、content等;
常用的mimeType有:

{".*","*/*"},
{".3gp", "video/3gpp"},  
{".apk", "application/vnd.android.package-archive"},  
{".asf", "video/x-ms-asf"},  
{".avi", "video/x-msvideo"},  
{".bin", "application/octet-stream"},  
{".bmp", "image/bmp"},  
{".c", "text/plain"},  
{".class", "application/octet-stream"},  
{".conf", "text/plain"},  
{".cpp", "text/plain"},  
{".doc", "application/msword"},  
{".exe", "application/octet-stream"},  
{".gif", "image/gif"},  
{".gtar", "application/x-gtar"},  
{".gz", "application/x-gzip"},  
{".h", "text/plain"},  
{".htm", "text/html"},  
{".html", "text/html"},  
{".jar", "application/java-archive"},  
{".java", "text/plain"},  
{".jpeg", "image/jpeg"},  
{".jpg", "image/jpeg"},  
{".js", "application/x-javascript"},  
{".log", "text/plain"},  
{".m3u", "audio/x-mpegurl"},  
{".m4a", "audio/mp4a-latm"},  
{".m4b", "audio/mp4a-latm"},  
{".m4p", "audio/mp4a-latm"},  
{".m4u", "video/vnd.mpegurl"},  
{".m4v", "video/x-m4v"},  
{".mov", "video/quicktime"},  
{".mp2", "audio/x-mpeg"},  
{".mp3", "audio/x-mpeg"},  
{".mp4", "video/mp4"},  
{".mpc", "application/vnd.mpohun.certificate"},  
{".mpe", "video/mpeg"},  
{".mpeg", "video/mpeg"},  
{".mpg", "video/mpeg"},  
{".mpg4", "video/mp4"},  
{".mpga", "audio/mpeg"},  
{".msg", "application/vnd.ms-outlook"},  
{".ogg", "audio/ogg"},  
{".pdf", "application/pdf"},  
{".png", "image/png"},  
{".pps", "application/vnd.ms-powerpoint"},  
{".ppt", "application/vnd.ms-powerpoint"},  
{".prop", "text/plain"},  
{".rar", "application/x-rar-compressed"},  
{".rc", "text/plain"},  
{".rmvb", "audio/x-pn-realaudio"},  
{".rtf", "application/rtf"},  
{".sh", "text/plain"},  
{".tar", "application/x-tar"},  
{".tgz", "application/x-compressed"},  
{".txt", "text/plain"},  
{".wav", "audio/x-wav"},  
{".wma", "audio/x-ms-wma"},  
{".wmv", "audio/x-ms-wmv"},  
{".wps", "application/vnd.ms-works"},  
{".xml", "text/xml"},  
{".xml", "text/plain"},  
{".z", "application/x-compress"},  
{".zip", "application/zip"},  

你可能感兴趣的:(Android)