Android intent filter: associate app with file extension

后端 未结 16 1689
北海茫月
北海茫月 2020-11-22 11:06

I have a custom file type/extension that I want to associate my app with.

As far as I know, the data element is made for this purpose, but I can\'t get it working. h

相关标签:
16条回答
  • 2020-11-22 11:36

    The answeres given by Phyrum Tea and yuku are very informative already.

    I want to add that starting with Android 7.0 Nougat there is a change to the way file sharing between apps is handled:

    From official Android 7.0 Changes:

    For apps targeting Android 7.0, the Android framework enforces the StrictMode API policy that prohibits exposing file:// URIs outside your app. If an intent containing a file URI leaves your app, the app fails with a FileUriExposedException exception.

    To share files between applications, you should send a content:// URI and grant a temporary access permission on the URI. The easiest way to grant this permission is by using the FileProvider class. For more information on permissions and sharing files, see Sharing Files.

    If you have your own custom file ending without a specific mime-type (or i guess even with one) you may have to add a second scheme value to your intent-filter to make it work with FileProviders too.

    Example:

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

    The important thing here is the addition of

    <data android:scheme="content" />
    

    to the filter.

    I had a hard time finding out about this little change which kept my activity from opening on Android 7.0 devices while everything was fine on older versions. I hope it helps someone.

    0 讨论(0)
  • 2020-11-22 11:39

    Try adding

    <action android:name="android.intent.action.VIEW"/>
    
    0 讨论(0)
  • 2020-11-22 11:42
             <!--
                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>
    

    Notice that this will get your app open all gmail file attachments, there is no way to work around it

    0 讨论(0)
  • 2020-11-22 11:45

    Put this intent filter inside the activity tag in manifest you'd like to open touching the file:

    <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>
    
    0 讨论(0)
  • 2020-11-22 11:46

    The other solutions did not work reliably for me until I added:

    android:mimeType="*/*" 
    

    Before that it worked in some applications, in some not...

    complete solution for me:

    <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>
    
    0 讨论(0)
  • 2020-11-22 11:46

    Markus Ressel is correct. Android 7.0 Nougat no longer permits file sharing between apps using a file URI. A content URI must be used. However, a content URI does not allow a file path to be shared, only a mime type. So you cannot use a content URI to associate your app with your own file extension.

    Drobpox has an interesting behavior on Android 7.0. When it meets an unknown file extension it appears to form a file URI intent but instead of launching the intent it calls the operating system to find out which apps can accept the intent. If there is only one app that can accept that file URI it then sends an explicit content URI directly to that app. So to work with Dropbox you do not need to change the intent filters on your app. It does not require a content URI intent filter. Just make sure the app can receive a content URI and your app with your own file extension will work with Dropbox just like it did before Android 7.0.

    Here is an example of my file loading code modified to accept a content 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);
            ...
        }
    }
    
    0 讨论(0)
提交回复
热议问题