diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7fa83b9..95adeb9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## 1.3.7
+
+**Rollback - Breaking change:** Re-adds runtime verification for external storage read permission. Don't forget to add the permission to the `AndroidManifest.xml` file as well. More info in the README file.
+**Bug fix:** Fixes a crash that could cause some Android API to crash when multiple files were selected from external storage.
+
+## 1.3.6
+
+**Improvements**
+ * Removes the Android write permissions requirement.
+ * Minor improvements in the example app.
+ * Now the exceptions are rethrown in case the user wants to handle them, despite that already being done in the plugin call.
+
## 1.3.5
**Bug fix:** Fixes an issue that could prevent users to pick files from the iCloud Drive app, on versions below iOS 11.
diff --git a/README.md b/README.md
index 70604c2..ff9835b 100644
--- a/README.md
+++ b/README.md
@@ -11,15 +11,16 @@ A package that allows you to use a native file explorer to pick single or multip
First, add *file_picker* as a dependency in [your pubspec.yaml file](https://flutter.io/platform-plugins/).
```
-file_picker: ^1.3.5
+file_picker: ^1.3.7
```
### Android
-Add
+
+Add
```
-
-
+
```
-before `` to your app's `AndroidManifest.xml` file. This is required due to file caching when a path is required from a remote file (eg. Google Drive).
+before `` to your app's `AndroidManifest.xml` file. This is required to access files from external storage.
+
### iOS
Based on the location of the files that you are willing to pick paths, you may need to add some keys to your iOS app's _Info.plist_ file, located in `/ios/Runner/Info.plist`:
@@ -108,6 +109,8 @@ String someFilePath = filePaths['fileName']; // Access a file path directly by i
* [X] Load path from **any**
* [X] Create a `File` object from **any** selected file
+If you have any feature that you want to see in this package, please add it [here](https://github.com/miguelpruivo/plugins_flutter_file_picker/issues/99). 🎉
+
## Demo App
![Demo](https://github.com/miguelpruivo/plugins_flutter_file_picker/blob/master/example/example.gif)
diff --git a/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java b/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
index cced080..ced49cd 100644
--- a/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
+++ b/android/src/main/java/com/mr/flutter/plugin/filepicker/FilePickerPlugin.java
@@ -30,7 +30,7 @@ public class FilePickerPlugin implements MethodCallHandler {
private static final int REQUEST_CODE = (FilePickerPlugin.class.hashCode() + 43) & 0x0000ffff;
private static final int PERM_CODE = (FilePickerPlugin.class.hashCode() + 50) & 0x0000ffff;
private static final String TAG = "FilePicker";
- private static final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+ private static final String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
private static Result result;
private static Registrar instance;
@@ -63,6 +63,9 @@ public class FilePickerPlugin implements MethodCallHandler {
while(currentItem < count) {
final Uri currentUri = data.getClipData().getItemAt(currentItem).getUri();
String path = FileUtils.getPath(currentUri, instance.context());
+ if(path == null) {
+ path = FileUtils.getUriFromRemote(instance.activeContext(), currentUri, result);
+ }
paths.add(path);
Log.i(TAG, "[MultiFilePick] File #" + currentItem + " - URI: " +currentUri.getPath());
currentItem++;
@@ -174,21 +177,26 @@ public class FilePickerPlugin implements MethodCallHandler {
Intent intent;
if (checkPermission()) {
- if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- intent = new Intent(Intent.ACTION_PICK);
- } else {
- intent = new Intent(Intent.ACTION_GET_CONTENT);
- }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ intent = new Intent(Intent.ACTION_PICK);
+ } else {
+ intent = new Intent(Intent.ACTION_GET_CONTENT);
+ }
- Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath() + File.separator);
- intent.setDataAndType(uri, type);
- intent.setType(type);
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultipleSelection);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
+ Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath() + File.separator);
+ intent.setDataAndType(uri, type);
+ intent.setType(type);
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultipleSelection);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
- instance.activity().startActivityForResult(intent, REQUEST_CODE);
+ if (intent.resolveActivity(instance.activity().getPackageManager()) != null) {
+ instance.activity().startActivityForResult(intent, REQUEST_CODE);
+ } else {
+ Log.e(TAG, "Can't find a valid activity to handle the request. Make sure you've a file explorer installed.");
+ result.error(TAG, "Can't handle the provided file type.", null);
+ }
} else {
- requestPermission();
+ requestPermission();
}
}
diff --git a/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java b/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
index 077653e..e66185f 100644
--- a/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
+++ b/android/src/main/java/com/mr/flutter/plugin/filepicker/FileUtils.java
@@ -19,10 +19,6 @@ import java.io.InputStream;
import io.flutter.plugin.common.MethodChannel;
-/**
- * Credits to NiRRaNjAN from utils extracted of in.gauriinfotech.commons;.
- **/
-
public class FileUtils {
private static final String TAG = "FilePickerUtils";
@@ -109,9 +105,11 @@ public class FileUtils {
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
Log.e(TAG, "NO DOCUMENT URI - CONTENT");
- if (isGooglePhotosUri(uri))
+ if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
-
+ } else if (isDropBoxUri(uri)) {
+ return null;
+ }
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
Log.e(TAG, "No DOCUMENT URI - FILE");
@@ -177,11 +175,12 @@ public class FileUtils {
public static String getUriFromRemote(Context context, Uri uri, MethodChannel.Result result) {
+ Log.i(TAG, "Caching file from remote/external URI");
FileOutputStream fos = null;
- String cloudFile = context.getCacheDir().getAbsolutePath() + "/" + FileUtils.getFileName(uri, context);
+ String externalFile = context.getCacheDir().getAbsolutePath() + "/" + FileUtils.getFileName(uri, context);
try {
- fos = new FileOutputStream(cloudFile);
+ fos = new FileOutputStream(externalFile);
try {
BufferedOutputStream out = new BufferedOutputStream(fos);
InputStream in = context.getContentResolver().openInputStream(uri);
@@ -208,10 +207,13 @@ public class FileUtils {
return null;
}
- Log.i(TAG, "Remote file loaded and cached at:" + cloudFile);
- return cloudFile;
+ Log.i(TAG, "File loaded and cached at:" + externalFile);
+ return externalFile;
}
+ private static boolean isDropBoxUri(Uri uri) {
+ return "com.dropbox.android.FileCache".equals(uri.getAuthority());
+ }
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index ce5983a..3f815b3 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -22,7 +22,6 @@ android {
}
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.mr.flutter.plugin.filepickerexample"
minSdkVersion 16
targetSdkVersion 28
@@ -33,7 +32,6 @@ android {
buildTypes {
release {
- // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 8755b71..94e4412 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -7,7 +7,7 @@
to allow setting breakpoints, to provide hot reload, etc.
-->
-
+