You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android设备获取USB存储设备广播及访问问题——MEDIA_MOUNTED Intent不触发的解决方案咨询

解决Android中MEDIA_MOUNTED广播无法触发的问题

你遇到的这个问题其实是Android系统版本迭代带来的权限和广播机制变化导致的——从**Android 7.0(API Level 24)**开始,系统彻底停止发送MEDIA_MOUNTEDMEDIA_UNMOUNTED这类隐式存储广播,而且静态注册的广播接收器也无法再接收这类广播。你的Moto G能正常工作,大概率是因为它运行的是Android 7.0以下的旧版本系统,而三星、小米等机型基本都是7.0+的系统,自然收不到这些广播。

下面给你几个可行的替代方案,适配新版本系统:


方案一:利用已收到的USB_DEVICE广播结合StorageManager处理

既然你已经能收到USB_DEVICE_ATTACHEDUSB_DEVICE_DETACHED广播,我们可以基于这个触发点,通过系统的StorageManager来获取USB存储设备的挂载状态和访问权限:

  1. 在广播接收器中处理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等
        }
    }
    
  2. 处理USB权限请求结果
    在你的Activity中重写onActivityResult(Android 10及以下)或者使用ActivityResultContracts(Android 11+),获取授权后的存储访问Uri,之后就可以通过SAF(Storage Access Framework)来操作USB设备里的文件了。


方案二:直接监听存储卷状态变化(更可靠)

如果不想依赖USB_DEVICE广播,可以直接使用StorageManagerregisterStorageVolumeCallback方法,监听所有存储卷的挂载/卸载事件:

  1. 在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);
        }
    }
    

额外注意事项

  1. 权限配置

    • 在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控制台说明应用用途,仅推荐文件管理器类应用使用。
  2. 厂商定制系统差异
    小米、三星等厂商的系统可能对USB存储有额外限制,比如需要手动在应用权限设置中开启「存储」权限,或者允许「访问所有文件」的权限,测试时记得检查这些设置。

  3. 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

火山引擎 最新活动