4

I am trying to share an image via classic Intent. I have added the following items:

file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="my_images" path="." />
</paths>

Manifest:

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.android.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

And finally MainActivity.java:

private void shareFile(String fileName) {
        Intent share = new Intent(Intent.ACTION_SEND);
        Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getApplicationInfo().dataDir + "/app_flutter/userphotos", fileName));
        share.setData(uri);
        share.setType("image/png");
        share.putExtra(Intent.EXTRA_STREAM, uri);
        share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity(Intent.createChooser(share, "Share"));
    }

The problem I am facing is that image I am trying to share has the following path:

/data/user/0/shoedrobe.innovativeproposals.com.shoedrobe/app_flutter/userphotos/receipt20181101094430.jpg

However the FileProvider is trying to access it from here:

java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/shoedrobe.innovativeproposals.com.shoedrobe/app_flutter/userphotos/receipt20181101094430.jpg

For saving images I am using package path_provider and I am saving items under getApplicationDocumentsDirectory(), which in Android is AppData directory.

I am not sure why FileProvider decided suddenly to go from /data/user/0/ to /data/data/ folder, therefore any help or tips regarding this matter would be highly appreciated.

Update:
I have updated the code as per recommendations and replaced the Uri under MainActivity.java with the following line:

Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getDir("flutter", Context.MODE_PRIVATE).getPath() + "/app_flutter/userphotos", path));

Nonetheless, the problem still persists (same exception that file is supposed to be under /data/data/<package> instead of /data/user/0. I have also tried to add additional persmissions to my AndroidManifest:

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

but it did not work as well. Could the problem lie with my file_paths.xml file?

Robert J.
  • 2,631
  • 8
  • 32
  • 59

2 Answers2

1

In the end, none of the proposed solutions did not work; neither using extenal-path, nor the other solution.

The way how I managed in the end to share file was to actually copy it to a temporary (cache) directory first (in flutter path_provider it's getTemporaryDirectory()) and update file_paths.xml to following:

<cache-path name="image" path="."/>

and finally under MainActivity.java:

Uri uri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(this.getCacheDir(), path));
Robert J.
  • 2,631
  • 8
  • 32
  • 59
0

Under the hood, Flutter's getApplicationDocumentsDirectory() is using getDir() instead of dataDir, which could be different.

From the Android documentation on getDataDir(), which is equivalent to this.getApplicationInfo().dataDir:

Returns the absolute path to the directory on the filesystem where all private files belonging to this app are stored. Apps should not use this path directly; they should instead use getFilesDir(), getCacheDir(), getDir(String, int), or other storage APIs on this class.

The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted.

Therefore, to ensure consistency between the directory used for saving images by Flutter and the directory used to retrieve the files via FileProvider, the getUriForFile line in MainActivity.java could be modified like this:

FileProvider.getUriForFile(this, "com.example.android.fileprovider", new File(<your application context>.getDir("flutter", Context.MODE_PRIVATE).getPath() + "/app_flutter/userphotos", fileName));

... replacing <your application context> with the variable storing your application's context, if any.

Community
  • 1
  • 1
Carol Ng
  • 575
  • 2
  • 11
  • Would it be possible to share necessary code changes to fix the app? – Robert J. Nov 11 '18 at 20:48
  • I've amended the answer with a possible fix, which involves changing the directory used to get the images from your existing `dataDir` to `Context.getDir()` as in the Flutter source. – Carol Ng Nov 11 '18 at 22:37
  • I have updated my code with proposed changes (see post updates please), yet the same problem persists (with different paths). As the path problem persists, should I use different path where to store items? Or should I update my file_paths file maybe? – Robert J. Nov 12 '18 at 06:34