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 8b2af83..04bf9dd 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
@@ -87,7 +87,7 @@ public class FilePickerPlugin implements MethodCallHandler {
result.error(TAG, "Failed to retrieve path: " + e.getMessage(),null);
}
- Log.i(TAG, "Cloud file loaded and cached on:" + cloudFile);
+ Log.i(TAG, "Remote file loaded and cached at:" + cloudFile);
fullPath = cloudFile;
}
Log.i(TAG, "Absolute file path:" + fullPath);
@@ -151,6 +151,10 @@ public class FilePickerPlugin implements MethodCallHandler {
}
switch (type) {
+ case "AUDIO":
+ return "audio/*";
+ case "IMAGE":
+ return "image/*";
case "VIDEO":
return "video/*";
case "ANY":
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 9a6bf56..57454d7 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,7 +19,7 @@ import android.webkit.MimeTypeMap;
public class FileUtils {
- private static final String tag = "FilePathPicker";
+ private static final String tag = "FilePickerUtils";
public static String getPath(final Uri uri, Context context) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
@@ -38,27 +38,26 @@ public class FileUtils {
@TargetApi(19)
private static String getForApi19(Context context, Uri uri) {
- Log.e(tag, "+++ API 19 URI :: " + uri);
+ Log.e(tag, " --- API 19 URI --- " + uri);
if (DocumentsContract.isDocumentUri(context, uri)) {
- Log.e(tag, "+++ Document URI");
+ Log.e(tag, "--- Document URI ---");
if (isExternalStorageDocument(uri)) {
- Log.e(tag, "+++ External Document URI");
+ Log.e(tag, "--- External Document URI ---");
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
- Log.e(tag, "+++ Primary External Document URI");
+ Log.e(tag, "--- Primary External Document URI ---");
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {
- Log.e(tag, "+++ Downloads External Document URI");
+ Log.e(tag, "--- Downloads External Document URI ---");
final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
-
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads",
@@ -72,26 +71,26 @@ public class FileUtils {
return path;
}
} catch (Exception e) {
- Log.e(tag, "+++ Something went wrong while retrieving document path: " + e.toString());
+ Log.e(tag, "Something went wrong while retrieving document path: " + e.toString());
}
}
}
} else if (isMediaDocument(uri)) {
- Log.e(tag, "+++ Media Document URI");
+ Log.e(tag, "--- Media Document URI ---");
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
- Log.e(tag, "+++ Image Media Document URI");
+ Log.e(tag, "--- Image Media Document URI ---");
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
- Log.e(tag, "+++ Video Media Document URI");
+ Log.e(tag, "--- Video Media Document URI ---");
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
- Log.e(tag, "+++ Audio Media Document URI");
+ Log.e(tag, "--- Audio Media Document URI ---");
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
@@ -103,13 +102,13 @@ public class FileUtils {
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
- Log.e(tag, "+++ No DOCUMENT URI :: CONTENT ");
+ Log.e(tag, "--- NO DOCUMENT URI - CONTENT ---");
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
- Log.e(tag, "+++ No DOCUMENT URI :: FILE ");
+ Log.e(tag, "--- No DOCUMENT URI - FILE ---");
return uri.getPath();
}
return null;
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index 652a159..f626a5c 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -2,26 +2,20 @@ PODS:
- file_picker (0.0.1):
- Flutter
- Flutter (1.0.0)
- - image_picker (0.0.1):
- - Flutter
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `.symlinks/flutter/ios`)
- - image_picker (from `.symlinks/plugins/image_picker/ios`)
EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: ".symlinks/flutter/ios"
- image_picker:
- :path: ".symlinks/plugins/image_picker/ios"
SPEC CHECKSUMS:
file_picker: 78c3344d9b2c343bb3090c2f032b796242ebaea7
Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
- image_picker: ee00aab0487cedc80a304085219503cc6d0f2e22
PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index a25de3b..114e0c7 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -22,10 +22,6 @@
$(FLUTTER_BUILD_NUMBER)
LSRequiresIPhoneOS
- NSCameraUsageDescription
- Used to demonstrate image picker plugin
- NSMicrophoneUsageDescription
- Used to capture audio for image picker plugin
NSPhotoLibraryUsageDescription
Used to demonstrate image picker plugin
UILaunchStoryboardName
@@ -38,11 +34,11 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
- UIBackgroundModes
-
- fetch
- remote-notification
-
+ UIBackgroundModes
+
+ fetch
+ remote-notification
+
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 5e27ef0..5d85465 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -3,14 +3,14 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:file_picker/file_picker.dart';
-void main() => runApp(new MyApp());
+void main() => runApp(new FilePickerDemo());
-class MyApp extends StatefulWidget {
+class FilePickerDemo extends StatefulWidget {
@override
- _MyAppState createState() => new _MyAppState();
+ _FilePickerDemoState createState() => new _FilePickerDemoState();
}
-class _MyAppState extends State {
+class _FilePickerDemoState extends State {
String _fileName = '...';
String _path = '...';
String _extension;
@@ -60,9 +60,13 @@ class _MyAppState extends State {
hint: new Text('LOAD PATH FROM'),
value: _pickingType,
items: [
+ // new DropdownMenuItem(
+ // child: new Text('FROM CAMERA'),
+ // value: FileType.CAMERA,
+ // ),
new DropdownMenuItem(
- child: new Text('FROM CAMERA'),
- value: FileType.CAMERA,
+ child: new Text('FROM AUDIO'),
+ value: FileType.AUDIO,
),
new DropdownMenuItem(
child: new Text('FROM GALLERY'),
diff --git a/ios/Classes/FilePickerPlugin.h b/ios/Classes/FilePickerPlugin.h
index 145a322..fecbd3f 100644
--- a/ios/Classes/FilePickerPlugin.h
+++ b/ios/Classes/FilePickerPlugin.h
@@ -1,5 +1,7 @@
#import
#import
+#import
+#import
#import
@interface FilePickerPlugin : NSObject
diff --git a/ios/Classes/FilePickerPlugin.m b/ios/Classes/FilePickerPlugin.m
index f9bc5d3..bfb6ff7 100644
--- a/ios/Classes/FilePickerPlugin.m
+++ b/ios/Classes/FilePickerPlugin.m
@@ -1,10 +1,13 @@
#import "FilePickerPlugin.h"
#import "FileUtils.h"
+#import "ImageUtils.h"
-@interface FilePickerPlugin()
+@interface FilePickerPlugin()
@property (nonatomic) FlutterResult result;
@property (nonatomic) UIViewController *viewController;
+@property (nonatomic) UIImagePickerController *galleryPickerController;
@property (nonatomic) UIDocumentPickerViewController *pickerController;
+@property (nonatomic) MPMediaPickerController *audioPickerController;
@property (nonatomic) UIDocumentInteractionController *interactionController;
@property (nonatomic) NSString * fileType;
@end
@@ -32,16 +35,6 @@
return self;
}
-- (void)initPicker {
-
- self.pickerController = [[UIDocumentPickerViewController alloc]
- initWithDocumentTypes:@[self.fileType]
- inMode:UIDocumentPickerModeImport];
-
- self.pickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
- self.pickerController.delegate = self;
-}
-
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if (_result) {
_result([FlutterError errorWithCode:@"multiple_request"
@@ -56,24 +49,77 @@
if([call.method isEqualToString:@"VIDEO"]) {
[self resolvePickVideo];
}
- else {
+ else if([call.method isEqualToString:@"AUDIO"]) {
+ [self resolvePickAudio];
+ }
+ else if([call.method isEqualToString:@"IMAGE"]) {
+ [self resolvePickImage];
+ } else {
self.fileType = [FileUtils resolveType:call.method];
if(self.fileType == nil){
result(FlutterMethodNotImplemented);
} else {
- [self initPicker];
- [_viewController presentViewController:self.pickerController animated:YES completion:^{
- if (@available(iOS 11.0, *)) {
- self.pickerController.allowsMultipleSelection = NO;
- }
- }];
-
+ [self resolvePickDocument];
}
}
}
+#pragma mark - Resolvers
+
+- (void)resolvePickDocument {
+
+ self.pickerController = [[UIDocumentPickerViewController alloc]
+ initWithDocumentTypes:@[self.fileType]
+ inMode:UIDocumentPickerModeImport];
+
+ if (@available(iOS 11.0, *)) {
+ self.pickerController.allowsMultipleSelection = NO;
+ } else {
+ // Fallback on earlier versions
+ }
+ self.pickerController.delegate = self;
+ self.pickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
+ self.galleryPickerController.allowsEditing = NO;
+ [_viewController presentViewController:self.pickerController animated:YES completion:nil];
+}
+
+- (void) resolvePickImage {
+
+ self.galleryPickerController = [[UIImagePickerController alloc] init];
+ self.galleryPickerController.delegate = self;
+ self.galleryPickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
+ self.galleryPickerController.mediaTypes = @[(NSString *)kUTTypeImage];
+ self.galleryPickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
+
+ [_viewController presentViewController:self.galleryPickerController animated:YES completion:nil];
+}
+
+- (void) resolvePickAudio {
+
+ self.audioPickerController = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAnyAudio];
+ self.audioPickerController.delegate = self;
+ self.audioPickerController.showsCloudItems = NO;
+ self.audioPickerController.allowsPickingMultipleItems = NO;
+ self.audioPickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
+ [self.viewController presentViewController:self.audioPickerController animated:YES completion:nil];
+}
+
+- (void) resolvePickVideo {
+
+ self.galleryPickerController = [[UIImagePickerController alloc] init];
+ self.galleryPickerController.delegate = self;
+ self.galleryPickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
+ self.galleryPickerController.mediaTypes = @[(NSString*)kUTTypeMovie, (NSString*)kUTTypeAVIMovie, (NSString*)kUTTypeVideo, (NSString*)kUTTypeMPEG4];
+ self.galleryPickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
+
+ [self.viewController presentViewController:self.galleryPickerController animated:YES completion:nil];
+}
+
+#pragma mark - Delegates
+
+// DocumentPicker delegate
- (void)documentPicker:(UIDocumentPickerViewController *)controller
didPickDocumentsAtURLs:(NSArray *)urls{
@@ -82,23 +128,51 @@ didPickDocumentsAtURLs:(NSArray *)urls{
}
-// VideoPicker delegate
-- (void) resolvePickVideo{
-
- UIImagePickerController *videoPicker = [[UIImagePickerController alloc] init];
- videoPicker.delegate = self;
- videoPicker.modalPresentationStyle = UIModalPresentationCurrentContext;
- videoPicker.mediaTypes = @[(NSString*)kUTTypeMovie, (NSString*)kUTTypeAVIMovie, (NSString*)kUTTypeVideo, (NSString*)kUTTypeMPEG4];
- videoPicker.videoQuality = UIImagePickerControllerQualityTypeHigh;
-
- [self.viewController presentViewController:videoPicker animated:YES completion:nil];
-}
-
+// ImagePicker delegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
- NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
+ NSURL *pickedVideoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
+ NSURL *pickedImageUrl;
+
+ if (@available(iOS 11.0, *)) {
+ pickedImageUrl = [info objectForKey:UIImagePickerControllerImageURL];
+ } else {
+ UIImage *pickedImage = [info objectForKey:UIImagePickerControllerEditedImage];
+
+ if(pickedImage == nil) {
+ pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
+ }
+ pickedImageUrl = [ImageUtils saveTmpImage:pickedImage];
+ }
+
[picker dismissViewControllerAnimated:YES completion:NULL];
- _result([videoURL path]);
+
+ if(pickedImageUrl == nil && pickedVideoUrl == nil) {
+ _result([FlutterError errorWithCode:@"file_picker_error"
+ message:@"Temporary file could not be created"
+ details:nil]);
+ }
+
+ _result([pickedVideoUrl != nil ? pickedVideoUrl : pickedImageUrl path]);
+}
+
+
+// AudioPicker delegate
+- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
+{
+ [mediaPicker dismissViewControllerAnimated:YES completion:NULL];
+ NSURL *url = [[[mediaItemCollection items] objectAtIndex:0] valueForKey:MPMediaItemPropertyAssetURL];
+ if(url == nil) {
+ NSLog(@"Couldn't retrieve the audio file path, either is not locally downloaded or the file DRM protected.");
+ }
+ _result([url absoluteString]);
+}
+
+#pragma mark - Actions canceled
+
+- (void)mediaPickerDidCancel:(MPMediaPickerController *)controller {
+ _result = nil;
+ [controller dismissViewControllerAnimated:YES completion:NULL];
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
diff --git a/ios/Classes/FileUtils.m b/ios/Classes/FileUtils.m
index ae24524..805ebca 100644
--- a/ios/Classes/FileUtils.m
+++ b/ios/Classes/FileUtils.m
@@ -23,10 +23,7 @@
return [UTIString containsString:@"dyn."] ? nil : UTIString;
}
- if ([type isEqualToString:@"PDF"]) {
- return @"com.adobe.pdf";
- }
- else if ([type isEqualToString:@"ANY"]) {
+ if ([type isEqualToString:@"ANY"]) {
return @"public.item";
} else {
return nil;
diff --git a/ios/Classes/ImageUtils.h b/ios/Classes/ImageUtils.h
new file mode 100644
index 0000000..53aefad
--- /dev/null
+++ b/ios/Classes/ImageUtils.h
@@ -0,0 +1,11 @@
+//
+// ImageUtils.h
+// Pods
+//
+// Created by Miguel Ruivo on 05/03/2019.
+//
+
+@interface ImageUtils : NSObject
++ (BOOL)hasAlpha:(UIImage *)image;
++ (NSURL*)saveTmpImage:(UIImage *)image;
+@end
diff --git a/ios/Classes/ImageUtils.m b/ios/Classes/ImageUtils.m
new file mode 100644
index 0000000..df5b681
--- /dev/null
+++ b/ios/Classes/ImageUtils.m
@@ -0,0 +1,35 @@
+//
+// ImageUtils.m
+// file_picker
+//
+// Created by Miguel Ruivo on 05/03/2019.
+//
+
+#import "ImageUtils.h"
+
+@implementation ImageUtils
+
+// Returns true if the image has an alpha layer
++ (BOOL)hasAlpha:(UIImage *)image {
+ CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image.CGImage);
+ return (alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast ||
+ alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast);
+}
+
+// Save the image temporarly in the app's tmp directory
++ (NSURL *)saveTmpImage:(UIImage *)image {
+ BOOL hasAlpha = [ImageUtils hasAlpha:image];
+ NSData *data = hasAlpha ? UIImagePNGRepresentation(image) : UIImageJPEGRepresentation(image, 1.0);
+ NSString *fileExtension = hasAlpha ? @"tmp_%@.png" : @"tmp_%@.jpg";
+ NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
+ NSString *tmpFile = [NSString stringWithFormat:fileExtension, guid];
+ NSString *tmpDirectory = NSTemporaryDirectory();
+ NSString *tmpPath = [tmpDirectory stringByAppendingPathComponent:tmpFile];
+
+ if ([[NSFileManager defaultManager] createFileAtPath:tmpPath contents:data attributes:nil]) {
+ return [NSURL URLWithString: tmpPath];
+ }
+ return nil;
+}
+
+@end
diff --git a/lib/file_picker.dart b/lib/file_picker.dart
index e1f60f2..4527d49 100644
--- a/lib/file_picker.dart
+++ b/lib/file_picker.dart
@@ -1,14 +1,15 @@
import 'dart:async';
import 'package:flutter/services.dart';
-import 'package:image_picker/image_picker.dart';
+// import 'package:image_picker/image_picker.dart';
/// Supported file types, [ANY] should be used if the file you need isn't listed
enum FileType {
ANY,
IMAGE,
VIDEO,
- CAMERA,
+ AUDIO,
+ // CAMERA,
CUSTOM,
}
@@ -28,15 +29,15 @@ class FilePicker {
return null;
}
- static Future _getImage(ImageSource type) async {
- try {
- var image = await ImagePicker.pickImage(source: type);
- return image?.path;
- } on PlatformException catch (e) {
- print("[$_tag] Platform exception: " + e.toString());
- }
- return null;
- }
+ // static Future _getImage(ImageSource type) async {
+ // try {
+ // var image = await ImagePicker.pickImage(source: type);
+ // return image?.path;
+ // } on PlatformException catch (e) {
+ // print("[$_tag] Platform exception: " + e.toString());
+ // }
+ // return null;
+ // }
/// Returns an absolute file path from the calling platform
///
@@ -46,9 +47,11 @@ class FilePicker {
static Future getFilePath({FileType type = FileType.ANY, String fileExtension}) async {
switch (type) {
case FileType.IMAGE:
- return _getImage(ImageSource.gallery);
- case FileType.CAMERA:
- return _getImage(ImageSource.camera);
+ return _getPath('IMAGE');
+ // case FileType.CAMERA:
+ // return _getImage(ImageSource.camera);
+ case FileType.AUDIO:
+ return _getPath('AUDIO');
case FileType.VIDEO:
return _getPath('VIDEO');
case FileType.ANY: