androidandroid-instant-appsdynamic-feature

How do you share images via an intent in an instant app?


We are building a quiz instant app, where the user can complete the quiz and then share their result. We share some text with a link, and also an image that shows the user's quiz result. There is no problem when we go through this flow in the installed app, however in the instant app, the image fails to share.

Here is how we generate the intent:

val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", image)
val shareIntent = Intent().apply {
    action = Intent.ACTION_SEND
    putExtra(Intent.EXTRA_TEXT, content)
    putExtra(Intent.EXTRA_STREAM, uri)
    type = "image/*"
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
activity?.startActivity(Intent.createChooser(shareIntent, getString(R.string.quiz_share_title)))

Here is the provider in our base application manifest:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/fileprovider" />
</provider>

When the user shares the image in the instant app, this error message appears in logcat:

java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.redacted.fileprovider/shared/1563809004297.png from pid=29184, uid=1000 requires the provider be exported, or grantUriPermission()

I have tried setting exported="true", and that crashes the instant app on startup with the following exception:

java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.SecurityException: Provider must not be exported

I'm guessing that instant apps can't use the FLAG_GRANT_READ_URI_PERMISSION flag, for the same reason that they can't use the WRITE_EXTERNAL_STORAGE permission.

Is there another way we can share images in instant apps?


Solution

  • An instant app can not have an exported ContentProvider. This is a security restriction and crashing the app here is working as intended.

    You could use InstantApps.showInstallPrompt() before firing the Intent in order to get users to install the app before doing this. Please make sure that you display a message containing your rationale or otherwise you might confuse your users.

    There are other ways to share images using instant apps. But these depend on where the image is coming from. In case of an external content provider (i.e. the Camera app's) you should be able to forward the URI.