我希望能够从网络下载具有特定扩展名的文件,并将其传递给我的应用程序来处理它,但我无法弄清楚意图过滤器。文件类型不包含在 mimetypes 中,我尝试使用
<data android:path="*.ext" />
但我无法让它发挥作用。
我希望能够从网络下载具有特定扩展名的文件,并将其传递给我的应用程序来处理它,但我无法弄清楚意图过滤器。文件类型不包含在 mimetypes 中,我尝试使用
<data android:path="*.ext" />
但我无法让它发挥作用。
这是我在 AndroidManifest.xml 中定义我的活动以使其正常工作的方式。
<activity android:name="com.keepassdroid.PasswordActivity">
<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="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.kdb" />
<data android:host="*" />
</intent-filter>
</activity>
scheme
offile
表示这应该在打开本地文件时发生(而不是像 HTTP 这样的协议)。
mimeType
可以设置为*/*
匹配任何 mime 类型。
pathPattern
是您指定要匹配的扩展名的地方(在此示例中.kdb
)。.*
开头的 匹配任何字符序列。这些字符串需要双重转义,因此\\\\.
匹配文字句点。然后,以文件扩展名结束。pathPattern 的一个警告是,.*
如果这是一个正则表达式,这不是一个贪婪的匹配。.
此模式将无法匹配在 .之前包含 a 的路径.kdb
。有关此问题的更详细讨论和解决方法,请参见此处
最后,根据 Android 文档,host
和scheme
属性都是该pathPattern
属性工作所必需的,因此只需将其设置为通配符即可匹配任何内容。
现在,如果您.kdb
在 Linda File Manager 之类的应用程序中选择一个文件,我的应用程序就会显示为一个选项。我应该注意,仅此一项并不允许您在浏览器中下载此文件类型,因为这仅在文件方案中注册。在您的手机上拥有像 Linda File Manager 这样的应用程序本身通常允许您下载任何文件类型。
关于这个主题有很多错误信息,尤其是来自 Google 自己的文档。最好的,并且考虑到奇怪的逻辑,可能唯一真正的文档是源代码。
意图过滤器实现具有几乎无法描述的逻辑。解析器代码是另一个相关的难题。
以下过滤器非常接近合理的行为。对于"file"
方案意图,路径模式确实适用。
只要文件扩展名匹配,全局 mime 类型模式匹配就会匹配所有类型。这并不完美,但它是匹配 ES 文件资源管理器等文件管理器行为的唯一方法,并且仅限于 URI/文件扩展名匹配的意图。
我没有包括像"http"
这里这样的其他方案,但它们可能在所有这些过滤器上都可以正常工作。
奇怪的方案是"content"
,其扩展对过滤器不可用。但只要提供商说明您的 MIME 类型(例如,Gmail 将不受阻碍地传递附件的 MIME 类型),过滤器就会匹配。
需要注意的问题:
scheme
AND才能匹配规则(目前与 Google 的 API 指南相反)。host
path
""
,其过滤方式与 非常不同null
,无法显式匹配,只能通过有风险的"*/*"
过滤器匹配。"*/*"
过滤器不会匹配具有 MIME 类型的 Intent -null
这需要针对这种特定情况使用单独的过滤器,而根本没有 MIME 类型。"content"
方案只能通过 MIME 类型匹配,因为原始文件名在意图中不可用(至少在 Gmail 中)。"data"
(几乎)与解释无关,除了host
和port
- 的特定例外,它们确实配对在一起。"data"
其他所有内容在元素内或元素之间没有特定关联"data"
。考虑到这一切,下面是一个带有注释的示例:
<!--
Capture content by MIME type, which is how Gmail broadcasts
attachment open requests. pathPattern and file extensions
are ignored, so the MIME type *MUST* be explicit, otherwise
we will match absolutely every file opened.
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.my-type" />
</intent-filter>
<!--
Capture file open requests (pathPattern is honoured) where no
MIME type is provided in the Intent. An Intent with a null
MIME type will never be matched by a filter with a set MIME
type, so we need a second intent-filter if we wish to also
match files with this extension and a non-null MIME type
(even if it is non-null but zero length).
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<!--
Work around Android's ugly primitive PatternMatcher
implementation that can't cope with finding a . early in
the path unless it's explicitly matched.
-->
<data android:pathPattern=".*\\.my-ext" />
<data android:pathPattern=".*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>
<!--
Capture file open requests (pathPattern is honoured) where a
(possibly blank) MIME type is provided in the Intent. This
filter may only be necessary for supporting ES File Explorer,
which has the probably buggy behaviour of using an Intent
with a MIME type that is set but zero-length. It's
impossible to match such a type except by using a global
wildcard.
-->
<intent-filter
android:icon="@drawable/icon"
android:label="@string/app_name"
android:priority="50" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<!--
Work around Android's ugly primitive PatternMatcher
implementation that can't cope with finding a . early in
the path unless it's explicitly matched.
-->
<data android:pathPattern=".*\\.my-ext" />
<data android:pathPattern=".*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>
我必须承认,在 Android 上打开电子邮件附件和文件系统文件的简单任务是有史以来最令人抓狂的体验之一。处理太多或太少的文件很容易。但要做到恰到好处是很难的。stackoverflow 上发布的大多数解决方案对我来说都无法正常工作。
我的要求是:
完成此任务的最佳方法可能是为您的附件指定自定义 MIME 类型。您可能还会选择自定义文件扩展名。因此,假设我们的应用名为“Cool App”,我们生成的文件附件末尾带有“.cool”。
这是我最接近目标的一次,而且效果很好……令人满意。
<!-- Register to handle email attachments -->
<!-- WARNING: Do NOT use android:host="*" for these as they will not work properly -->
<intent-filter>
<!-- needed for properly formatted email messages -->
<data
android:scheme="content"
android:mimeType="application/vnd.coolapp"
android:pathPattern=".*\\.cool" />
<!-- needed for mangled email messages -->
<data
android:scheme="content"
android:mimeType="application/coolapp"
android:pathPattern=".*\\.cool" />
<!-- needed for mangled email messages -->
<data
android:scheme="content"
android:mimeType="application/octet-stream"
android:pathPattern=".*\\.cool" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<!-- Register to handle file opening -->
<intent-filter>
<data android:scheme="file"
android:mimeType="*/*"
android:pathPattern=".*\\.cool"
android:host="*"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
笔记:
pathPattern
似乎或多或少地忽略了附件(使用时)android:scheme="content"
。如果有人让 pathPattern 只响应某些模式,我会很高兴看到如何。android:host="*"
如果我添加了该属性,Gmail 应用程序拒绝在选择器中列出我的应用程序。intent-filter
但我尚未验证这一点。android:scheme="http"
可以使用。请注意,某些浏览器可能会搞砸android:mimeType
这样的实验,android:mimeType="*/*"
并在调试器中检查实际通过的内容,然后收紧过滤,以免最终成为处理所有事情的烦人应用程序。intent-filter
是在 Galaxy S3 上使用三星的“我的文件”应用程序进行测试的。FX Explorer 仍然拒绝正确打开文件,我还注意到应用程序图标未用于文件。同样,如果有人让它工作,请在下面发表评论。我希望您会发现这很有用,并且您不必浪费几天时间来研究所有可能的组合。有改进的余地,欢迎评论。
上面布赖恩的回答让我成功了 90%。为了完成它,对于我使用的 mime 类型
android:mimeType="*/*"
我怀疑以前的海报试图发布相同的细节,但是尽管引用了斜杠星作为代码,stackoverflow 将它显示为一个斜杠。
Android 已向意图过滤器的内容 URI 和 MIME-Type 发展。
内容 URI 不一定必须包含文件的扩展名或名称,并且在提供内容/文件的不同应用程序之间会有所不同。
以下是来自不同电子邮件应用程序的相同电子邮件附件的一些示例内容 URI :
邮箱 ->content://com.google.android.gm.sapi/some_email@gmail.com/message_attachment_external/%23thread-a%3Ar332738858767305663/%23msg-a%3Ar-5439466788231005876/0.1?account_type=com.google&mimeType=application%2Foctet-stream&rendition=1
展望->content://com.microsoft.office.outlook.fileprovider/outlookfile/data/data/com.microsoft.office.outlook/cache/file-download/file--2146063402/filename.customextention
三星电子邮件应用程序 ->content://com.samsung.android.email.attachmentprovider/1/1/RAW
正如所见,它们都是不同的,并且不保证包含与您的实际文件相关的任何内容。因此,您不能使用android:pathPattern
大多数人建议的方式。
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content"/>
<data android:host="*"/>
<!-- Required for Gmail and Samsung Email App -->
<data android:mimeType="application/octet-stream"/>
<!-- Required for Outlook -->
<data android:mimeType="application/my-custom-extension"/>
</intent-filter>
通过测试,我找到了 Gmail、Outlook 和三星电子邮件使用的 MIME 类型,并将它们添加到我的意图过滤器中。
我发现通过上述解决方案,如果我打开任何二进制类型的文件,它会自动启动我的应用程序。如果我们无法解析文件,我会在我的活动中通过显示失败状态来处理此问题。我认为这是一个非常罕见的事件,所以它是可以接受的。
<data android:mimeType="*/*"/>
如果不添加到我的意图过滤器,我找不到任何方法通过文件浏览器启动我的应用程序。我不能使用它,因为它会在用户点击手机上的任何文件(不仅仅是自定义文件扩展名)时启动我的应用程序。我不建议将其添加到您的意图过滤器中。
而不是android:path
, try android:mimeType
, 具有此特定内容的 MIME 类型的值。此外,android:path
不接受通配符 -android:pathPattern
用于此目的。
我一直试图让它工作很长时间,并且基本上尝试了所有建议的解决方案,但仍然无法让 Android 识别特定的文件扩展名。我有一个带有"*/*"
mimetype 的意图过滤器,它似乎是唯一有效的东西,文件浏览器现在将我的应用程序列为打开文件的选项,但是我的应用程序现在显示为打开任何类型文件的选项,即使我已经使用 pathPattern 标签指定了特定的文件扩展名。到目前为止,即使我尝试在我的联系人列表中查看/编辑联系人,Android 也会询问我是否要使用我的应用程序来查看联系人,而这只是发生这种情况的众多情况之一,非常非常烦人。
最终,我发现这个 google groups 发布了一个类似的问题,一位实际的 Android 框架工程师回答了这个问题。她解释说,android 根本不知道文件扩展名,只知道 MIME 类型(https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0)。
因此,从我所见、尝试和阅读的情况来看,Android 根本无法区分文件扩展名,而 pathPattern 标签基本上是对时间和精力的巨大浪费。如果您有幸只需要某种 mime 类型的文件(例如文本、视频或音频),则可以使用具有 mime 类型的意图过滤器。如果您需要特定的文件扩展名或 Android 不知道的 mime 类型,那么您就不走运了。
如果我对此有任何错误,请告诉我,到目前为止,我已经阅读了每一篇文章并尝试了我能找到的每一个提议的解决方案,但没有一个奏效。
我可以再写一两页来说明这类事情在 Android 中的普遍性以及开发人员的体验是多么糟糕,但我会为你省去我愤怒的咆哮;)。希望我为某人节省了一些麻烦。
如果后缀未在 Android 的 system=wide MIME 数据库中注册为 MIME 类型,则上述任何操作都不能正常工作,对于 VIEW 或 SEND 操作。我发现对指定后缀触发的唯一设置包括android:mimeType="*/*"
,但随后对所有文件触发该操作。显然不是你想要的!
如果不将 mime 和后缀添加到 Android mime 数据库,我找不到任何合适的解决方案,到目前为止,我还没有找到一种方法来做到这一点。如果有人知道,指针会很棒。
在 Android 4 上,规则变得比过去更加严格。利用:
<data
android:host=""
android:mimeType="*/*"
android:pathPattern=".*\\.ext"
android:scheme="file"
></data>
我自己一直在为自定义文件扩展名而苦苦挣扎。经过大量搜索,我找到了这个网页,发帖人发现当您的路径包含路径中其他地方的匹配模式的第一个字符时,Android 的 patternMatcher 类(用于 Intent-Filters 中的 pathPattern 匹配)具有意外行为(例如,如果您尝试匹配“*.xyz”,则如果您的路径中前面有一个“x”,则 patternMatcher 类将停止)。这是他找到的解决方法,并为我工作,尽管它有点像黑客:
PatternMatcher 用于 IntentFilter 的 pathPattern 但是,PatternMatcher 的算法对我来说很奇怪。这是Android PatternMatcher 的算法。
如果字符串中间有“.*”模式的“下一个字符”,PatternMatcher 将在该点停止循环。(参见 Android 框架的 PatternMatcher.java。)
前任。字符串:“这是我的附件”模式:“. att. ”。Android PatternMatcher 进入循环匹配'. ' 模式直到遇到模式的下一个字符(在这个例子中,'a')所以,'。' 匹配循环在索引 8 处停止 - 'is' 和 'my' 之间的 'a'。因此,此匹配的结果返回“假”。
很奇怪,不是吗。要解决这个问题 - 实际上减少可能性 - 开发人员应该使用烦人的愚蠢 pathPattern。
前任。目标:匹配包含“消息”的 uri 路径。
<intent-filter>
...
<data android:pathPattern=".*message.*" />
<data android:pathPattern=".*m.*message.*" />
<data android:pathPattern=".*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*m.*message.*" />
...
</intent-filter>
与自定义文件扩展名匹配时尤其会发出此问题。
Brian 的回答非常接近,但是在尝试使用您自己的自定义扩展名(不需要方案或主机)打开文件时,这是一种干净且无错误的方式来调用您的应用程序:
<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:mimeType="*/*" />
<data android:pathPattern="*.*\\.kdb" />
</intent-filter>
当 Intent 满足 aintent-filter
时,这些是intent-filter
要求:(想象一个清单)。
<action>
<category>
<data mimeType>
(容易修复:“ / ”)可选:
任何匹配<data scheme>
(容易修复<data android:scheme="file" /> <data android:scheme="content" />
:)
任何匹配<data host>
(简单修复:“*”)
<data pathPattern/etc.>
(例如.*\\.0cc
)定义多个<data $type="">
元素会检查 $type 框,如果任何<data $type=>
匹配Intent
.
省略 mimeType 会破坏你的intent-filter
,即使它看起来是多余的。省略<data scheme/host/pathPattern>
会导致您的过滤器匹配所有内容。
https://f-droid.org/en/packages/de.k3b.android.intentintercept/是一个旨在接收所有意图的应用程序,并允许您检查意图。我了解到通过简单文件管理器打开的无法识别的文件扩展名是通过 MIME 类型提供的application/octet-stream
。
https://stackoverflow.com/a/4621284/2683842报告它<data pathPattern=>
.*xyz
第一次看到就中止,x
如果后面没有yz
. 所以除非你尝试,否则/sdcard/.hidden/foo.0cc
不会通过。.*\\.0cc
.*\\..*\\.0cc
最终结果:
<activity android:name=".Ft2NsfActivity">
<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="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:pathPattern=".*\\.ftm"/>
<data android:pathPattern=".*\\..*\\.ftm"/>
<data android:pathPattern=".*\\..*\\..*\\.ftm"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\.ftm"/>
<data android:pathPattern=".*\\.0cc"/>
<data android:pathPattern=".*\\..*\\.0cc"/>
<data android:pathPattern=".*\\..*\\..*\\.0cc"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\.0cc"/>
<data android:mimeType="*/*" />
</intent-filter>
</activity>
使用以下过滤器从浏览器、gmail 和文件浏览器打开(已测试)。注意:请不要合并两个过滤器,这会使浏览器忽略您的应用程序(已测试)。
<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="file" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
<data android:scheme="content" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
</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="http"
android:host="*"
android:pathPattern=".*\\.ext" />
<data android:scheme="https"
android:host="*"
android:pathPattern=".*\\.ext" />
<data android:scheme="ftp"
android:host="*"
android:pathPattern=".*\\.ext" />
</intent-filter>
如果您希望直接从 Gmail、Dropbox 或任何内置 android 文件工具打开文件,请使用以下代码(删除使文件无法被 gmail 访问的 'android:host="*"'):
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content" android:pathPattern=".*\\.kdb"
android:mimeType="application/octet-stream"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="file" android:mimeType="*/*"
android:pathPattern=".*\\.kdb"/>
</intent-filter>
根据 Android 4.x 版本,数据过滤器必须写在一个语句中
阅读此 https://developer.android.com/training/sharing/receive ,这可能有助于开始。然后在清单文件中在要打开的活动中注册接收器时尝试以下意图过滤器
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="content"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/your_extension" />
</intent-filter>
确保提供的扩展名没有“。” 在里面