能否通过Content Provider发送Bitmap生成的文件而非assets目录下的文件?
实现方案
1. 运行时导出ImageView图片到应用私有目录
assets目录为只读路径,运行时生成的文件可以存储在应用内部缓存/私有文件目录,不需要申请存储权限,也能通过Content Provider正常暴露给外部应用。参考代码如下:
// 从ImageView获取Bitmap并存储到私有缓存目录 private File saveBitmapFromImageView(ImageView imageView, String identifier, String fileName) throws IOException { // 创建专门存储运行时生成图的目录 File generatedDir = new File(getContext().getCacheDir(), "generated_stickers/" + identifier); if (!generatedDir.exists()) { generatedDir.mkdirs(); } File outputFile = new File(generatedDir, fileName); // 获取ImageView渲染的Bitmap imageView.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(imageView.getDrawingCache()); imageView.setDrawingCacheEnabled(false); // 压缩写入文件,可按需调整格式、质量参数 try (FileOutputStream fos = new FileOutputStream(outputFile)) { bitmap.compress(Bitmap.CompressFormat.WEBP, 90, fos); fos.flush(); } bitmap.recycle(); return outputFile; }
2. 扩展Content Provider的Uri匹配规则
在现有UriMatcher中新增运行时生成资源的匹配规则,和原有assets资源做明确区分:
// 原有匹配规则保留,新增运行时资源匹配码和规则 private static final int GENERATED_STICKER_CODE = 3; static { // 示例规则:content://你的provider授权名/generated/贴纸包标识/文件名 MATCHER.addURI(AUTHORITY, "generated/*/*", GENERATED_STICKER_CODE); }
3. 修改Content Provider逻辑,支持两类资源返回
3.1 调整openAssetFile分支判断
@Nullable @Override public AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode) { final int matchCode = MATCHER.match(uri); if (matchCode == STICKERS_ASSET_CODE || matchCode == STICKER_PACK_TRAY_ICON_CODE) { return getImageAsset(uri); } else if (matchCode == GENERATED_STICKER_CODE) { return getGeneratedImageAsset(uri); } return null; }
3.2 新增运行时生成资源的读取逻辑
private AssetFileDescriptor getGeneratedImageAsset(Uri uri) { List<String> pathSegments = uri.getPathSegments(); String identifier = pathSegments.get(1); String fileName = pathSegments.get(2); // 先校验文件是否属于允许暴露的贴纸列表,避免任意文件泄露风险 if (!checkGeneratedStickerValid(identifier, fileName)) { throw new IllegalArgumentException("非法的生成文件请求:" + uri); } File targetFile = new File(getContext().getCacheDir(), "generated_stickers/" + identifier + "/" + fileName); try { ParcelFileDescriptor pfd = ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); return new AssetFileDescriptor(pfd, 0, targetFile.length()); } catch (IOException e) { Log.e(getContext().getPackageName(), "读取生成文件失败,uri:" + uri, e); return null; } } // 自定义校验逻辑,确保要返回的文件是你自己生成的合法贴纸 private boolean checkGeneratedStickerValid(String identifier, String fileName) { // 和原有assets贴纸校验逻辑对齐,遍历贴纸包判断即可 for (StickerPack stickerPack : getStickerPackList()) { if (identifier.equals(stickerPack.identifier)) { // 可给StickerPack/Sticker新增isGenerated字段标记是否为运行时生成 if (fileName.equals(stickerPack.trayImageFile) && stickerPack.isGenerated) { return true; } for (Sticker sticker : stickerPack.getStickers()) { if (fileName.equals(sticker.imageFileName) && sticker.isGenerated) { return true; } } } } return false; }
注意事项
- 生成的文件名建议做唯一标识,避免不同贴纸包重名覆盖
- 可以定期清理缓存目录下的过期生成文件,减少存储空间占用
- 对外分享时生成的Uri要对应新的规则:
content://[你的provider授权名]/generated/[贴纸包标识]/[文件名]
内容的提问来源于stack exchange,提问作者dalv5
相关产品推荐
相关产品推荐

