Search code examples
androidflutterandroid-contentproviderandroid-contextflutter-plugin

Android cursor doesn't work on a Flutter plugin with Android embedding v2


I use a plugin to get the absolute path of a file in Android, the helper class is this one..

The previous link is a fork from a Flutter plugin that return the absolute path of a photo in photo gallery with Flutter embedding V1 and work properly. The Uri is content://media/external/images/media/41.

And now I'm trying to adapt this to a plugin with Flutter Android embedding V2. The fork is here. As you can see here I call directly the helper with a hardcoded Uri:

FileDirectory.getAbsolutePath(context, Uri.parse("content://media/external/images/media/41"))

And at the helper class, that basically is a copy paste of the other plugin, the program return error on this piece of code:

private fun getDataColumn(context: Context, uri: Uri, selection: String?,
                              selectionArgs: Array<String>?): String? {
        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(column)

        try {
            cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
            if (cursor != null && cursor.moveToFirst()) {
                val column_index = cursor.getColumnIndexOrThrow(column)
                return cursor.getString(column_index)
            }
        } finally {
            cursor?.close()
        }
        return null
    }

This code above work correctly on the Flutter embedding V1 but not on the V2. After some dirty debugging, I get that:

For Flutter plugin with Android embedding V1:

context type equals to io.flutter.app.FlutterApplication

cursor!!.moveToFirst() is TRUE

cursor!!.getCount() is 1

For Flutter plugin with Android embedding V2:

context type equals to android.app.Application

cursor!!.moveToFirst() is FALSE

cursor!!.getCount() is 0

I supose that the problem is how the plugin get the application context, for the V1 is given by the Registrar:

    companion object {
        @JvmStatic
        fun registerWith(registrar: Registrar) {
            val channel = MethodChannel(registrar.messenger(), "flutter_absolute_path")
            channel.setMethodCallHandler(FlutterAbsolutePathPlugin(registrar.context()))
        }
    }

For the V2, instead, is given by the ActivityAware as shown in this answer:

    private fun doOnAttachedToEngine(messenger: BinaryMessenger) {
        methodChannel = MethodChannel(messenger, "flutter_file_dialog")
        methodChannel?.setMethodCallHandler(this)
        context = pluginBinding!!.applicationContext
    }

Another thing is that If I try to use the plugin with embeddingV1 in my app, I get the following error, so I can't use it.

 java.lang.RuntimeException: Unable to start activity ComponentInfo{net.altermundi.elrepoio/net.altermundi.elrepoio.MainActivity}: java.lang.IllegalStateException: registrar.context() must not be null

Solution

  • After cleaning the code to minimum I got this working. Probably something wrong in the Flutter embeddingv2 plugin, but using this it work.