Android设备获取USB存储设备广播及访问问题——MEDIA_MOUNTED Intent不触发的解决方案咨询
你遇到的这个问题其实是Android系统版本迭代带来的权限和广播机制变化导致的——从**Android 7.0(API Level 24)**开始,系统彻底停止发送MEDIA_MOUNTED、MEDIA_UNMOUNTED这类隐式存储广播,而且静态注册的广播接收器也无法再接收这类广播。你的Moto G能正常工作,大概率是因为它运行的是Android 7.0以下的旧版本系统,而三星、小米等机型基本都是7.0+的系统,自然收不到这些广播。
下面给你几个可行的替代方案,适配新版本系统:
方案一:利用已收到的USB_DEVICE广播结合StorageManager处理
既然你已经能收到USB_DEVICE_ATTACHED和USB_DEVICE_DETACHED广播,我们可以基于这个触发点,通过系统的StorageManager来获取USB存储设备的挂载状态和访问权限:
在广播接收器中处理USB连接事件
当收到USB设备连接的广播时,通过StorageManager获取所有存储卷,筛选出可移除的非模拟卷(也就是USB设备),然后请求访问权限:@Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { // 获取StorageManager实例 StorageManager storageManager = context.getSystemService(StorageManager.class); List<StorageVolume> volumes = storageManager.getStorageVolumes(); for (StorageVolume volume : volumes) { // 筛选USB存储设备:可移除且非模拟 if (volume.isRemovable() && !volume.isEmulated()) { // 创建访问权限请求Intent Intent accessIntent = volume.createAccessIntent(null); if (accessIntent != null) { // 注意:这里需要在Activity中处理权限请求结果,所以要确保context是Activity实例 ((Activity) context).startActivityForResult(accessIntent, REQUEST_CODE_USB_ACCESS); } } } } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { // 处理USB设备卸载后的逻辑,比如清理缓存、更新UI等 } }处理USB权限请求结果
在你的Activity中重写onActivityResult(Android 10及以下)或者使用ActivityResultContracts(Android 11+),获取授权后的存储访问Uri,之后就可以通过SAF(Storage Access Framework)来操作USB设备里的文件了。
方案二:直接监听存储卷状态变化(更可靠)
如果不想依赖USB_DEVICE广播,可以直接使用StorageManager的registerStorageVolumeCallback方法,监听所有存储卷的挂载/卸载事件:
- 在Activity/Service中注册回调
private StorageManager storageManager; private StorageVolumeCallback volumeCallback; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); storageManager = getSystemService(StorageManager.class); // 初始化存储卷回调 volumeCallback = new StorageVolumeCallback() { @Override public void onStorageVolumeAdded(StorageVolume volume) { // 存储卷挂载时触发,处理USB设备 handleUsbStorage(volume); } @Override public void onStorageVolumeRemoved(StorageVolume volume) { // 存储卷卸载时触发,清理相关资源 } }; // 注册回调,使用主线程执行器确保UI操作安全 storageManager.registerStorageVolumeCallback(getMainExecutor(), volumeCallback); } private void handleUsbStorage(StorageVolume volume) { if (volume.isRemovable() && !volume.isEmulated()) { Intent accessIntent = volume.createAccessIntent(null); if (accessIntent != null) { startActivityForResult(accessIntent, REQUEST_CODE_USB_ACCESS); } } } @Override protected void onDestroy() { super.onDestroy(); // 记得销毁回调,避免内存泄漏 if (volumeCallback != null) { storageManager.unregisterStorageVolumeCallback(volumeCallback); } }
额外注意事项
权限配置:
- 在Manifest中添加基础存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> - 对于Android 10+,如果需要访问整个USB存储设备,可能需要申请
MANAGE_EXTERNAL_STORAGE权限,但这个权限需要在Google Play控制台说明应用用途,仅推荐文件管理器类应用使用。
- 在Manifest中添加基础存储权限:
厂商定制系统差异:
小米、三星等厂商的系统可能对USB存储有额外限制,比如需要手动在应用权限设置中开启「存储」权限,或者允许「访问所有文件」的权限,测试时记得检查这些设置。USB权限请求:
部分机型可能需要先请求USB设备的访问权限,你可以在USB_DEVICE_ATTACHED广播中添加权限请求逻辑:UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent("com.your.package.USB_PERMISSION"), 0); usbManager.requestPermission(usbDevice, permissionIntent);然后再监听这个自定义权限广播,确认授权后再处理存储访问。
内容的提问来源于stack exchange,提问作者Wandering Sovereign




