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

Android应用下载图片代码模拟器正常但打包APK后失效如何解决?

问题诱发原因

  • 权限适配缺失:模拟器通常运行低版本Android系统(API<23)无需动态申请存储权限,而用户真机普遍运行Android 6.0及以上版本,存储权限属于危险权限,仅在AndroidManifest静态声明不生效;同时Android 10及以上版本引入分区存储机制,原有旧API调用会被限制。
  • 资源混淆/收缩:打包release版APK时默认会开启资源混淆、未使用资源收缩逻辑,你通过字符串拼接"bild"+counter动态查找drawable资源的方式,会被打包工具判定为资源未被直接引用,要么被删除要么资源名被混淆,导致getIdentifier返回0,最终拿不到Bitmap。
  • 异常逻辑缺失:MediaStore.Images.Media.insertImage执行失败时会返回null,代码未做判空直接解析Uri会触发崩溃,且无法感知执行失败原因。

修复方案

1. 权限适配

首先在AndroidManifest.xml中声明对应权限:

<!-- 安卓9及以下存储写入权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<!-- 安卓13及以上读取媒体图片权限(如果后续需要读取自己保存的图片可加) -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />

在触发下载逻辑前,先对Android 6.0-Android 9的设备动态申请WRITE_EXTERNAL_STORAGE权限,拿到权限后再执行保存逻辑。

2. 防资源收缩/混淆配置

在proguard-rules.pro中添加规则,防止R类的drawable资源被混淆:

-keep class 你的应用包名.R$drawable {
    public static final int bild*;
}

在模块级build.gradle的android闭包中添加规则,保留bild开头的drawable资源不被收缩:

android {
    buildTypes {
        release {
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            // 保留目标资源
            resValue "string", "keep_bild_res", "@drawable/bild*"
        }
    }
}

3. 兼容分区存储的保存逻辑替换

废弃已过时的insertImage方法,适配全版本系统的保存逻辑示例如下:

public void download (View view) {
    // 先校验权限再执行后续逻辑,此处省略权限判断代码
    int resId = getResources().getIdentifier("bild" + counter, "drawable", getPackageName());
    if (resId == 0) {
        Toast.makeText(MainActivity.this, "资源不存在", Toast.LENGTH_LONG).show();
        return;
    }
    Drawable drawable = getResources().getDrawable(resId);
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "bild" + counter);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    // 安卓10及以上指定存储路径
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
        values.put(MediaStore.Images.Media.IS_PENDING, 1);
    }
    
    ContentResolver resolver = getContentResolver();
    Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    if (uri == null) {
        Toast.makeText(MainActivity.this, "保存失败", Toast.LENGTH_LONG).show();
        return;
    }
    try {
        OutputStream outputStream = resolver.openOutputStream(uri);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.close();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            values.clear();
            values.put(MediaStore.Images.Media.IS_PENDING, 0);
            resolver.update(uri, values, null, null);
        }
        Toast.makeText(MainActivity.this, "Image Saved Successfully", Toast.LENGTH_LONG).show();
    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(MainActivity.this, "保存失败:" + e.getMessage(), Toast.LENGTH_LONG).show();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 15:18:01