Search code examples
android-intentionic-frameworkemail-attachments

Ionic App - Open a custom type of file from mail attachment


I'm developing a small Ionic app that needs some data to be processed and displayed in a certain way. The data are originally stored in a file under XLSX format, then the file's extension is changed to a custom one, let's say .myext (for those who wonder: I do that so all .xlsx files are not automatically opened with my app, which needs a certain data structuration).

I managed, like you can see in a previous post I made about this app, to make my app able to open XLSX files, and then able to open .myext files. Though, I can only open a .myext file with my app automatically when opening it via a file system explorer on my Android device (in my case File Commander). I want the device to automatically open .myext files with my app when the user receive such file in his/her mail inbox (whether dedicated app or browser); when I try to do so, I got a warning saying that no app capable to open such files is available on my device (the file is downloaded anyway and I still can open it via device file system explorer).

I tried to change my intent declaration in the AndroidManifest, without any luck for now (note the android:scheme lines; I tried several combinations, using one, two, three, or all of them at the same time):

<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.Black.NoTitleBar" android:windowSoftInputMode="adjustResize">
    <intent-filter android:label="@string/launcher_name">
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </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="file" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:scheme="content" />
        <data android:mimeType="*/*" />
        <data android:pathPattern=".*\\.myext" />
        <data android:host="*" />
    </intent-filter>
</activity>

I feel like I'm missing something, or that is not possible to open custom file extension via mail attachment. Do you have any idea to do so?


Solution

  • With the help of user e666 and his/her research, I managed to modify the intents declaration of my Ionic app, which are now like follow in my AndroidManifest.xml (saying my custom file extension is ".myapp"):

    <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.Black.NoTitleBar" android:windowSoftInputMode="adjustResize">
        <intent-filter android:label="@string/launcher_name">
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <data android:mimeType="application/vnd.myapp" android:pathPattern=".*\\.myapp" android:scheme="content" />
            <data android:mimeType="application/myapp" android:pathPattern=".*\\.myapp" android:scheme="content" />
            <data android:mimeType="application/octet-stream" android:pathPattern=".*\\.myapp" android:scheme="content" />
            <action android:name="android.intent.action.VIEW" />
            <action android:name="android.intent.action.GET_CONTENT" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
        </intent-filter>
        <intent-filter>
            <data android:scheme="file" />
            <data android:mimeType="*/*" />
            <data android:pathPattern=".*\\.myapp" />
            <data 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>
    </activity>
    

    The first intent is the default one created by the Ionic framework when I added the support of the android platform. The second intent is for file downloaded from a mail attachment. The third and last intent filter is for file opened through a file explorer on the user's android device.

    Note that when you fetch the URI in backend Ionic Javascript part of the app, you get a content:// URI when you try to open a .myapp file via mail app or mail browser interface. But the type of content:// URI is not the same if you try to directly open the file with the mail app/brower interface (case 1), and if you download the file THEN try to open it by taping the "download complete" notification (case 2):

    • case 1: you'll get something like content://gmail-ls/myemail@gmail.com/messages/520/attachments/0.1/BEST/false
    • case 2: you'll get something like content://downloads/all_downloads/283

    In the first case, I couldn't find a way to parse this URI to a file:/// URI (which I need to open then read the data in the file).

    In the second case, I installed the cordova-plugin-filepath package (that creates the window.FilePath object) and used it as follow to parse the content URI into a file URI (see my previous post on the subject to understand how to feed a file to your app):

    window.plugins.webintent.getUri(function (url) { // success getUri
        if(url.startsWith('content://')){
            window.FilePath.resolveNativePath(url, function(res){
                // parse content uri to file uri
                var converted_url = "file://" + res;
    
                // extract path and filename from parsed uri
                var path = converted_url.slice(0, converted_url.lastIndexOf('/') + 1);
                var filename = converted_url.substring(converted_url.lastIndexOf('/') + 1);
    
                // read the file
                $cordovaFile.readAsBinaryString(path, filename).then(function (result) { // success readAsBinaryString
                    // use the data
                }, function(error){ //failure readAsBinaryString
                    // error when trying to open the file
                });
            }, function(error) { // failure resolveNativePath
                // couldn't parse content URI to file URI
            });
        } else {
            // the given URI is not a content URI
        }
    }, function(error) { // failure getUri
        // no URI has been given to the app
    }
    

    I hope this will help someone else in the future.