Diego Perez
Diego Perez

Reputation: 2862

Kotlin: java.lang.IllegalArgumentException: Couldn't find meta-data for provider with authority xxx

My app includes the classic "Share This App" menu option, which takes two screenshots and send them by mail along with a promotional text.

It was working fine before migrating from Java to Kotlin, but now in Kotlin it started to throw an exception.

The weird thing is that even the exception (which can be seen in logcat) the process is working fine, the app is not crashing (at least not in a visible way) and the share process is done, for example, if you choose email the email is received along with the images.

Manifest.xml

<provider
    android:name=".helpers.GenericFileProvider"
    android:authorities="${applicationId}.GenericFileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

GenericFileProvider:

package com.xxx.xxx.helpers

import androidx.core.content.FileProvider

class GenericFileProvider : FileProvider()

provider_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path name="cache" path="."/>
</paths>

shareFile:

@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
    try {
        val share = Intent(Intent.ACTION_SEND_MULTIPLE)
        share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        share.type = fileType
        val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
        share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
        share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
        share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
        activity!!.get()!!.startActivity(
            Intent.createChooser(
                share,
                getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
            )
        )
    } catch (ex: Exception) {
        Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
    }
}

onImageProcessingFinished:

fun onImageProcessingFinished(ipr: ImageProcessingResult, activity: Activity) {
    val uris = ArrayList<Uri?>()
    for (file in ipr.screenShotFiles) {
        val uri = FileProvider.getUriForFile(activity,  activity.packageName + ".GenericFileProvider", file)
        if (uri!=null) uris.add(uri)
    }
    AWDrawerMenu.listener = activity as IActionListeners
    AWDrawerMenu.activity = WeakReference(activity)
    AWDrawerMenu.shareFile(uris, "image/jpg")
}

Exception:

2022-06-16 22:01:08.427 11357-11378/com.xxx.xxx E/DatabaseUtils: Writing exception to parcel
    java.lang.SecurityException: Permission Denial: reading com.xxx.xxx.helpers.GenericFileProvider uri content://com.xxx.xxx.GenericFileProvider/cache/xxx.jpg from pid=6474, uid=1000 requires the provider be exported, or grantUriPermission()
        at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:820)
        at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:684)
        at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:674)
        at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:548)
        at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:327)
        at android.os.Binder.execTransactInternal(Binder.java:1154)
        at android.os.Binder.execTransact(Binder.java:1123)

Edit 1:

If I replace the onImageProcessingFinished method by this next

fun onImageProcessingFinished(ipr: ImageProcessingResult, activity: Activity) {
    val uris = ArrayList<Uri?>()
    for (file in ipr.screenShotFiles) {
        val uri = FileProvider.getUriForFile(activity,  activity.packageName + ".helpers.GenericFileProvider", file)
        if (uri!=null) uris.add(uri)
    }
    AWDrawerMenu.listener = activity as IActionListeners
    AWDrawerMenu.activity = WeakReference(activity)
    AWDrawerMenu.shareFile(uris, "image/jpg")
}

adding the .helpers before GenericFileProvider (which in the end is the complete package name for the GenericFileProvider), then the following exception is thrown (an in this case the app DO crashes):

2022-06-16 21:48:10.203 10694-10694/com.xxx.xxx E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xxx.xxx, PID: 10694
    java.lang.IllegalArgumentException: Couldn't find meta-data for provider with authority com.xxx.xxx.helpers.GenericFileProvider
        at androidx.core.content.FileProvider.parsePathStrategy(FileProvider.java:662)
        at androidx.core.content.FileProvider.getPathStrategy(FileProvider.java:635)
        at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:441)
        at com.xxx.xxx.component.drawer.AWDrawer$Companion.onImageProcessingFinished(AWDrawer.kt:294)
        at com.xxx.xxx.activities.main.MainActivity.onImageProcessingFinished(MainActivity.kt:448)
        at com.xxx.xxx.activities.main.MainActivity.onShareThisApp$lambda-6(MainActivity.kt:443)
        at com.xxx.xxx.activities.main.MainActivity.$r8$lambda$c-xNLWLGog-3ah1DvHN4y6HCHsw(Unknown Source:0)
        at com.xxx.xxx.activities.main.MainActivity$$ExternalSyntheticLambda3.onComplete(Unknown Source:4)
        at com.xxx.xxx.helpers.TaskRunner.executeAsync$lambda-1$lambda-0(TaskRunner.kt:24)
        at com.xxx.xxx.helpers.TaskRunner.$r8$lambda$ItjAcdIefpXj05LbTtje15JKSPM(Unknown Source:0)
        at com.xxx.xxx.helpers.TaskRunner$$ExternalSyntheticLambda0.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

Upvotes: 0

Views: 1381

Answers (2)

Anderson Paiva
Anderson Paiva

Reputation: 978

I had this issue with @Transactional and managed to fix it by using open class instead of just class

Upvotes: 0

Diego Perez
Diego Perez

Reputation: 2862

I ended finding out I was having the exact same problem as described here:

Permission Denial while sharing file with FileProvider

And luckily the exact same solution worked for me.

I had to replace this:

@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
    try {
        val share = Intent(Intent.ACTION_SEND_MULTIPLE)
        share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        share.type = fileType
        val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
        share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
        share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
        share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
        activity!!.get()!!.startActivity(
            Intent.createChooser(
                share,
                getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
            )
        )
        activity!!.get()!!.startActivity(share)
    } catch (ex: Exception) {
        Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
    }
}

by this:

@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
    try {
        val share = Intent(Intent.ACTION_SEND_MULTIPLE)
        share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        share.type = fileType
        val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
        share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
        share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
        share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
        /*activity!!.get()!!.startActivity(
            Intent.createChooser(
                share,
                getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
            )
        )*/
        activity!!.get()!!.startActivity(share)
    } catch (ex: Exception) {
        Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
    }
}

The chooser looks a little bit different (don't know why), but it works.

Edit 1:

OK, the final working code:

@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
    try {
        val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
        val strMessage = getStringResourceByName("mainmenu_sharethisapp_message")
        val intent = Intent()
        intent.type = fileType
        intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        intent.putExtra(Intent.EXTRA_SUBJECT, strSubject)
        intent.putExtra(Intent.EXTRA_TEXT, strMessage)

        if (uris!!.size == 0) {
            return
        } else if (uris.size == 1) {
            val uri = uris[0]!!
            intent.action = Intent.ACTION_SEND
            intent.putExtra(Intent.EXTRA_STREAM, uri)
            intent.clipData = ClipData.newRawUri("", uri)
        } else {
            intent.action = Intent.ACTION_SEND_MULTIPLE
            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
            val clipData = ClipData.newRawUri("", uris[0])
            for (i in 1 until uris.size) {
                val uri = uris[i]!!
                clipData.addItem(ClipData.Item(uri))
            }
            intent.clipData = clipData
        }

        activity!!.get()!!.startActivity(
            Intent.createChooser(
                intent, getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
            )
        )
    } catch (ex: Exception) {
        Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
    }
}

Upvotes: 0

Related Questions