Android 为什么分享图片时目标应用可以自由读取该图片

2022-05-11  本文已影响0人  雁过留声_泪落无痕

问题

当我们的应用在自身内部存储空寂那存储了一张图片后,想进行分享,为什么分享到第三方应用时,它可以自由读取该图片?

前提

使用了 FileProvider

解答

val uri = UtilsFileProvider.getUriForFile(this, "$packageName.utilcode.fileprovider", file)
var intent = Intent(Intent.ACTION_SEND)
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent = Intent.createChooser(intent, "")
startActivity(intent)

使用如上代码即可进行分享,但是我们并没有调用 Intent#addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),为什么也可以成功呢?

其实问题的关键就是 Intent.ACTION_SEND,通过在 'Intent#addFlags()' 方法打断点,可以发现,在 Intent#migrateExtraStreamToClipData() 方法中调用了 Intent#addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),如下:

public boolean migrateExtraStreamToClipData(Context context) {
    ...
    if (ACTION_CHOOSER.equals(action)) {
        ...
    } else if (ACTION_SEND.equals(action)) {
        try {
            final Uri stream = getParcelableExtra(EXTRA_STREAM);
            final CharSequence text = getCharSequenceExtra(EXTRA_TEXT);
            final String htmlText = getStringExtra(EXTRA_HTML_TEXT);
            if (stream != null || text != null || htmlText != null) {
                final ClipData clipData = new ClipData(
                        null, new String[] { getType() },
                        new ClipData.Item(text, htmlText, null, stream));
                setClipData(clipData);
                addFlags(FLAG_GRANT_READ_URI_PERMISSION);
                return true;
            }
        } catch (ClassCastException e) {
        }

    } else if (ACTION_SEND_MULTIPLE.equals(action)) {
        ...
    } else if (isImageCaptureIntent()) {
        ...
    }

    return false;
}

可以看到当 action 是 ACTION_SEND 时,自动添加了 FLAG_GRANT_READ_URI_PERMISSION 这个 flag,于是问题得到解答。

引申

我们想要三方应用往我们的目录里写文件时,可以添加 addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 调用即可。

比如想拍照并将照片存储在我们的私有目录,而不是先拍照再从图库里去获取图片,就可以:

val imgFile = File(filesDir, "tmp_camera_capture.jpg")
if (!imgFile.exists()) {
    imgFile.createNewFile()
}
// 通过FileProvider.getUriForFile创建文件的Uri
uri = FileProvider.getUriForFile(this, "xxx.fileprovider", imgFile)

Intent().apply {
    action = MediaStore.ACTION_IMAGE_CAPTURE
    putExtra(MediaStore.EXTRA_OUTPUT, uri)
    // 为目标应用赋予当前文件的读写权限
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    startActivityForResult(this, 1)
}

参考

上一篇 下一篇

猜你喜欢

热点阅读