华为P20 Android设备OBB挂载失败,调用getFile方法触发重启求助
我之前处理华为设备OBB挂载问题时,刚好遇到过P20机型的类似状况,结合你的代码和问题描述,整理了几个关键的排查方向和修复建议:
1. 先明确状态码21的含义
状态码21对应OBB_ERROR_PERMISSION_DENIED(权限被拒绝),但华为P20的权限限制比常规机型更严格,不一定只是基础存储权限问题,还要检查你的调用参数是否符合系统要求。
2. 修复OBB路径的错误处理
你的代码里有一段多余的路径处理逻辑:
if (strMainPath != null && strMainPath.startsWith("/")) { strMainPath = strMainPath.substring(1); }
这会把正确的绝对路径(比如/storage/emulated/0/Android/obb/com.your.package/main.44.com.your.package.obb)改成相对路径,导致系统找不到OBB文件,进而触发权限错误。直接删除这段代码即可,Environment.getExternalStorageDirectory()返回的是标准外部存储根路径,拼接后的绝对路径完全符合系统要求。
3. 修正OBB挂载的密码参数
在mount()方法中,你传入了"AppName"作为密码:
storageManager.mountObb(strMainPath, "AppName", mListener);
如果你的OBB文件没有加密,这里必须传null而不是任意字符串!华为设备对OBB加密验证的逻辑更严格,错误的密码参数会直接导致挂载失败,甚至触发系统服务异常引发重启。修改后代码:
storageManager.mountObb(strMainPath, null, mListener);
4. 完善权限适配逻辑
华为P20的隐私权限体系有特殊处理,除了常规的READ_EXTERNAL_STORAGE动态权限:
- 如果你的App目标SDK≥30(Android 11+),还需要申请
MANAGE_EXTERNAL_STORAGE权限(即“访问所有文件”权限),否则无法正常访问OBB目录。 - 在调用
mount()之前,一定要先检查权限是否已获取,避免无权限情况下调用系统服务导致异常。示例代码:
public void mount() { // 检查基础存储权限 if (ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "缺少存储权限,无法挂载OBB"); // 这里需要在Activity中处理权限请求,建议通过回调或通知触发 return; } // Android 11+ 额外检查全文件访问权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { Log.w(TAG, "需要获取访问所有文件权限"); Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + ctx.getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ctx.startActivity(intent); return; } final StorageManager storageManager = (StorageManager) ctx.getSystemService(Context.STORAGE_SERVICE); String packageName = ctx.getPackageName(); File root = Environment.getExternalStorageDirectory(); File expPath = new File(root.toString() + EXP_PATH + packageName); String strMainPath = expPath + File.separator + "main." + version + "." + packageName + ".obb"; // 先检查是否已挂载,避免重复请求 if (storageManager.isObbMounted(strMainPath)) { Log.i(TAG, "OBB已挂载,无需重复操作"); return; } storageManager.mountObb(strMainPath, null, mListener); }
5. 避免触发系统重启的循环操作
你的getFile()方法在OBB未挂载时会调用mount(),但如果挂载失败(比如权限问题),后续的调用会重复触发挂载请求,频繁调用系统服务可能导致华为P20的ROM触发崩溃重启。建议在ObbStateChangeListener中处理失败状态,避免重复请求:
private OnObbStateChangeListener mListener = new OnObbStateChangeListener() { @Override public void onObbStateChange(String path, int state) { super.onObbStateChange(path, state); if (state == MOUNTED) { Intent intent = new Intent(); intent.setAction(ACTION_MOUNT); LocalBroadcastManager.getInstance(ctx).sendBroadcast(intent); } else { Log.e(TAG, "OBB挂载失败,状态码:" + state); // 根据状态码给出用户提示,比如状态21提示权限问题 if (state == OBB_ERROR_PERMISSION_DENIED) { // 触发权限申请逻辑 } } } };
总结
华为P20的定制ROM在OBB挂载的参数校验和权限控制上比其他机型更严格,优先修复路径处理和密码参数这两个明显的代码问题,再完善权限检查逻辑,应该就能解决挂载失败和设备重启的问题。
内容的提问来源于stack exchange,提问作者SamSB

