How to grant temporary access to custom content provider using FLAG_GRANT_READ_URI_PERMISSION

99封情书 提交于 2019-11-30 09:16:13

It seems that FLAG_GRANT_READ_URI_PERMISSION affects only Uri Intent.mData but not uris in extras.

I found similar problems when playing with ACTION_SEND, which takes an uri in EXTRA_STREAM. Providing the same uri in setData() will work, but doesn't conform to the rules and leads to unexpected behavior (e.g. Gmail recipient).

As of Jelly Bean intents can contain ClipData, which should solve the problem. For ACTION_SEND it's generated automatically from extras.

grantUriPermission will work, but requires revokeUriPermission. To do the same job as startActivity(Intent.createChooser(intent, title)) you will have to pick the target (ACTION_PICK_ACTIVITY), grant permissions to its package and revoke them when not needed anymore (onActivityResult?).

Here's some code:

Receiver app:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.handler" >

    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        …
        <activity
            android:name=".ActivityView"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="android.intent.action.SEND"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="*/*"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

ActivityView.java:

protected void onCreate(Bundle savedInstanceState) {
    Intent intent = getIntent();
    if ((intent != null)) {
        procUri(intent.getData());
        procUri(intent.<Uri>getParcelableExtra(Intent.EXTRA_STREAM));
    }
}

private void procUri(Uri uri) {
    if (uri != null) {
        InputStream i;
        try {
            i = getContentResolver().openInputStream(uri);
            byte[] b = new byte[i.available()];
            i.read(b);
            …
        } catch (Throwable e) {
            …
        }
    }
}

Sender app:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sender" >

    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        …
        <activity
            android:name=".ActivitySend"
            android:label="@string/app_name" >
        </activity>
        <provider
            android:name=".MyContentProvider"
            android:authorities="com.example.sender.content"
            android:enabled="true"
            android:exported="false"
            android:grantUriPermissions="true" >
        </provider>
    </application>
</manifest>

ActivitySend.java:

// OK!
private void doTestView(Uri uri, String type) {
    startActivity(
            new Intent(Intent.ACTION_VIEW)
                .setDataAndType(uri, type)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        );
}

// error prior to JellyBean
// ok on JellyBean, even without explicit FLAG_GRANT_READ_URI_PERMISSION (due to generated ClipData)
private void doTestSend(Uri uri, String type, CharSequence title) {
    startActivity(
            Intent.createChooser(
                new Intent(Intent.ACTION_SEND)
                    .setType(type)
                    .putExtra(Intent.EXTRA_STREAM, uri)
                    .putExtra(Intent.EXTRA_SUBJECT, title)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                ,
                title
            )
        );
}

// working but not ok, unexpected results!
private void doTestSend2(Uri uri, String type, CharSequence title) {
    startActivity(
            Intent.createChooser(
                new Intent(Intent.ACTION_SEND)
                    .setDataAndType(uri, type)
                    .putExtra(Intent.EXTRA_STREAM, uri)
                    .putExtra(Intent.EXTRA_SUBJECT, title)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                ,
                title
            )
        );
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!