I am looking to create a custom image picker in my Flutter application using Method Channels. I have been looking for a while and there really is no great documentation on the subject.
The Flutter docs reference getting the battery level, but it is not much help to be honest. I would like to avoid using third-party packages because there are none out there with high reviews and that support multi-image selection.
Requirements:
- Display your image gallery in-app (photo below)
- Select multiple images
- Display the chosen images full-size on another screen
- Be in a format I can save to my cloud datastore
I am able to get an image preview of my camera gallery in my flutter application using Method Channels by using the swift code below:
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "/gallery", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch (call.method) {
case "getItemCount": result(self.getGalleryImageCount())
case "getItem":
let index = call.arguments as? Int ?? 0
self.dataForGalleryItem(index: index, completion: { (data, id, created, location) in
result([
"data": data ?? Data(),
"id": id,
"created": created,
"location": location
])
})
default: result(FlutterError(code: "0", message: nil, details: nil))
}
})
dataForGalleryItem:
func dataForGalleryItem(index: Int, completion: @escaping (Data?, String, Int, URL?) -> Void) {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.includeHiddenAssets = false
fetchOptions.predicate = NSPredicate(format: "mediaType = %d",
PHAssetMediaType.image.rawValue)
let collection: PHFetchResult = PHAsset.fetchAssets(with: fetchOptions)
if (index >= collection.count) {
return
}
var url : URL?
let asset = collection.object(at: index)
asset.requestContentEditingInput(with: PHContentEditingInputRequestOptions()) {(editingInput, info) in
if let input = editingInput, let photoUrl = input.fullSizeImageURL {
url = photoUrl;
}}
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isSynchronous = false
let imageSize = CGSize(width: 600,
height: 600)
let imageManager = PHCachingImageManager()
imageManager.requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFit, options: options) { (image, info) in
if let image = image {
let data = image.jpegData(compressionQuality: 1.0)
completion(data,
asset.localIdentifier,
Int(asset.creationDate?.timeIntervalSince1970 ?? 0),
url)
} else {
completion(nil, "", 0, nil)
}
}
}
Using the imageManager.requestImage()
I am able to get the image data and send it back to the Flutter client.
On the Flutter side I am taking that data and using Image.memory()
on the byte list to display the preview image pictured in the screenshot above.
Issues
Is this an acceptable Swift implementation for getting camera roll images?
How on earth do I get the local file path from the Swift code to be able to use
Image.file()
on the Flutter client?let asset = collection.object(at: index) asset.requestContentEditingInput(with: PHContentEditingInputRequestOptions()) {(editingInput, info) in if let input = editingInput, let photoUrl = input.fullSizeImageURL { url = photoUrl; }}
The URL keeps coming back as NULL.
I need to get the file path to be able to save the image to my Google Cloud Bucket.