102

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

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

但我无法让它发挥作用。

4

15 回答 15

125

这是我在 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>

schemeoffile表示这应该在打开本地文件时发生(而不是像 HTTP 这样的协议)。

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

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

最后,根据 Android 文档,hostscheme属性都是该pathPattern属性工作所必需的,因此只需将其设置为通配符即可匹配任何内容。

现在,如果您.kdb在 Linda File Manager 之类的应用程序中选择一个文件,我的应用程序就会显示为一个选项。我应该注意,仅此一项并不允许您在浏览器中下载此文件类型,因为这仅在文件方案中注册。在您的手机上拥有像 Linda File Manager 这样的应用程序本身通常允许您下载任何文件类型。

于 2010-01-14T04:15:34.023 回答
41

关于这个主题有很多错误信息,尤其是来自 Google 自己的文档。最好的,并且考虑到奇怪的逻辑,可能唯一真正的文档是源代码。

意图过滤器实现具有几乎无法描述的逻辑。解析器代码是另一个相关的难题。

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

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

我没有包括像"http"这里这样的其他方案,但它们可能在所有这些过滤器上都可以正常工作。

奇怪的方案是"content",其扩展对过滤器不可用。但只要提供商说明您的 MIME 类型(例如,Gmail 将不受阻碍地传递附件的 MIME 类型),过滤器就会匹配。

需要注意的问题:

  1. 请注意,过滤器中没有任何行为一致,这是一个特殊情况的迷宫,并将违反最小意外原则视为设计目标。没有一个模式匹配算法遵循相同的语法或行为。缺少字段有时是通配符,有时不是。数据元素中的属性有时必须放在一起,有时会忽略分组。它真的可以做得更好。
  2. 必须指定schemeAND才能匹配规则(目前与 Google 的 API 指南相反)。hostpath
  3. 至少 ES File Explorer 会生成 MIME 类型的 Intent "",其过滤方式与 非常不同null,无法显式匹配,只能通过有风险的"*/*"过滤器匹配。
  4. "*/*"过滤器不会匹配具有 MIME 类型的 Intent -null这需要针对这种特定情况使用单独的过滤器,而根本没有 MIME 类型。
  5. "content"方案只能通过 MIME 类型匹配,因为原始文件名在意图中不可用(至少在 Gmail 中)。
  6. 单独元素中的属性分组"data"(几乎)与解释无关,除了hostport- 的特定例外,它们确实配对在一起。"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>
于 2015-06-24T13:52:02.597 回答
27

我必须承认,在 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="*/*"并在调试器中检查实际通过的内容,然后收紧过滤,以免最终成为处理所有事情的烦人应用程序。
  • 某些文件资源管理器也会弄乱您文件的 MIME 类型。以上intent-filter是在 Galaxy S3 上使用三星的“我的文件”应用程序进行测试的。FX Explorer 仍然拒绝正确打开文件,我还注意到应用程序图标未用于文件。同样,如果有人让它工作,请在下面发表评论。

我希望您会发现这很有用,并且您不必浪费几天时间来研究所有可能的组合。有改进的余地,欢迎评论。

于 2014-10-15T22:12:03.343 回答
10

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

android:mimeType="*/*"

我怀疑以前的海报试图发布相同的细节,但是尽管引用了斜杠星作为代码,stackoverflow 将它显示为一个斜杠。

于 2011-05-23T23:26:30.290 回答
10

2020 年更新

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 中的特定扩展类型相关联。这是我在我的情况下能做的最好的事情。
于 2020-04-20T20:40:47.840 回答
9

而不是android:path, try android:mimeType, 具有此特定内容的 MIME 类型的值。此外,android:path不接受通配符 -android:pathPattern用于此目的。

于 2009-11-14T11:58:05.713 回答
8

我一直试图让它工作很长时间,并且基本上尝试了所有建议的解决方案,但仍然无法让 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 中的普遍性以及开发人员的体验是多么糟糕,但我会为你省去我愤怒的咆哮;)。希望我为某人节​​省了一些麻烦。

于 2014-10-29T15:36:26.447 回答
4

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

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

于 2013-01-20T18:25:28.700 回答
3

在 Android 4 上,规则变得比过去更加严格。利用:

    <data
      android:host=""
      android:mimeType="*/*"
      android:pathPattern=".*\\.ext"
      android:scheme="file"
    ></data>
于 2013-12-18T17:30:48.163 回答
3

我自己一直在为自定义文件扩展名而苦苦挣扎。经过大量搜索,我找到了这个网页,发帖人发现当您的路径包含路径中其他地方的匹配模式的第一个字符时,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>

与自定义文件扩展名匹配时尤其会发出此问题。

于 2014-04-25T20:32:31.930 回答
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>
于 2011-07-22T21:11:44.627 回答
2

当 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>
于 2018-09-18T10:18:56.807 回答
1

使用以下过滤器从浏览器、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>
于 2014-05-23T09:59:46.390 回答
1

如果您希望直接从 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 版本,数据过滤器必须写在一个语句中

于 2014-03-18T07:52:39.310 回答
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>

确保提供的扩展名没有“。” 在里面

于 2020-10-14T21:40:05.627 回答