Flutter: how to let a file be opened by an external app (like Android's implicit intent)?
It's hard to get this to work correctly. Here are some hints that helped me to launch ACTION_VIEW
intents from Flutter, with files downloaded with Flutter.
1) Register a FileProvider
in the android manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
provider_paths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
</paths>
2) Create a custom platform channel that provides 2 methods (Code below is Kotlin):
getDownloadsDir
: Should return the data dir where downloaded files should be placed. Try this one:
val downloadsDir = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).path
result.success(downloadsDir);
previewFile
that takes 2 string arguments: path
(File.path
in Dart) and type
(e.g. "application/pdf"):
val file = File(path);
val uri = FileProvider.getUriForFile(this, "com.example.myapp.provider", file);
val viewFileIntent = Intent(Intent.ACTION_VIEW);
viewFileIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION);
viewFileIntent.setDataAndType(uri, type);
try {
startActivity(viewFileIntent);
result.success(null);
} catch (e: ActivityNotFoundException) {
result.error(...);
}
The most important part is the creation of the FileProvider
. url_launcher and android_intent will not work, you have to create your own platform channel. You can change the download path, but then you also have to find the correct provider/permissions settings.
Making this work on iOS is also possible, but out of scope of this question.
If you are using the image_picker plugin:
The FileProvider
conflicts with the current version of the image_picker (0.4.6) plugin, a fix will be released soon.