You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

存储图片URI后跳转ThirdActivity触发SecurityException问题求助

问题分析与解决方案

问题根源

  1. 通过ACTION_PICK获取的媒体URI仅拥有临时访问权限,权限仅在获取它的SecondActivity生命周期内有效,ThirdActivity直接读取该URI会触发权限异常。
  2. 你添加的FLAG_GRANT_READ_URI_PERMISSION未绑定具体URI,且未将URI传递给ThirdActivity,权限授予逻辑无效。
  3. 直接持久化存储URI字符串不可靠,临时权限重启后会失效,无法跨生命周期或跨Activity复用。

解决方案一:跨Activity临时传递URI(适合单次跳转场景)

1. 修改SecondActivity跳转逻辑

读取存储的URI,传递给ThirdActivity并正确授予权限:

// SecondActivity.java
Button showPickedButton = findViewById(R.id.showPickedButton);
showPickedButton.setOnClickListener(view -> {
    String uriStr = "";
    // 读取存储的URI字符串
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("uri"), StandardCharsets.UTF_8))) {
        uriStr = reader.readLine();
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (!uriStr.isEmpty()) {
        Uri imageUri = Uri.parse(uriStr);
        Intent thirdIntent = new Intent(SecondActivity.this, ThirdActivity.class);
        // 将URI放入Intent传递
        thirdIntent.setData(imageUri);
        // 授予ThirdActivity该URI的读取权限
        thirdIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        // 兜底:显式授予权限,避免flag失效
        grantUriPermission(getPackageName(), imageUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity(thirdIntent);
    }
});

2. 修改ThirdActivity读取逻辑

直接从Intent获取URI,无需读取文件:

// ThirdActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_third);

    LinearLayout imagesList = findViewById(R.id.imagesList);
    Uri imageUri = getIntent().getData();
    if (imageUri != null) {
        ImageView imageView = new ImageView(this);
        imageView.setImageURI(imageUri);
        imageView.setAdjustViewBounds(true);
        imageView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        imagesList.addView(imageView);
    }
}

解决方案二:持久化URI权限(适合长期复用场景)

如果需要保存URI并在后续启动、跨Activity时复用,需申请持久化权限,步骤如下:

1. 修改打开图库的Intent

用ACTION_OPEN_DOCUMENT替代ACTION_PICK,该Action支持持久权限申请:

// SecondActivity.java
openGalleryButton.setOnClickListener(view -> {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.setType("image/*");
    intent.addCategory(Intent.CATEGORY_OPENABLE); // 指定可打开的文件类型
    activityResultLauncher.launch(intent);
});

2. 修改ActivityResultLauncher逻辑,申请持久权限

获取URI后,调用takePersistableUriPermission获取持久访问权限:

ActivityResultLauncher<Intent> activityResultLauncher =
    registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            Intent data = result.getData();
            if (data != null) {
                Uri imageUri = data.getData();
                galleryImage.setImageURI(imageUri);

                if (imageUri != null) {
                    // 获取Intent中的权限flag
                    int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    // 申请持久化权限
                    getContentResolver().takePersistableUriPermission(imageUri, takeFlags);
                }

                // 保存URI到文件
                try {
                    openFileOutput("uri", MODE_PRIVATE).write((imageUri + "\n").getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    });

3. ThirdActivity原逻辑无需修改(持久权限已生效)

此时ThirdActivity读取存储的URI字符串并加载图片,不会触发权限异常。


注意事项

  • 持久化权限仅当用户主动选择文件时才能申请,无法自动获取;
  • 若用户删除文件或在系统设置中撤销应用权限,持久权限会失效,需添加异常捕获逻辑;
  • ACTION_OPEN_DOCUMENT仅支持Android 4.4(API 19)及以上版本。

内容的提问来源于stack exchange,提问作者Alex Cai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:55:27