针对特定文件扩展名的Android意图过滤器?

时间:2009-11-14 03:55:26

标签: android android-intent android-manifest

我希望能够从'net下载具有特定扩展名的文件,并将其传递给我的应用程序来处理它,但我无法弄清楚intent过滤器。文件类型不包含在mimetypes中,我尝试使用

<data android:path="*.ext" />

但我无法让它发挥作用。

15 个答案:

答案 0 :(得分:114)

以下是我在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的{​​{1}}表示在打开本地文件时会发生这种情况(而不是像HTTP这样的协议)。

file可以设置为mimeType以匹配任何mime类型。

\*/\*用于指定要匹配的扩展名(在此示例中为pathPattern)。开头的.kdb匹配任何字符序列。这些字符串需要双重转义,因此.*与文字句点匹配。然后,您以文件扩展名结束。使用pathPattern的一个警告是\\\\.不是一个贪婪的匹配,如果这是一个正则表达式,你会期望。此模式无法匹配.*之前包含.的路径。有关此问题和解决方法的更详细讨论,请参阅here

最后,根据Android文档,.kdb属性需要hostscheme属性,因此只需将其设置为通配符以匹配任何内容。

现在,如果您在像Linda文件管理器这样的应用中选择pathPattern文件,我的应用就会显示为一个选项。我应该注意,仅此一项不允许您在浏览器中下载此文件类型,因为它只注册文件方案。像手机上的Linda文件管理器这样的应用程序可以自行恢复,允许您下载任何文件类型。

答案 1 :(得分:24)

关于这个话题存在很多错误信息,尤其是谷歌自己的文档。最好的,鉴于奇怪的逻辑,可能唯一真正的文档是源代码。

intent filter implementation的逻辑几乎无法描述。 parser code是这个难题的另一个相关部分。

以下过滤器非常接近合理的行为。对于“文件”方案意图,路径模式确实适用。

只要文件扩展名匹配,全局mime类型模式匹配将匹配所有类型。这并不完美,但它是匹配ES文件资源管理器等文件管理器行为的唯一方法,并且仅限于URI /文件扩展名匹配的意图。

我没有在这里添加其他方案,例如“http”,但它们可能在所有这些过滤器上都能正常工作。

奇数计划输出是“内容”,扩展名不适用于过滤器。但只要提供商声明您的MIME类型(例如,Gmail将无阻碍地传递附件的MIME类型),过滤器就会匹配。

要注意:

  1. 请注意,过滤器中没有任何表现一致,这是一个典型案例的迷宫,并将违反最小意外原则的行为视为设计目标。所有模式匹配算法都不遵循相同的语法或行为。缺少某个领域有时是一个通配符,有时则不是。数据元素中的属性有时必须结合在一起,有时会忽略分组。它真的可以做得更好。
  2. 必须为要匹配的路径规则指定方案和主机(目前与Google的API指南相反)。
  3. 至少ES文件资源管理器生成MIME类型为“”的意图,其过滤方式与null完全不同,无法明确匹配,只能与风险“* / *”过滤器匹配。
  4. “* / *”过滤器不会与具有空MIME类型的Intent匹配 - 这需要针对此特定情况使用单独的过滤器,而根本不需要MIME类型。
  5. “内容”方案只能与MIME类型匹配,因为原始文件名在intent中不可用(至少使用Gmail)。
  6. 单独的“数据”元素中的属性分组(几乎)与解释无关,除了主机和端口之外 - 它们组合在一起。其他所有内容在“数据”元素或“数据”元素之间没有特定的关联。
  7. 考虑到所有这些,这是一个带注释的例子:

    <!--
         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>
    

答案 2 :(得分:23)

我必须承认,从Android上的文件系统打开电子邮件和文件附件的简单任务一直是令人抓狂的经历之一。处理太多文件或太少文件很容易。但要做到恰到好处是很难的。 stackoverflow上发布的大多数解决方案对我来说都没有正常工作。

我的要求是:

  • 让我的应用处理我应用分享的附件
  • 让我的应用程序处理由我的应用程序生成并具有特定扩展名的文件存储上的文件

执行此任务的最佳方法可能是为附件指定自定义MIME类型。您可能还会选择自定义文件扩展名。所以,让我们说我们的应用程序被称为#34; Cool App&#34;我们生成的文件附件包含&#34; .cool&#34;最后。

这是我达到目标的最接近的目标,并且有效......令人满意。

<!-- 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="*/*"进行实验并检查调试器实际传递的内容,然后收紧过滤以最终成为处理一切的烦人应用程序即可。
  • 某些文件浏览器也会破坏文件的MIME类型。上面的intent-filter已经过三星&#34;我的文件&#34;银河S3上的应用程序。 FX Explorer仍然拒绝正确打开文件,我也注意到应用程序图标不用于文件。再说一遍,如果有人上网,请在下面发表评论。

我希望你会发现这很有用,并且你不必浪费时间来完成所有可能的组合。还有改进的余地,欢迎提出意见。

答案 3 :(得分:10)

布莱恩上面的回答让我90%的回答。为了完成它,对于我使用的mime类型

android:mimeType="*/*"

我怀疑之前的海报曾试图发布相同的细节,但是很快就将星形斜线作为代码,stackoverflow将其作为斜线显示。

答案 4 :(得分:8)

而不是android:path,尝试android:mimeType,使用此特定内容的MIME类型的值。另外,android:path不接受通配符 - 请使用android:pathPattern

答案 5 :(得分:4)

我一直试图让这个工作多年,并且基本上尝试了所有建议的解决方案,仍然无法让Android识别特定的文件扩展名。我有一个带有"*/*" mimetype的intent-filter,这是唯一可行的,文件浏览器现在列出我的应用程序作为打开文件的选项,但是我的应用程序现在显示为打开ANY的选项即使我使用pathPattern标记指定了特定的文件扩展名,也要保存文件。到目前为止,即使我尝试在我的联系人列表中查看/编辑联系人,Android也会询问我是否要使用我的应用程序查看联系人,这只是发生这种情况的众多情况之一,非常烦人。

最终我发现这个谷歌群组发布了一个类似的问题,实际的Android框架工程师回答了这个问题。她解释说,android根本不知道文件扩展,只有MIME类型(https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0)。

因此,从我所看到的,尝试和阅读,Android根本无法区分文件扩展名和pathPattern标签基本上是一个巨大的浪费时间和精力。如果您有幸只需要某个mime类型的文件(比如文本,视频或音频),则可以使用具有mime类型的intent-filter。如果您需要特定的文件扩展名或Android不知道的mime类型,那么您就不幸了。

如果我对此有任何不妥之处请告诉我,到目前为止,我已阅读过每篇文章,并尝试了我能找到的所有解决方案,但没有一个有效。

我可以写另外一两页关于这些东西在Android中的常见程度,以及开发者体验如何搞砸了,但我会拯救你愤怒的咆哮;)。希望我救了别人一些麻烦。

答案 6 :(得分:4)

更新2020

Android已转向用于意图过滤器的内容URI和MIME类型。

问题

内容URI不一定必须包含文件的扩展名或名称,并且在提供内容/文件的不同应用程序中它会有所不同。

以下是来自相同电子邮件附件的不同电子邮件应用程序的一些示例内容URI:

Gmail-> 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

Outlook-> 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和Samsung Email使用的MIME类型,并将它们添加到我的意图过滤器中。

注意事项/陷阱

  • 我发现,使用上述解决方案,如果打开任何二进制类型的文件,它将自动启动我的应用程序。如果无法解析文件,我会在活动中显示失败状态来处理此问题。我认为这是非常罕见的事件,因此可以接受。

  • 在找不到将<data android:mimeType="*/*"/>添加到我的意图过滤器的情况下,我找不到通过文件浏览器启动我的应用程序的任何方法。我无法使用它,因为只要用户单击手机上的任何文件(不仅是自定义文件扩展名的文件),它就会启动我的应用程序。我不建议将其添加到您的意图过滤器中。

最终思想

  • 目前尚无优雅的解决方案来将您的应用与Android中的特定扩展名类型相关联。这是我所能做的最好的事情。

答案 7 :(得分:3)

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>

答案 8 :(得分:3)

如果在Android的system = wide MIME数据库中未使用MIME类型注册后缀,则对于VIEW或SEND操作,上述任何一项都无法正常工作。我发现指定后缀的唯一设置包括android:mimeType="*/*",但随后该操作将触发所有文件。显然不是你想要的!

如果没有将mime和后缀添加到Android mime数据库中,我找不到任何正确的解决方案,到目前为止,我还没有找到办法做到这一点。如果有人知道,指针就会很棒。

答案 9 :(得分:3)

在Android 4上,规则变得比以前更严格了。使用:

    <data
      android:host=""
      android:mimeType="*/*"
      android:pathPattern=".*\\.ext"
      android:scheme="file"
    ></data>

答案 10 :(得分:3)

我自己一直在为自定义文件扩展而苦苦挣扎。经过大量搜索后,我发现this web page海报发现Android的patternMatcher类(用于Intent-Filters中的pathPattern匹配)在您的路径包含其他位置的匹配模式的第一个字符时会出现意外行为路径(就像你试图匹配“* .xyz”一样,如果你的路径中有一个“x”,则patternMatcher类会停止)。这是他找到的解决方法,并为我工作,虽然它有点像黑客:

  

PatternMatcher用于IntentFilter的pathPattern但是,   PatternMatcher的算法对我来说很奇怪。这是算法   Android PatternMatcher。

     

如果字符串中间有“。*”模式的“下一个字符”,   PatternMatcher在该点停止循环。 (参见PatternMatcher.java   Android框架。)

     

实施例。 string:“这是我的附件”模式:“。 att。”。 Android的   PatternMatcher进入循环以匹配'。'模式,直到遇到下一个   模式的特征(在这个例子中,'a')所以,'。'匹配循环   停在索引8 - '是'和'我'之间的'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>
  

在与自定义文件扩展名匹配时特别发布。

答案 11 :(得分:2)

意图满足intent-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=""><data $type=>匹配,则定义多个Intent元素会选中$ type框。

忽略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>

答案 12 :(得分:1)

如果您希望直接从Gmail,Dropbox或任何buildin android文件工具打开文件,请使用以下代码(删除&#39; android:host =&#34; *&#34;& #39;使文件无法访问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>

根据Android版本4.x

,数据过滤器必须写在一个语句中

答案 13 :(得分:1)

使用以下过滤器从浏览器打开,gmail&amp;文件浏览器(已测试)。 注意:请不要合并两个过滤器,这将使浏览器忽略您的应用程序(已测试)。

        <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>

答案 14 :(得分:0)

阅读此 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>

确保提供的扩展名不带“。”在其中