Android intent filter for a particular file extension?

后端 未结 15 1370
我寻月下人不归
我寻月下人不归 2020-11-22 16:04

I want to be able to download a file with a particular extension from the \'net, and have it passed to my application to deal with it, but I haven\'t been able to figure out

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

    Brian's answer is very close, but here's a clean and error-free way to have your app invoked when trying to open a file with your own custom extension (no need for scheme or host):

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

    When an Intent meets a intent-filter, these are the intent-filter requirements: (imagine a checklist).

    • Any matching <action>
    • Any matching <category>
    • Any matching <data mimeType> (easy fix: "/")
    • Optionally:

      • Any matching <data scheme> (easy fix: <data android:scheme="file" /> <data android:scheme="content" />)

      • Any matching <data host> (easy fix: "*")

      • Any matching <data pathPattern/etc.> (for example .*\\.0cc)

    Defining multiple <data $type=""> elements checks the $type box iff any <data $type=> matches the Intent.

    Omitting mimeType breaks your intent-filter, even though it's seemingly redundant. Omitting <data scheme/host/pathPattern> causes your filter to match everything.

    https://f-droid.org/en/packages/de.k3b.android.intentintercept/ is an app designed to receive all intents, and allows you to inspect the intent. I learned that unrecognized file extensions opened via Simple File Manager are delivered with MIME type application/octet-stream.

    https://stackoverflow.com/a/4621284/2683842 reports that <data pathPattern=> .*xyz aborts at the first x it sees, and will fail immediately if not followed by yz. So /sdcard/.hidden/foo.0cc will not pass .*\\.0cc unless you try .*\\..*\\.0cc instead.

    • I did not verify whether this workaround is necessary.

    End result:

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

    Using the filter as below to open from browser, gmail & file browser (Tested). NOTE: Please do not merge two filters, that will make browser ignored your app(Tested).

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

    Update 2020

    Android has moved towards content URIs and MIME-Types for intent filters.

    The Problem

    A content URI does not necessarily have to contain the file's extension or name and it will be different between different applications that are providing the content/file.

    Here are some example content URIs from different email applications for the same email attachment:

    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

    Samsung Email App -> content://com.samsung.android.email.attachmentprovider/1/1/RAW

    As can see they are all different and are not guaranteed to contain anything related to your actual file. Thus, you cannot use the android:pathPattern like most have suggested.

    A work around solution for email attachments

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

    Through testing I found the MIME-Types that Gmail, Outlook, and Samsung Email used and added those to my intent-filter.

    Caveats/Gotchas

    • I found that with my above solution, if I opened any file that was a binary type, it would automatically launch my app. I handled this in my activity by displaying a failed state if we could not parse the file. I figured this was a pretty rare event so it would acceptable.

    • I could not find any way to launch my app via the file browser without adding <data android:mimeType="*/*"/> to my intent-filter. I couldn't use this because it would then launch my app whenever the user clicked any file on their phone (not just the custom-file-extension ones). I would not recommend adding this to your intent-filter.

    Final Thoughts

    • There is currently no elegant solution for associating your app with a specific extension type in Android. This was the best that I could do in my situation.
    0 讨论(0)
  • 2020-11-22 16:38

    I've been struggling with this quite a bit for a custom file extension, myself. After a lot of searching, I found this web page where the poster discovered that Android's patternMatcher class (which is used for the pathPattern matching in Intent-Filters) has unexpected behavior when your path contains the first character of your match pattern elsewhere in the path (like if you're trying to match "*.xyz", the patternMatcher class stops if there's an "x" earlier in your path). Here's what he found for a workaround, and worked for me, although it is a bit of a hack:

    PatternMatcher is used for pathPattern at IntentFilter But, PatternMatcher's algorithm is quite strange to me. Here is algorithm of Android PatternMatcher.

    If there is 'next character' of '.*' pattern in the middle of string, PatternMatcher stops loop at that point. (See PatternMatcher.java of Android framework.)

    Ex. string : "this is a my attachment" pattern : ".att.". Android PatternMatcher enter loop to match '.' pattern until meet the next character of pattern (at this example, 'a') So, '.' matching loop stops at index 8 - 'a' between 'is' and 'my'. Therefore result of this match returns 'false'.

    Quite strange, isn't it. To workaround this - actually reduce possibility - developer should use annoying stupid pathPattern.

    Ex. Goal : Matching uri path which includes 'message'.

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

    This is especially issued when matching with custom file extention.

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

    None of the above work properly, for VIEW or SEND actions, if the suffix is not registered with a MIME type in Android's system=wide MIME database. The only settings I've found that fire for the specified suffix include android:mimeType="*/*", but then the action fires for ALL files. Clearly NOT what you want!

    I can't find any proper solution without adding the mime and suffix to the Android mime database, so far, I haven't found a way to do that. If anyone knows, a pointer would be terrific.

    0 讨论(0)
提交回复
热议问题