Android意图过滤器:将app与文件扩展名相关联

时间:2010-09-21 12:32:05

标签: android android-manifest intentfilter

我有一个自定义文件类型/扩展名,我想将我的应用与。

相关联

据我所知,数据元素是为此目的而制作的,但我无法使其正常工作。 http://developer.android.com/guide/topics/manifest/data-element.html 根据文档和很多论坛帖子,它应该像这样工作:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:mimeType="application/pdf" />
</intent-filter>

嗯,它不起作用。我做错了什么?我只想声明自己的文件类型。

17 个答案:

答案 0 :(得分:111)

您需要多个意图过滤器来解决您想要处理的不同情况。

示例1,处理没有mimetypes的http请求:

  <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="http" />
    <data android:host="*" />
    <data android:pathPattern=".*\\.pdf" />
  </intent-filter>

使用mimetypes处理,后缀无关紧要:

  <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="http" />
    <data android:host="*" />
    <data android:mimeType="application/pdf" />
  </intent-filter>

处理文件浏览器应用程序的意图:

  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="file" />
    <data android:host="*" />
    <data android:pathPattern=".*\\.pdf" />
  </intent-filter>

答案 1 :(得分:46)

在我添加之前,其他解决方案对我来说无法可靠地工作:

android:mimeType="*/*" 

之前它在某些应用程序中有效,有些则不...

完整的解决方案:

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <data android:scheme="file"  android:host="*" android:pathPattern=".*\\.EXT" android:mimeType="*/*"  />
</intent-filter>

答案 2 :(得分:19)

Phyrum Teayuku给出的回复已经非常有用。

我想补充一点,从 Android 7.0 Nougat 开始,处理应用之间文件共享的方式发生了变化:

来自官方Android 7.0 Changes

  

对于定位Android 7.0的应用,Android框架强制实施   禁止在外部公开file:// URI的StrictMode API策略   你的应用。如果包含文件URI的意图离开了您的应用程序,该应用程序   因FileUriExposedException异常而失败。

     

要在应用程序之间共享文件,您应该发送content:// URI   并授予URI临时访问权限。最简单的方法   通过使用FileProvider类授予此权限。更多   有关权限和共享文件的信息,请参阅共享文件。

如果您自己的自定义文件没有特定的mime-type结束(或者我猜即使有一个),您可能需要向scheme添加第二个intent-filter值才能生成也可以使用FileProviders

示例:

<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: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:host="*" />
    <data android:pathPattern=".*\\.sfx" />
    <data android:pathPattern=".*\\..*\\.sfx" />
    <data android:pathPattern=".*\\..*\\..*\\.sfx" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.sfx" />
    <!-- keep going if you need more -->

</intent-filter>

这里重要的是增加了

<data android:scheme="content" />

过滤器。

我很难发现这个小小的变化让我的活动在Android 7.0设备上打开,而旧版本的一切都很好。我希望它有所帮助。

答案 3 :(得分:18)

我的发现:

您需要多个过滤器来处理检索文件的不同方法。即,通过gmail附件,通过文件浏览器,通过HTTP,通过FTP ... 他们都发出了非常不同的意图。

您需要过滤掉在您的活动代码中触发活动的意图。

对于下面的示例,我创建了一个假文件类型new.mrz。我从gmail附件和文件资源管理器中检索它。

onCreate()中添加的活动代码:

        Intent intent = getIntent();
        String action = intent.getAction();

        if (action.compareTo(Intent.ACTION_VIEW) == 0) {
            String scheme = intent.getScheme();
            ContentResolver resolver = getContentResolver();

            if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0) {
                Uri uri = intent.getData();
                String name = getContentName(resolver, uri);

                Log.v("tag" , "Content intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name);
                InputStream input = resolver.openInputStream(uri);
                String importfilepath = "/sdcard/My Documents/" + name; 
                InputStreamToFile(input, importfilepath);
            }
            else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0) {
                Uri uri = intent.getData();
                String name = uri.getLastPathSegment();

                Log.v("tag" , "File intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name);
                InputStream input = resolver.openInputStream(uri);
                String importfilepath = "/sdcard/My Documents/" + name; 
                InputStreamToFile(input, importfilepath);
            }
            else if (scheme.compareTo("http") == 0) {
                // TODO Import from HTTP!
            }
            else if (scheme.compareTo("ftp") == 0) {
                // TODO Import from FTP!
            }
        }

Gmail附件过滤器:

        <intent-filter android:label="@string/app_name">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="content" />
            <data android:mimeType="application/octet-stream" />
        </intent-filter>
  • 日志:检测到内容意图:android.intent.action.VIEW:content://gmail-ls/l.foul@gmail.com/messages/2950/attachments/0.1/BEST/false:application / octet-stream :new.mrz

文件资源管理器过滤器:

        <intent-filter android:label="@string/app_name">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="file" />
            <data android:pathPattern=".*\\.mrz" />
        </intent-filter>
  • 日志:检测到文件意图:android.intent.action.VIEW:file:///storage/sdcard0/My%20Documents/new.mrz:null:new.mrz

HTTP过滤器:

        <intent-filter android:label="@string/rbook_viewer">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="http" />
            <data android:pathPattern=".*\\.mrz" />
        </intent-filter>

上面使用的私人功能:

private String getContentName(ContentResolver resolver, Uri uri){
    Cursor cursor = resolver.query(uri, null, null, null, null);
    cursor.moveToFirst();
    int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
    if (nameIndex >= 0) {
        return cursor.getString(nameIndex);
    } else {
        return null;
    }
}

private void InputStreamToFile(InputStream in, String file) {
    try {
        OutputStream out = new FileOutputStream(new File(file));

        int size = 0;
        byte[] buffer = new byte[1024];

        while ((size = in.read(buffer)) != -1) {
            out.write(buffer, 0, size);
        }

        out.close();
    }
    catch (Exception e) {
        Log.e("MainActivity", "InputStreamToFile exception: " + e.getMessage());
    }
}

答案 4 :(得分:15)

pathPattern

<data android:pathPattern=".*\\.pdf" />
如果文件路径在“.pdf”之前包含一个或多个点,则

不起作用。

这将有效:

<data android:pathPattern=".*\\.pdf" />
<data android:pathPattern=".*\\..*\\.pdf" />
<data android:pathPattern=".*\\..*\\..*\\.pdf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" />

如果您想支持更多点,请添加更多。

答案 5 :(得分:4)

Markus Ressel是对的。 Android 7.0 Nougat不再允许使用文件URI在应用程序之间共享文件。必须使用内容URI。但是,内容URI不允许共享文件路径,只允许共享mime类型。因此,您无法使用内容URI将您的应用与自己的文件扩展名相关联。

Drobpox在Android 7.0上有一个有趣的行为。当它遇到未知的文件扩展名时,它似乎形成了文件URI意图,但它没有启动意图,而是调用操作系统来找出哪些应用程序可以接受意图。如果只有一个应用程序可以接受该文件URI,则它会直接向该应用程序发送显式内容URI。因此,要使用Dropbox,您无需更改应用中的intent过滤器。它不需要内容URI意图过滤器。只需确保该应用可以接收内容URI,您的应用程序将使用自己的文件扩展名,就像在Android 7.0之前一样使用Dropbox。

以下是我的文件加载代码被修改为接受内容URI的示例:

Uri uri = getIntent().getData();
if (uri != null) {
    File myFile = null;
    String scheme = uri.getScheme();
    if (scheme.equals("file")) {
        String fileName = uri.getEncodedPath();
        myFile = new File(filename);
    }
    else if (!scheme.equals("content")) {
        //error
        return;
    }
    try {
        InputStream inStream;
        if (myFile != null) inStream = new FileInputStream(myFile);
        else inStream = getContentResolver().openInputStream(uri);
        InputStreamReader rdr = new InputStreamReader(inStream);
        ...
    }
}

答案 6 :(得分:3)

我一直试图让这个工作多年,并且基本上尝试了所有建议的解决方案,仍然无法让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中的常见程度,以及开发者体验如何搞砸了,但我会拯救你愤怒的咆哮;)。希望我救了别人一些麻烦。

答案 7 :(得分:2)

尝试添加

<action android:name="android.intent.action.VIEW"/>

答案 8 :(得分:1)

对于Gmail附件,您可以使用:

<intent-filter android:label="@string/app_name">
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <data android:scheme="content" />
  <data android:mimeType="application/pdf" /> <!-- .pdf -->
  <data android:mimeType="application/msword" /> <!-- .doc / .dot -->
  <data android:mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" /> <!-- .docx -->
  <data android:mimeType="application/vnd.ms-excel" />  <!-- .xls / .xlt / .xla -->
  <data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />  <!-- .xlsx -->
  <data android:mimeType="application/vnd.ms-powerpoint" />  <!-- .ppt / .pps / .pot / .ppa -->
  <data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" /> <!-- .pptx -->
  <data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" /> <!-- .ppsx -->
  <data android:mimeType="application/zip" /> <!-- .zip -->
  <data android:mimeType="image/jpeg" /> <!-- .jpeg -->
  <data android:mimeType="image/png" /> <!-- .png -->
  <data android:mimeType="image/gif" /> <!-- .gif -->
  <data android:mimeType="text/plain" /> <!-- .txt / .text / .log / .c / .c++ / ... -->

根据需要添加任意数量的mime类型。我只需要那些项目。

答案 9 :(得分:1)

         <!--
            Works for Files, Drive and DropBox
        -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="file" />
            <data android:mimeType="*/*" />
            <data android:host="*" />
            <data android:pathPattern=".*\\.teamz" />
        </intent-filter>

        <!--
            Works for 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:host="gmail-ls" android:scheme="content" android:mimeType="application/octet-stream"/>
        </intent-filter>

请注意,这会让你的应用打开所有gmail文件附件,没有办法解决它

答案 10 :(得分:1)

那些与其他文件管理器\资源管理器应用程序有问题的人,如@yuku和@ phyrum-tea已回答

这适用于LG默认文件管理器应用

     <intent-filter android:label="@string/app_name_decrypt">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="file" />
            <data android:pathPattern=".*\\.lock" />
            <data android:pathPattern=".*\\..*\\.lock" />
            <data android:pathPattern=".*\\..*\\..*\\.lock" />
        </intent-filter>

但无法使用ES文件资源管理器和其他文件管理器,所以我添加了

 android:mimeType="*/*"

然后它适用于ES Explorer,但LG文件管理器无法检测文件类型,因此我的解决方案是

     <intent-filter android:label="@string/app_name_decrypt">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="file" />
            <data android:pathPattern=".*\\.lock" />
            <data android:pathPattern=".*\\..*\\.lock" />
            <data android:pathPattern=".*\\..*\\..*\\.lock" />
        </intent-filter>
        <intent-filter android:label="@string/app_name_decrypt">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="file"/>
            <data android:scheme="content" />
            <data android:mimeType="*/*" />
            <data android:pathPattern=".*\\.lock" />
            <data android:pathPattern=".*\\..*\\.lock" />
            <data android:pathPattern=".*\\..*\\..*\\.lock" />
        </intent-filter>

答案 11 :(得分:1)

您可以尝试使用此扩展名。除了pdf之外,您还可以使用其他扩展名。 首先,您必须在 androidmanifest.xml 文件中添加读取外部存储权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

然后在Activity标签的 androidmanifest 文件中,添加如下所示的意图过滤器。     

            <action android:name="android.intent.action.SEND" />

            <action android:name="android.intent.action.VIEW" />

             <category android:name="android.intent.category.DEFAULT" />

            <data android:mimeType= "application/pdf" />

            <data android:host="*" />

        </intent-filter>

最后,在代码中,您将获得pdf文件的路径,如下所示:

Intent intent=getIntent();

if(intent!=null) {          

        String action=intent.getAction();

        String type=intent.getType();

        if(Intent.ACTION_VIEW.equals(action) && type.endsWith("pdf")) {

            // Get the file from the intent object

            Uri file_uri=intent.getData();

            if(file_uri!=null)

                filepath=file_uri.getPath();

            else

                filepath="No file";

        }

        else if(Intent.ACTION_SEND.equals(action) && type.endsWith("pdf")){

            Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);

            filepath = uri.getPath();

        }

答案 12 :(得分:0)

内容URI ftw,以及清单中的intent过滤器...如果您的文件具有自定义扩展名.xyz,请添加匹配的mime类型:

        <intent-filter>
            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.DEFAULT" />

            <data
                android:host="*"
                android:mimeType="application/xyz"
                android:scheme="content" />
        </intent-filter>

某些应用程序(如电子邮件)似乎将扩展程序转换为mime类型。现在我可以点击电子邮件中的附件,并在我的应用程序中打开它。

答案 13 :(得分:0)

//我已经尝试过此代码。而且运作良好。您可以使用此代码接受pdf文件。

<intent-filter>
   <action android:name="android.intent.action.SEND" />
   <category android:name="android.intent.category.DEFAULT" />
   <data android:mimeType="application/pdf" />
   <data android:pathPattern=".*\\.pdf" />
   <data android:pathPattern=".*\\..*\\.pdf" />
   <data android:pathPattern=".*\\..*\\..*\\.pdf" />
   <data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" />
</intent-filter>

答案 14 :(得分:0)

在kotlin中读取打开文件:

InputStream

答案 15 :(得分:0)

以上解决方案都不适合我,我必须将所有解决方案结合起来才能像这样工作:

            <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="http"/>
            <data android:host="*"/>
            <data android:pathPattern=".*\\.pdf"/>
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="content"/>
            <data android:scheme="file"/>
            <data android:mimeType="application/pdf"/>
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="content"/>
            <data android:scheme="file"/>
            <data android:host="*"/>
            <data android:pathPattern=".*\\.pdf"/>
        </intent-filter>

答案 16 :(得分:-1)

将此意图过滤器放入要打开的清单文件中的活动标签内:

<intent-filter android:priority="999">
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.OPENABLE" />

    <data android:host="*" />
    <data android:mimeType="application/octet-stream" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\..*\\.yourextension" />
    <data android:pathPattern=".*\\.yourextension" />
    <data android:scheme="content" />
</intent-filter>