特定文件扩展名的Android意图过滤器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1733195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android intent filter for a particular file extension?
提问by Curyous
I want to be able to download a file with a particular extension from the 'net, and have it passed to my application to deal with it, but I haven't been able to figure out the intent filter. The filetype is not included in the mimetypes, and I tried using
我希望能够从 'net 下载具有特定扩展名的文件,并将其传递给我的应用程序来处理它,但我无法弄清楚意图过滤器。文件类型不包含在 mimetypes 中,我尝试使用
<data android:path="*.ext" />
but I couldn't get that to work.
但我无法让它发挥作用。
回答by Brian Pellin
Here is how I defined my activity in my AndroidManifest.xml to get this to work.
这是我在 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>
The scheme
of file
indicates that this should happen when a local file is opened (rather than protocol like HTTP).
在scheme
中file
表明,当一个本地文件被打开(而不是像HTTP协议),这应该发生。
mimeType
can be set to \*/\*
to match any mime type.
mimeType
可以设置为\*/\*
匹配任何 mime 类型。
pathPattern
is where you specify what extension you want to match (in this example .kdb
). The .*
at the beginning matches any squence of characters. These strings require double escaping, so \\\\.
matches a literal period. Then, you end with your file extension. One caveat with pathPattern is that .*
is not a greedy match like you would expect if this was a regular expression. This pattern will fail to match paths that contain a .
before the .kdb
. For a more detailed discussion of this issue and a workaround see here
pathPattern
是您指定要匹配的扩展名的地方(在本例中.kdb
)。在.*
开头的任何字符匹配SQUENCE。这些字符串需要双重转义,因此\\\\.
匹配文字句点。然后,您以文件扩展名结束。pathPattern 的一个警告是,.*
如果这是一个正则表达式,它不像您期望的那样贪婪匹配。此模式将无法匹配..
之前包含 a 的路径.kdb
。有关此问题的更详细讨论和解决方法,请参见此处
Finally, according to the Android documentation, both host
and scheme
attributes are required for the pathPattern
attribute to work, so just set that to the wildcard to match anything.
最后,根据Android文档,都host
和scheme
属性是必需的pathPattern
属性来工作,所以才设置为通配符匹配任何东西。
Now, if you select a .kdb
file in an app like Linda File Manager, my app shows up as an option. I should note that this alone does not allow you to download this filetype in a browser, since this only registers with the file scheme. Having an app like Linda File Manager on your phone resisters itself generically allowing you to download any file type.
现在,如果您.kdb
在 Linda File Manager 等应用程序中选择一个文件,我的应用程序会显示为一个选项。我应该注意,仅此一项并不能让您在浏览器中下载此文件类型,因为这只会注册文件方案。在您的手机上安装 Linda File Manager 之类的应用程序本身通常会允许您下载任何文件类型。
回答by David Sainty
There's a lot of misinformation on this topic, not least from Google's own documentation. The best, and given the strange logic, possibly the only real documentation is the source code.
关于这个主题有很多错误信息,尤其是来自 Google 自己的文档。最好的,并且考虑到奇怪的逻辑,可能唯一真正的文档是源代码。
The intent filter implementationhas logic that almost defies description. The parser codeis the other relevant piece of the puzzle.
该意图过滤器的实现具有几乎无法描绘的逻辑。该解析器代码是其他相关的一块拼图。
The following filters get pretty close to sensible behaviour. The path patterns do apply, for "file" scheme intents.
以下过滤器非常接近合理的行为。路径模式确实适用于“文件”方案意图。
The global mime type pattern match will match all types so long as the file extension matches. This isn't perfect, but is the only way to match the behaviour of file managers like ES File Explorer, and it is limited to intents where the URI/file extension matches.
只要文件扩展名匹配,全局 MIME 类型模式匹配将匹配所有类型。这并不完美,但它是匹配文件管理器(如 ES 文件资源管理器)行为的唯一方法,并且仅限于 URI/文件扩展名匹配的意图。
I haven't included other schemes like "http" here, but they will probably work fine on all these filters.
我没有在此处包含其他方案,例如“http”,但它们可能适用于所有这些过滤器。
The odd scheme out is "content", for which the extension is not available to the filter. But so long as the provider states your MIME type (E.g. Gmail will pass on the MIME type for the attachment unimpeded), the filter will match.
奇怪的方案是“内容”,其扩展名对过滤器不可用。但是只要提供商声明您的 MIME 类型(例如 Gmail 将无阻碍地传递附件的 MIME 类型),过滤器就会匹配。
Gotchas to be aware of:
需要注意的问题:
- Be aware that nothing behaves consistently in the filters, it's a maze of specal cases, and treats violation of the principle of least surprise as a design goal. None of the pattern matching algorithms follow the same syntax or behaviour. Absence of a field sometimes is a wildcard and sometimes isn't. Attributes within a data element sometimes must go together and sometimes ignore grouping. It really could have been done better.
- The scheme AND the host must be specified for path rules to match (contrary to Google's API guide, currently).
- At least ES File Explorer generates intents with a MIME type of "", which is filtered very differently to null, is impossible to match explicitly, and can only be matched by the risky "*/*" filter.
- The "*/*" filter will NOT match Intents with a null MIME type - that requires a separate filter for this specific case with no MIME type at all.
- The "content" scheme can only be matched by MIME type, because the original file name isn't available in the intent (at least with Gmail).
- The grouping of attributes in separate "data" elements is (almost) irrelevant to the interpretation, with the specific exception of host and port - which do pair together. Everything else has no specific association within a "data" element or between "data" elements.
- 请注意,过滤器中没有任何行为一致,这是一个特殊情况的迷宫,并将违反最小意外原则作为设计目标。没有任何模式匹配算法遵循相同的语法或行为。缺少字段有时是通配符,有时则不是。数据元素内的属性有时必须放在一起,有时会忽略分组。真的可以做得更好。
- 必须指定方案和主机才能匹配路径规则(目前与 Google 的 API 指南相反)。
- 至少 ES 文件资源管理器会生成 MIME 类型为“”的意图,其过滤方式与 null 非常不同,无法明确匹配,只能通过有风险的“*/*”过滤器匹配。
- "*/*" 过滤器不会匹配具有空 MIME 类型的 Intent - 这需要一个单独的过滤器用于这种特定情况,根本没有 MIME 类型。
- “内容”方案只能通过 MIME 类型匹配,因为原始文件名在意图中不可用(至少对于 Gmail)。
- 单独的“数据”元素中的属性分组(几乎)与解释无关,但主机和端口的特定例外 - 它们配对在一起。其他所有内容在“数据”元素内或“数据”元素之间没有特定关联。
With all this in mind, here's an example with comments:
考虑到所有这些,这里有一个带有注释的示例:
<!--
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>
回答by omahena
I must admit that the simple task of opening attachments from emails and files from the filesystem on Android has been one of the more maddening experiences ever. It is easy to handle too many files or too few. But getting it just right is hard. Most of the solutions posted on stackoverflow didn't work correctly for me.
我必须承认,在 Android 上打开电子邮件附件和文件系统中文件的简单任务是有史以来最令人抓狂的体验之一。处理过多或过少的文件都很容易。但是要做到恰到好处是很困难的。在 stackoverflow 上发布的大多数解决方案对我来说都不能正常工作。
My requirements were:
我的要求是:
- have my app handle attachments shared by my app
- have my app handle files on filestorage that were generated by my app and have a particular extension
- 让我的应用处理我的应用共享的附件
- 让我的应用程序处理文件存储上由我的应用程序生成并具有特定扩展名的文件
Probably the best way to go about this task is to specify a custom MIME Type for your attachments. And you will probably also choose to have a custom file extension. So let's say that our app is called "Cool App" and we generate file attachments that have ".cool" at the end.
完成此任务的最佳方法可能是为您的附件指定自定义 MIME 类型。您可能还会选择自定义文件扩展名。因此,假设我们的应用程序称为“Cool App”,并且我们生成以“.cool”结尾的文件附件。
This is the closest I got got to my goal and it works... satisfactory.
这是我离目标最近的一次,而且效果很好……令人满意。
<!-- 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>
Notes:
笔记:
- The
pathPattern
seems to be more or less ignored for attachments (when usingandroid:scheme="content"
). If somebody gets the pathPattern to respond only to certain patterns I would be thrilled to see how. - The Gmail app refused to list my app in the chooser if I added the
android:host="*"
attribute. - It probably still works if these
intent-filter
blocks are merged but I haven't verified this. - To handle requests from a browser when downloading a file the
android:scheme="http"
can be used. Note that certain browsers might mess up theandroid:mimeType
so experiment withandroid:mimeType="*/*"
and check in the debugger what is actually passed through and then tighten the filtering to not end up being that annoying app that handles everything. - Certain File Explorers will mess up the MIME-Types for your files as well. The above
intent-filter
was tested with the Samsung's "My Files" app on a Galaxy S3. The FX Explorer still refuses to properly open the file and I also noticed that the app icon is not used for the files. Again, if anyone gets that to work please comment below.
- 在
pathPattern
似乎或多或少地忽略了附件(使用时android:scheme="content"
)。如果有人让 pathPattern 只响应某些模式,我会很高兴看到如何。 - 如果我添加了该
android:host="*"
属性,Gmail 应用程序拒绝在选择器中列出我的应用程序。 - 如果
intent-filter
合并这些块,它可能仍然有效,但我还没有验证这一点。 - 要在下载文件时处理来自浏览器的请求,
android:scheme="http"
可以使用它。请注意,某些浏览器可能会搞乱android:mimeType
so 实验android:mimeType="*/*"
并在调试器中检查实际通过的内容,然后加强过滤,以免最终成为处理所有内容的烦人应用程序。 - 某些文件资源管理器也会弄乱文件的 MIME 类型。以上
intent-filter
是在 Galaxy S3 上使用三星的“我的文件”应用程序测试的。FX Explorer 仍然拒绝正确打开文件,我还注意到应用程序图标未用于文件。同样,如果有人让它工作,请在下面发表评论。
I hope you will find this useful and that you won't have to waste days going through all possible combinations. There is room for improvement so comments are welcome.
我希望您会发现这很有用,并且您不必浪费时间浏览所有可能的组合。有改进的余地,欢迎评论。
回答by Dawson
Brian's answer above got me 90% of the way there. To finish it off, for mime type I used
上面布赖恩的回答让我完成了 90% 的工作。为了完成它,对于我使用的 mime 类型
android:mimeType="*/*"
I suspect that previous posters have attempted to post the same detail, but the withough qoting the star slash star as code, stackoverflow diplays it as just a slash.
我怀疑以前的海报试图发布相同的细节,但是尽管将斜线星标为代码,但stackoverflow 将其显示为斜线。
回答by CommonsWare
Rather than android:path
, try android:mimeType
, with a value of the MIME type of this particular piece of content. Also, android:path
does not accept wildcards -- use android:pathPattern
for that.
而不是android:path
, try android:mimeType
,使用此特定内容的 MIME 类型的值。此外,android:path
不接受通配符 -android:pathPattern
用于该目的。
回答by PeeGee85
I've been trying to get this to work for ages and have tried basicly all the suggested solutions and still cannot get Android to recognise specific file extensions. I have an intent-filter with a "*/*"
mimetype which is the only thing that seems to work and file-browsers now list my app as an option for opening files, however my app is now shown as an option for opening ANY KIND of file even though I've specified specific file extensions using the pathPattern tag. This goes so far that even when I try to view/edit a contact in my contacts list Android asks me if I want to use my app to view the contact, and that is just one of many situations where this occurs, VERY VERY annoying.
我一直试图让它工作很长时间,并且基本上已经尝试了所有建议的解决方案,但仍然无法让 Android 识别特定的文件扩展名。我有一个带有"*/*"
mimetype的意图过滤器,它似乎是唯一可用的东西,文件浏览器现在将我的应用程序列为打开文件的选项,但是我的应用程序现在显示为打开任何类型文件的选项,即使我已经使用 pathPattern 标记指定了特定的文件扩展名。到目前为止,即使我尝试查看/编辑联系人列表中的联系人,Android 也会询问我是否要使用我的应用程序查看联系人,这只是发生这种情况的众多情况之一,非常非常烦人。
Eventually I found this google groups post with a similar question to which an actual Android framework engineer replied. She explains that android simply does not know anything about file-extensions, only MIME-types (https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0).
最终我找到了这个 google groups 的帖子,里面有一个类似的问题,一个实际的 Android 框架工程师回答了这个问题。她解释说 android 对文件扩展名一无所知,只知道 MIME 类型(https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0)。
So from what I've seen, tried and read, Android simply cannot distinguish between file-extensions and the pathPattern tag is basicly a gigantic waste of time and energy. If you are fortunate enough to only need files of a certain mime-type (say text, video or audio), you can use an intent-filter with a mime-type. If you need a specific file-extension or a mime-type not known by Android however then you're out of luck.
因此,从我所看到、尝试和阅读的情况来看,Android 根本无法区分文件扩展名,而 pathPattern 标签基本上是对时间和精力的巨大浪费。如果你足够幸运只需要某种 mime 类型的文件(比如文本、视频或音频),你可以使用带有 mime 类型的意图过滤器。但是,如果您需要特定的文件扩展名或 Android 不知道的 mime 类型,那么您就不走运了。
If I'm wrong about any of this please tell me, so far I've read every post and tried every proposed solution I could find but none have worked.
如果我对此有任何错误,请告诉我,到目前为止,我已经阅读了所有帖子并尝试了我能找到的所有建议解决方案,但都没有奏效。
I could write another page or two about how common these kinds of things seem to be in Android and how screwed up the developer experience is, but I'll save you my angry rantings ;). Hope I saved someone some trouble.
我可以再写一两页关于这类事情在 Android 中似乎有多普遍以及开发者体验是多么糟糕,但我会为你省去我愤怒的咆哮 ;)。希望我为某人省了一些麻烦。
回答by benjamin davis
I've been struggling with this quite a bit for a custom file extension, myself. After a lot of searching, I found this web pagewhere the poster discovered that Android's patternMatcher class (which is used for the pathPattern matching in Intent-Filters) has unexpected behavior when your path contains the first character of your match pattern elsewhere in the path (like if you're trying to match "*.xyz", the patternMatcher class stops if there's an "x" earlier in your path). Here's what he found for a workaround, and worked for me, although it is a bit of a hack:
我自己一直在为自定义文件扩展名而苦苦挣扎。经过大量搜索,我找到了这个网页,海报发现Android的patternMatcher类(用于Intent-Filters中的pathPattern匹配)当您的路径包含路径中其他位置的匹配模式的第一个字符时出现意外行为(就像如果你试图匹配“*.xyz”,如果你的路径前面有一个“x”,patternMatcher 类就会停止)。这是他找到的解决方法,并为我工作,尽管它有点黑客:
PatternMatcher is used for pathPattern at IntentFilter But, PatternMatcher's algorithm is quite strange to me. Here is algorithm of Android PatternMatcher.
If there is 'next character' of '.*' pattern in the middle of string, PatternMatcher stops loop at that point. (See PatternMatcher.java of Android framework.)
Ex. string : "this is a my attachment" pattern : ".att.". Android PatternMatcher enter loop to match '.' pattern until meet the next character of pattern (at this example, 'a') So, '.' matching loop stops at index 8 - 'a' between 'is' and 'my'. Therefore result of this match returns 'false'.
Quite strange, isn't it. To workaround this - actually reduce possibility - developer should use annoying stupid pathPattern.
Ex. Goal : Matching uri path which includes 'message'.
PatternMatcher 用于 IntentFilter 的 pathPattern 但是,PatternMatcher 的算法对我来说很奇怪。这是Android PatternMatcher的算法。
如果字符串中间有 '.*' 模式的 '下一个字符',PatternMatcher 在该点停止循环。(参见 Android 框架的 PatternMatcher.java。)
前任。字符串:“这是我的附件”模式:“. att.”。Android PatternMatcher 输入循环以匹配 '. ' 模式直到遇到模式的下一个字符(在这个例子中,'a')所以,'。' 匹配循环在索引 8 处停止 - 'is' 和 'my' 之间的 'a'。因此,此匹配的结果返回“false”。
很奇怪,不是吗。为了解决这个问题 - 实际上减少可能性 - 开发人员应该使用烦人的愚蠢 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>
This is especially issued when matching with custom file extention.
这在与自定义文件扩展名匹配时尤其会发出。
回答by Kon
Brian's answer is very close, but here's a clean and error-free way to have your app invoked when trying to open a file with your own custom extension (no need for scheme or host):
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>
回答by Glenn Widener
None of the above work properly, for VIEW or SEND actions, if the suffix is not registered with a MIME type in Android's system=wide MIME database. The only settings I've found that fire for the specified suffix include android:mimeType="*/*"
, but then the action fires for ALL files. Clearly NOT what you want!
对于 VIEW 或 SEND 操作,如果后缀未在 Android 的 system=wide MIME 数据库中使用 MIME 类型注册,则上述方法均无法正常工作。我发现对指定后缀触发的唯一设置包括android:mimeType="*/*"
,但随后对所有文件触发该操作。显然不是你想要的!
I can't find any proper solution without adding the mime and suffix to the Android mime database, so far, I haven't found a way to do that. If anyone knows, a pointer would be terrific.
如果不将 mime 和后缀添加到 Android mime 数据库中,我找不到任何合适的解决方案,到目前为止,我还没有找到一种方法来做到这一点。如果有人知道,一个指针会很棒。
回答by Martin
On Android 4 the rules became more strict then they used to be. Use:
在 Android 4 上,规则变得比以前更加严格。用:
<data
android:host=""
android:mimeType="*/*"
android:pathPattern=".*\.ext"
android:scheme="file"
></data>