Shaik Ahron
8 Dec 2022
•
2 min read
Android 13 provides a new way of picking files without asking for permission to pick media files.
In this article, I will show how you can use this photo picker in your flutter apps for APIs above 32.
Let’s begin
Here is the GitHub link
Step 1: create a new flutter project name photo_picker_demo.
Step 2: Now, before working with the photo picker on the android side. we need to create a method channel that will invoke the functionality of opening the new photo picker in android 13.
class MainActivity: FlutterFragmentActivity() {
companion object{
private const val PHOTO_PICKER_METHOD_CHANNEL: String = "photo_picker_method_channel"
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
handlePhotoPickerHandler(flutterEngine)
}
private fun handlePhotoPickerHandler(flutterEngine: FlutterEngine) {
val photoPickerMethodChannelHandler = PhotoPickerMethodChannelHandler(WeakReference(this))
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PHOTO_PICKER_METHOD_CHANNEL)
.setMethodCallHandler(photoPickerMethodChannelHandler)
}
}
In MainActivity.kt file you need to register the method channel and pass the handler for that method channel.
make sure to extend MainActivity with FlutterFragmentActivity, not FlutterActivity as it provides functionalities for photo picking
Step 3: Now, we will create a handler for our channel.
package com.example.photo_picker_demo
import android.app.Activity
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.webkit.MimeTypeMap
import androidx.activity.ComponentActivity
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.io.*
import java.lang.ref.WeakReference
class PhotoPickerMethodChannelHandler(
private val activity: WeakReference<Activity>,
) : MethodChannel.MethodCallHandler {
private lateinit var pendingResult: MethodChannel.Result
private val pickMedia = (activity.get() as ComponentActivity).registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
val path = getPathFromUri(activity.get()!!.applicationContext,uri)
pendingResult.success(path)
} else {
pendingResult.success(null)
}
}
private val pickMultipleMedia = (activity.get() as ComponentActivity).registerForActivityResult(ActivityResultContracts.PickVisualMedia(5)) { uri ->
if (uri != null) {
val path = getPathFromUri(activity.get()!!.applicationContext,uri)
pendingResult.success(path)
} else {
pendingResult.success(null)
}
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"pickMedia" -> pickMedia(call,result)
"pickMultipleMedia" -> pickMultipleMedia(call,result)
else -> result.notImplemented()
}
}
private fun pickMultipleMedia(call: MethodCall, result: MethodChannel.Result) {
this.pendingResult = result
val items = call.argument<Int>("items") ?: 1
when(call.argument<String>("file_type") ?: "image"){
"media" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))
"image" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
"video" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly))
}
}
private fun pickMedia(call: MethodCall, result: MethodChannel.Result) {
this.pendingResult = result
when(call.argument<String>("file_type") ?: "image"){
"media" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo))
"image" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
"video" -> pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.VideoOnly))
}
}
}
Here I am registering for activity results and the contract is PickVisualMedia. You can understand the contract as input that you want to pass.
To this register for activity result. you need to add dependencies.
Set compileSdk to 33
implementation("androidx.activity:activity-ktx:1.6.1")
implementation "androidx.fragment:fragment-ktx:1.5.4"
And now depending on the media type you want to choose, we can use different Request Types.
You can choose multiple files as well by passing the number of items you want to choose.
Step 4: Now, we will create an instance of MethodChannel and call the pickMedia method and passing media type you want to choose.
void _selectPhoto() async{
const MethodChannel shareMethodChannel = MethodChannel('photo_picker_method_channel');
String? result;
try {
result = await shareMethodChannel.invokeMethod('pickMedia',<String,String>{
'file_type': "image"
});
if (kDebugMode) {
print('picked photo path: $result');
}
setState(() {
pickedPhotoPath = result ?? '';
});
} on PlatformException catch (e) {
result = e.message;
}
}
Output:
Here, I am choosing only the image
Shaik Ahron
Hi, I am Shaik Ahron. I am enthusiastic about Mobile Development. I like to develop mobile apps.
See other articles by Shaik
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!