We're planting a tree for every job application! Click here to learn more

Using Android 13 Permissionless PhotoPicker in Flutter

Shaik Ahron

8 Dec 2022

2 min read

Using Android 13 Permissionless PhotoPicker in Flutter
  • Android

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

https://gfycat.com/immaculatecolorfullaughingthrush

Did you like this article?

Shaik Ahron

Hi, I am Shaik Ahron. I am enthusiastic about Mobile Development. I like to develop mobile apps.

See other articles by Shaik

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub