intent-filter 之 data 「scheme, host, port, mimeType, path, pathPrefix, pathPattern」

本文详细解读了AndroidManifest.xml中intent-filter中data标签的scheme、host、port、path、pathPrefix、pathPattern、mimeType属性的含义及用法,并提供了实际例子演示其应用。

本文转自:http://www.cnblogs.com/newcj/archive/2011/08/11/2135094.html

之前一直搞不很明白 AndroidManifest.xml 中 activity 标签下的 intent-filter 中 data 标签的属性含义,今天认真看了 Dev Guide,又在网上查询了大量相关资料,现把 data 标签中的属性含义做一个总结。
 

一、定义
 

scheme, host, port, path, pathPrefix, pathPattern 是用来匹配 Intent 中的 Data Uri 的。具体规则如下:
 

  scheme://host:port/path or pathPrefix or pathPattern
 

这里需要注意的是这里的 scheme 不是 schema,也许你记得 xmlns:android="http://schemas.android.com/apk/res/android" 这段声明,你就会想起其中的 schema (至少我是这样想到了...- -!),但这里的 scheme 不是 schema。虽然在写 AndroidManifest.xml 的时候,有智能提示,但是希望大家还是能注意到。

上面那句最后的 “path or pathPrefix or pathPattern” 是指后面的 path 验证可以使用 data 属性中的 android:path、android:pathPrefix 或 pathPattern,你可以添加任意个 data 标签,由于是 “or” ,因此,只要其中任意一个 data 匹配,系统就会选择你的 Activity 启动,当然,如果别的 Activity 也有相同的 data 标签,系统就会给用户弹出一个 Chooser Dialog。


mimeType 也是是用来匹配 Intent 的。比如,当你使用 Intent.setType("text/plain") ,那么系统将会匹配到所有注册 android:mimeType="text/plain" 的 Activity,想获取更多有关 mimeType 的知识请参考:【转】备份:Android 常用 mimeType 表

这里需要十分注意的是 Intent.setType(), Intent.setData,Intent.setDataAndType() 这三个方法!
 

  • setType 调用后设置 mimeType,然后将 data 置为 null;
  • setData 调用后设置 data,然后将 mimeType 置为 null;
  • setDataAndType 调用后才会同时设置 data 与 mimeType。
     
另外需要注意的是,如果你在 data 标签,既设置了 mimeType 又设置了 scheme 之内的,那么你的 Intent 需要同时设置匹配的 data 与 mimeType 即调用 setDataAndType ,系统才能匹配到这个 Activity(即便你 mimeType 设置为 "*/*" 也是如此)。当然,如果你没有设置 mimeType,那么调用 setData 进行匹配,如果你设置了任何的 mimeType 将不会匹配到该 Activity。

二、区别

  这里主要说的区别是  pathpathPrefixpathPattern 之间的区别
 
  • path 用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
  • pathPrefix 用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
  • pathPattern 用表达式来匹配整个路径,这里需要说下匹配符号与转义。
匹配符号:
  1. “*” 用来匹配0次或更多,如:“a*” 可以匹配“a”、“aa”、“aaa”...
  2. “.” 用来匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”...
  3. 因此 “.*” 就是用来匹配任意字符0次或更多,如:“.*html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”...
转义:
因为当读取 Xml 的时候,“\” 是被当作转义字符的(当它被用作 pathPattern 转义之前),因此这里需要两次转义,读取 Xml 是一次,在 pathPattern 中使用又是一次。如:“*” 这个字符就应该写成 “\\*”,“\” 这个字符就应该写成 “\\\\”。


三、一些例子

   例子1:如果我们想要匹配 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” 其他都一样。
 

例子2:如果我们做的是一个IM应用,或是其他类似于微博之类的应用,如何让别人通过 Intent 进行调用分享出现在选择框里呢?
 
我们只用注册 android.intent.action.SEND 与 mimeType 为 “text/plain” 或 “*/*” 就可以了,整个 intent-filter 设置为:
<intent-filter>
     <action android:name="android.intent.action.SEND" />
     <category android:name="android.intent.category.DEFAULT" />
     <data mimeType="*/*" />
</intent-filter>

这里设置 category 的原因是,创建的 Intent 的实例默认 category 就包含了 Intent.CATEGORY_DEFAULT ,google 这样做的原因是为了让这个 Intent 始终有一个 category。

例子3:如果我们做的是一个音乐播放软件,当文件浏览器打开某音乐文件的时候,使我们的应用能够出现在选择框里?
 
这类似于文件关联了,其实做起来跟上面一样,也很简单,我们只用注册 android.intent.action.VIEW 与 mimeType 为 “audio/*” 就可以了,整个 intent-filter 设置为:
<intent-filter>
     <action android:name="android.intent.action.VIEW" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:mimeType="audio/*" />
</intent-filter>

参考:
【2】备份:Android 常用 mimeType 表  http://www.cnblogs.com/newcj/archive/2011/08/10/2134305.html

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal"> <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" /> <uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc.hce" android:required="false" /> <uses-feature android:name="android.hardware.nfc" android:required="false" /> <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:hardwareAccelerated="true"> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <!-- 添加NFC处理 --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="myapp" /> </intent-filter> <!-- 添加深度链接处理 --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="xl" android:host="goods" android:port="8888" android:pathPrefix="/goodsDetail" /> </intent-filter> </activity> </application> </manifest> 这是我现在的xml文件,我的应用包名为com.example.text 我该怎么更改,并使用什么URL去启动应用并传递数据
最新发布
08-07
<think>我们正在处理一个关于Android Intent Filter配置的问题,特别是如何支持通过微信打开特定类型的文件,使用content scheme。 根据用户的问题,我们需要配置intent-filter来匹配微信发送的Intent,并且这个Intent使用content scheme。 回顾引用内容: 引用[1]提到:pathPattern支持正则表达式,但需要注意转义字符。 引用[2]:IntentFilter用来过滤隐式意图,声明在清单文件中。 引用[4]:提到category的匹配,特别是默认category(android.intent.category.DEFAULT)的重要性。 引用[5]:给出了一个微信支付的例子,其中在intent-filter中配置了datascheme为微信的特定值(wxbbcf236b07638282),并且包含了actioncategory。 但是用户的需求是支持通过微信打开特定类型的文件,且使用content scheme。微信打开文件时,发送的Intent应该包含文件的URI,其scheme可能是content。 我们需要配置一个activity的intent-filter,使其能够接收微信发送的打开文件的Intent。 典型的配置包括: 1. action: 通常为android.intent.action.VIEW(查看文件) 2. category: 必须包含android.intent.category.DEFAULT(因为隐式启动需要) 3. data: 需要指定scheme为content,并且可能还需要指定mimeType来过滤特定类型的文件。 例如,如果我们希望应用能够打开微信分享的PDF文件,我们可以这样配置: ```xml <activity android:name=".FileViewerActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <!-- 指定scheme为content --> <data android:scheme="content" /> <!-- 指定mimeType为application/pdf --> <data android:mimeType="application/pdf" /> </intent-filter> </activity> ``` 注意:一个intent-filter中可以包含多个data元素,但同一个intent-filter中的data元素是“或”的关系,即满足其中一个即可。如果需要同时满足多个条件,则应该使用多个intent-filter。 另外,微信在打开文件时,可能会在Intent中设置特定的包名(setPackage)或组件,但如果是通过系统选择器,则会是隐式Intent。因此,我们配置的intent-filter需要能够匹配微信发送的隐式Intent。 同时,根据引用[5]中的例子,微信支付中配置了特定的scheme(微信的appid)来接收回调,但这我们处理的是文件打开,所以不需要微信的特定scheme,而是使用content scheme。 但是,需要注意的是,content scheme的URI通常由ContentProvider提供,它并不包含主机名(host路径(path)的固定格式,因此我们通常只指定schememimeType。 另外,微信在分享文件时,可能会使用不同的mimeType,所以如果我们希望支持多种类型,可以添加多个mimeType,或者使用通配符(如 */* 表示所有类型)。但使用通配符可能会导致我们的应用出现在系统打开各种文件的选项中,因此最好指定具体的mimeType。 如果我们的应用希望处理多种类型的文件,可以配置多个intent-filter,或者在一个intent-filter中指定多个data元素(每个data元素指定一种mimeType)。但是,同一个intent-filter中多个data元素是“或”的关系,所以这样是可以的。 例如,支持PDF图片: ```xml <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <data android:mimeType="application/pdf" /> <data android:mimeType="image/*" /> </intent-filter> ``` 这样,当微信发送一个content schemeIntent,并且mimeType是PDF或者任意图片时,我们的应用就会出现在选择列表中。 另外,我们还需要在Activity中处理接收到的Intent。在FileViewerActivity中,我们需要从Intent中获取数据(URI),然后使用ContentResolver打开文件流进行处理。 注意:由于使用了content scheme,我们需要通过ContentResolver来读取文件,并且要处理权限问题(在Android 6.0以上,使用content URI不需要申请存储权限,因为权限已经包含在URI中)。 总结步骤: 1. 在AndroidManifest.xml中为Activity配置intent-filter,指定action为VIEW,category为DEFAULT,scheme为content,并设置需要处理的mimeType。 2. 在Activity中获取Intent,并从中提取Uri。 3. 使用ContentResolver打开Uri对应的文件流,进行读取展示。 下面是一个简单的Activity中处理Intent的示例代码: ```java public class FileViewerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_file_viewer); Intent intent = getIntent(); Uri uri = intent.getData(); if (uri != null) { // 根据mimeType决定如何处理文件 String mimeType = getContentResolver().getType(uri); // 打开文件流,读取并展示 try (InputStream inputStream = getContentResolver().openInputStream(uri)) { // 处理输入流... } catch (IOException e) { e.printStackTrace(); } } } } ``` 注意:在实际应用中,我们可能需要根据文件类型进行不同的处理,比如PDF文件用PDF库渲染,图片用ImageView显示等。 另外,微信在发送文件时,可能会在Intent中附加额外的信息,我们可以通过Intent的getExtras()获取。 最后,为了确保我们的应用能够出现在微信的分享选择列表中,我们需要正确配置intent-filter,并且确保没有其他条件限制(比如exported属性设置为true,允许其他应用启动)。 根据引用[5]中的提醒,我们还需要在Activity中设置exported="true",但注意,如果设置了intent-filter,默认exported就是true(如果没有设置其他限制的话)。不过,为了安全,我们可能需要考虑是否要设置exported,如果不需要被其他应用启动,可以设置为false。但这我们需要被微信启动,所以必须为true。 因此,在清单文件中,我们不需要显式设置exported,因为默认就是true(当有intent-filter时)。但是,如果我们的Activity不需要被其他应用启动,我们应该设置exported="false",但这需要被微信启动,所以我们要确保exported为true。我们可以显式设置: ```xml <activity android:name=".FileViewerActivity" android:exported="true"> ... intent-filter ... </activity> ``` 注意:在Android 12(API级别31)及以上,如果Activity声明了intent-filter,则必须显式设置android:exported,否则安装会失败。 因此,建议显式设置exported属性。 综上所述,配置如下: ```xml <activity android:name=".FileViewerActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <!-- 支持的文件类型,按需添加 --> <data android:mimeType="application/pdf" /> <data android:mimeType="image/*" /> <!-- 还可以添加其他类型,如文本、视频等 --> </intent-filter> </activity> ``` 这样配置后,当微信尝试打开一个content scheme的文件,并且文件的mimeType匹配我们指定的类型时,我们的应用就会出现在选择列表中。 如果用户选择我们的应用,我们的Activity就会启动,并获取到文件的content URI。 注意:微信在分享文件时,可能会使用file scheme,但自Android 7.0(Nougat)以后,file scheme不允许跨应用共享,因此微信使用的是content scheme(通过FileProvider生成content URI)。所以我们的intent-filter只需要处理content scheme即可。 最后,用户可能还需要测试配置是否生效。可以使用adb命令发送一个Intent来测试: ``` adb shell am start -a android.intent.action.VIEW -c android.intent.category.DEFAULT -d "content://com.example.provider/path/to/file.pdf" -t "application/pdf" ``` 其中,com.example.provider是你的ContentProvider的authority,需要替换为实际的。 以上便是配置intent-filter以支持微信打开content scheme文件的方法。</think>### Android配置Intent Filter支持微信打开Content Scheme文件 在Android应用中配置Intent Filter以支持通过微信打开`content://`类型的文件,需要以下步骤: #### 1. 配置AndroidManifest.xml ```xml <activity android:name=".FileHandlerActivity" android:exported="true"> <intent-filter> <!-- 必须包含VIEW动作 --> <action android:name="android.intent.action.VIEW" /> <!-- 必须添加DEFAULT category --> <category android:name="android.intent.category.DEFAULT" /> <!-- 关键配置:声明支持content scheme --> <data android:scheme="content" /> <!-- 按需添加MIME类型过滤 --> <data android:mimeType="application/pdf" /> <!-- PDF示例 --> <data android:mimeType="image/*" /> <!-- 所有图片类型 --> </intent-filter> </activity> ``` #### 2. 关键配置说明 - **`<data android:scheme="content">`** 声明支持`content://`协议的URI,这是微信分享文件时使用的标准协议[^2][^5] - **`<category android:name="android.intent.category.DEFAULT">`** 隐式Intent必须包含此category才能匹配成功[^4] - **MIME类型过滤** 根据实际需求添加具体类型: - `image/*`:所有图片类型 - `application/pdf`:PDF文档 - `video/*`:视频文件 - `text/plain`:文本文件 #### 3. Activity中处理Intent 在目标Activity中处理接收到的Content URI: ```java public class FileHandlerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取微信传递的Intent Intent intent = getIntent(); Uri contentUri = intent.getData(); if (contentUri != null) { // 通过ContentResolver读取文件 try (InputStream inputStream = getContentResolver().openInputStream(contentUri)) { // 处理文件流(显示/上传/保存等) handleFileStream(inputStream); } catch (IOException e) { Log.e("FileHandler", "文件读取失败", e); } } } private void handleFileStream(InputStream is) { // 实现文件处理逻辑 } } ``` #### 4. 权限配置 在`AndroidManifest.xml`中添加必要权限: ```xml <!-- 读取Content Provider权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 11+ 需要添加 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> ``` #### 5. 微信适配注意事项 1. **文件大小限制** 微信分享的文件通常有大小限制(Android版约100MB) 2. **URI权限持久化** 使用`ContentResolver.takePersistableUriPermission()`保持URI访问权限: ```java getContentResolver().takePersistableUriPermission( contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ); ``` 3. **Android版本兼容** - Android 7.0+ 必须使用FileProvider处理文件共享 - Android 11+ 需要适配Scoped Storage #### 测试验证方法 ```bash # 使用adb测试Intent Filter adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.DEFAULT \ -d "content://media/external/images/media/123" \ -t "image/jpeg" ``` ### 常见问题解决 1. **匹配失败** - 检查是否遗漏`category.DEFAULT`[^4] - 确认微信发送的MIME类型与过滤类型匹配 2. **权限拒绝** - 添加`android:grantUriPermissions="true"`到`<provider>`声明 - 动态申请`READ_EXTERNAL_STORAGE`权限(Android 10及以下) 3. **文件路径获取** ```java // 从Content URI获取实际路径 String path = getRealPathFromURI(contentUri); ``` [^1]: IntentFilter支持正则表达式匹配路径,但`content://`URI通常不包含路径参数 [^2]: `content` scheme是Android文件共享的标准协议 [^4]: 隐式Intent必须包含`category.DEFAULT`才能匹配 [^5]: 微信支付配置验证了scheme声明的重要性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值