Android意图filter的特定文件扩展名?
我希望能够从网上下载一个具有特定扩展名的文件,并将其传递给我的应用程序来处理它,但我一直无法弄清楚意图filter。 文件types不包含在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>
file
的scheme
表明,这应该发生在打开本地文件(而不是HTTP等协议)时。
可以将mimeType
设置为\*/\*
来匹配任何MIMEtypes。
pathPattern
是指定要匹配的扩展名(在本例中为.kdb
)的位置。 .*
开始时匹配任何string。 这些string需要双重转义,所以\\\\.
匹配一个文字周期。 然后,你以文件扩展名结束。 一个与pathPattern的警告是.*
不是像你所期望的贪婪的比赛,如果这是一个正则expression式。 这种模式将无法匹配包含a的path.
在.kdb
之前。 有关此问题的更详细的讨论和解决方法,请参阅此处
最后,根据Android文档, pathPattern
属性需要host
和scheme
属性才能工作,所以只需将其设置为通配符即可匹配任何内容。
现在,如果您在诸如Linda文件pipe理器等应用程序中select.kdb
文件,我的应用程序将显示为一个选项。 我应该注意到,这本身不允许你在浏览器中下载这个文件types,因为这只能在文件模式下注册。 像手机上的琳达文件pipe理器的应用程序抵制自己一般允许您下载任何文件types。
我必须承认,从Android上的文件系统中打开电子邮件和文件附件的简单任务是有史以来最疯狂的经历之一。 处理太多文件很容易,或者太less。 但要做到这一点很困难。 发布在stackoverflow上的大部分解决scheme对我来说都不正确。
我的要求是:
- 让我的应用程序处理由我的应用程序共享的附件
- 让我的应用程序处理由我的应用程序生成的具有特定扩展名的filestorage上的文件
可能最好的方法是为您的附件指定一个自定义的MIMEtypes。 你也可能会select自定义文件扩展名。 因此,让我们说我们的应用程序被称为“酷应用程序”,我们生成的文件附件有“.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
似乎或多或less被忽略了附件(当使用android:scheme="content"
)。 如果有人得到pathPattern只响应某些模式,我会很高兴看到如何。 - 如果我添加了
android:host="*"
属性,Gmail应用程序拒绝在select器中列出我的应用程序。 - 如果这些
intent-filter
块被合并,这可能仍然有效,但我没有证实这一点。 - 在下载文件时,为了处理来自浏览器的请求,可以使用
android:scheme="http"
。 请注意,某些浏览器可能会搞乱android:mimeType
所以android:mimeType="*/*"
然后在debugging器中检查实际传递的内容,然后收紧筛选,最终不会成为处理所有事情的恼人的应用程序。 - 某些文件探索器也会混淆您的文件的MIMEtypes。 上面的
intent-filter
在Galaxy S3上用三星的“我的文件”应用程序进行了testing。 FX浏览器仍然拒绝正确打开文件,我也注意到应用程序图标不用于这些文件。 再次,如果有人得到这个工作,请在下面评论。
我希望你会发现这个有用的,你不会浪费天,经历所有可能的组合。 有改进的余地,所以欢迎评论。
关于这个话题有很多误导,特别是来自Google自己的文档。 最好的,并给出了奇怪的逻辑,可能唯一真正的文档是源代码。
意图filter实现具有几乎违背描述的逻辑。 parsing器代码是拼图的另一个相关部分。
下面的filter非常接近合理的行为。 path模式确实适用于“文件”scheme意图。
只要文件扩展名匹配,全局MIMEtypes模式匹配将匹配所有types。 这不是完美的,但是是匹配文件pipe理器(如ES文件资源pipe理器)的行为的唯一方法,并且它仅限于URI /文件扩展名匹配的意图。
我没有在这里包含像“http”这样的其他scheme,但他们可能会在所有这些filter上正常工作。
奇怪的scheme是“内容”,为此filter不能使用扩展名。 但只要提供者声明您的MIMEtypes(例如,Gmail将传递MIMEtypes以使附件畅通无阻),筛选器就会匹配。
需要注意的是:
- 请注意,在filter中没有任何行为一致,这是一个特殊情况的迷宫,并将违反最小惊喜原则作为devise目标。 没有一种模式匹配algorithm遵循相同的语法或行为。 缺less一个领域有时是一个通配符,有时不是。 数据元素中的属性有时必须放在一起,有时会忽略分组。 这真的可以做得更好。
- 该scheme和主机必须指定path规则来匹配(目前与Google的API指南相反)。
- 至lessES文件资源pipe理器会生成MIMEtypes为“”的意图,这种意图过滤的方式与null非常不同,不可能显式匹配,只能由具有风险的“* / *”filter进行匹配。
- “* / *”filter不会与空MIMEtypes的Intents相匹配 – 这个过程对于这个特定的情况需要一个单独的filter,根本没有MIMEtypes。
- “内容”scheme只能与MIMEtypes匹配,因为原始文件名在意图中不可用(至less在Gmail中)。
- 单独的“数据”元素中的属性的分组(几乎)与解释无关,除了主机和端口之外,它们可以配对在一起。 其他所有内容在“数据”元素或“数据”元素之间没有特定的关联。
考虑到这一切,这里有一个评论的例子:
<!-- 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>
上面的答案让我有90%的方式在那里。 为了完成它,我使用的MIMEtypes
android:mimeType="*/*"
我怀疑之前的海报曾经试图发表过相同的细节,但是把星星斜杠作为代码来填充,stackoverflow就把它当作斜线。
而不是android:path
,请尝试使用android:mimeType
,并使用此特定内容的MIMEtypes的值。 此外, android:path
不接受通配符 – 使用android:pathPattern
。
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>
在Android 4上,规则变得越来越严格了。 使用:
<data android:host="" android:mimeType="*/*" android:pathPattern=".*\\.ext" android:scheme="file" ></data>
如果后缀未在Android的system = wide MIME数据库中使用MIMEtypes进行注册,那么以上都无法正确执行VIEW或SEND操作。 唯一的设置,我发现指定的后缀的火灾包括android:mimeType="*/*"
,但然后行动触发所有文件。 显然不是你想要的!
我找不到任何适当的解决scheme,而没有添加MIME数据库的MIME和后缀,到目前为止,我还没有find一种方法来做到这一点。 如果有人知道,一个指针会很棒。
如果你想直接从Gmail,Dropbox或任何buildin安卓文件工具打开文件,然后使用下面的代码(删除'android:host =“*”',使文件无法访问的Gmail):
<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>
数据filter必须按照Android版本4.x以一个语句编写
我自己一直在为自定义文件扩展而苦苦挣扎。 经过大量的search之后,我发现这张海报发现Android的patternMatcher类(用于Intent-Filters中的PathPattern匹配)在path中包含path中其他位置的匹配模式的第一个字符时会出现意想不到的行为(比如如果你想匹配“* .xyz”,patternMatcher类会停止,如果你的path中有一个“x”的话)。 这是他find的解决办法,并为我工作,虽然这是一个黑客:
PatternMatcher用于IntentFilter的pathPattern但PatternMatcher的algorithm对我来说很奇怪。 这是Android PatternMatcher的algorithm。
如果在string中间有'。*'模式的'下一个字符',PatternMatcher停止循环。 (请参阅Android框架的PatternMatcher.java。)
防爆。 string:“这是我的附件”模式:“。 att。 ” Android PatternMatcherinput循环来匹配'。 '模式,直到遇到模式的下一个字符(在这个例子中,'a')。 '匹配循环在索引8处停止 – '是'和'我'之间的'a'。 所以这个匹配的结果返回'false'。
很奇怪,不是。 要解决这个问题 – 实际上减less了可能性 – 开发人员应该使用恼人的愚蠢pathPattern。
防爆。 目标:匹配包含“消息”的uripath。
<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>
当与自定义文件扩展匹配时,这是特别发行的。
使用下面的filter从浏览器,Gmail和文件浏览器(testing)打开。 注:请不要合并两个filter,这将使浏览器忽略您的应用程序(testing)。
<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>
我一直试图让这个工作很长时间,并基本上尝试了所有build议的解决scheme,仍然无法让Android识别特定的文件扩展名。 我有一个"*/*"
mimetype的意图filter是唯一的似乎工作和文件浏览器现在列出我的应用程序作为打开文件的选项,但我的应用程序现在显示为一个选项打开任何即使我已经使用pathPattern标签指定了特定的文件扩展名,文件的种类也是如此。 这到目前为止,即使当我尝试查看/编辑我的联系人列表中的联系人Android问我是否要使用我的应用程序来查看联系人,这只是这种情况发生的许多情况之一,非常非常讨厌。
最终,我发现这个谷歌小组发布了一个类似的问题,一个实际的Android框架工程师回答。 她解释说,android根本不知道任何有关文件扩展名的内容,只知道MIMEtypes( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 )。
所以从我所看到的,尝试和阅读,Android根本无法区分文件扩展名和pathPattern标记基本上是一个巨大的浪费时间和精力。 如果您有幸只需要某种特定MIMEtypes的文件(如文本,video或audio),则可以使用MIMEtypes的意向filter。 如果你需要一个特定的文件扩展名或Android不知道的MIMEtypes然后你运气不好。
如果我对这个问题有任何疑问,请告诉我,到目前为止,我已经阅读了每篇文章,并尝试了所有可以find的解决scheme,但都没有成功。
我可以再写一两页关于这些东西在Android中的普遍程度,以及开发者的经验是如何搞砸的,但是我会为你省去愤怒的咆哮。 希望我救了一些麻烦。