removes the image_picker dependency and adds support for picking song files on iOS

This commit is contained in:
Miguel Ruivo 2019-03-05 19:02:14 +00:00
parent 7402f4bf9d
commit a745cdb333
11 changed files with 206 additions and 87 deletions

View File

@ -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":

View File

@ -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;

View File

@ -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

View File

@ -22,10 +22,6 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Used to demonstrate image picker plugin</string>
<key>NSMicrophoneUsageDescription</key>
<string>Used to capture audio for image picker plugin</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to demonstrate image picker plugin</string>
<key>UILaunchStoryboardName</key>
@ -38,11 +34,11 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>

View File

@ -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<MyApp> {
class _FilePickerDemoState extends State<FilePickerDemo> {
String _fileName = '...';
String _path = '...';
String _extension;
@ -60,9 +60,13 @@ class _MyAppState extends State<MyApp> {
hint: new Text('LOAD PATH FROM'),
value: _pickingType,
items: <DropdownMenuItem>[
// 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'),

View File

@ -1,5 +1,7 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <Photos/Photos.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface FilePickerPlugin : NSObject<FlutterPlugin, UIDocumentPickerDelegate, UITabBarDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate>

View File

@ -1,10 +1,13 @@
#import "FilePickerPlugin.h"
#import "FileUtils.h"
#import "ImageUtils.h"
@interface FilePickerPlugin()
@interface FilePickerPlugin() <UIImagePickerControllerDelegate, MPMediaPickerControllerDelegate>
@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<NSURL *> *)urls{
@ -82,23 +128,51 @@ didPickDocumentsAtURLs:(NSArray<NSURL *> *)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 {

View File

@ -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;

11
ios/Classes/ImageUtils.h Normal file
View File

@ -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

35
ios/Classes/ImageUtils.m Normal file
View File

@ -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

View File

@ -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<String> _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<String> _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<String> 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: