Android USB写入数据失败(EACCES (Permission denied))

最近接到一个问题反馈,一个几年前的APP,之前USB热插拔读写备份正常,现在居然不能正常备份。log中显示:

System.err: java.io.IOException: open failed: EACCES (Permission denied)

但确认权限都有,targetSdkVersion为22,因此不存在动态申请权限的问题。之后用同样的APP在低版本手机上测试正常(有些是需要手动打开OTG)。后来搜索网上文章指出:Android 6.0以后,就算添加权限,也不能成功操作USB。进一步测试发现:在高版本手机,只是不能正常创建文件夹,如果手动创建了路径,还是能正常读写文件,因此本文只需采用第三方库创建文件路径,其他代码不用改变。

引入第三方库:

api 'com.github.mjdev:libaums:0.5.5'

在Service中初始化监听USB插拔广播:

IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MEDIA_CHECKING");
filter.addAction("android.intent.action.MEDIA_MOUNTED");
filter.addAction("android.intent.action.MEDIA_EJECT");
filter.addAction("android.intent.action.MEDIA_REMOVED");
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addDataScheme("file");

当MEDIA_MOUNTED时,可通过Android版本或者File路径创建是否成功,判断是否需要采用第三方库来创建路径:

private void readDeviceList() {
        Log.i(TAG, "开始读取设备列表...");
        //获取存储设备
        storageDevices = UsbMassStorageDevice.getMassStorageDevices(this);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        for (UsbMassStorageDevice device : storageDevices) {
            //可能有几个 一般只有一个 因为大部分手机只有1个otg插口
            if (usbManager.hasPermission(device.getUsbDevice())) {
                //有就直接读取设备是否有权限
                Log.i(TAG, "检测到有权限,直接读取");
                AppSession.getInstance().isHostMode = true;
                readDevice(device);
            } else {//没有就去发起意图申请
                Log.i(TAG, "检测到设备,但是没有权限,进行申请");
                usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
                //该代码执行后,系统弹出一个对话框,
            }
        }
        if (storageDevices.length == 0) {
            AppSession.getInstance().isHostMode = false;
            Log.i(TAG, "未检测到有任何存储设备插入");
        }
    }

    private void readDevice(UsbMassStorageDevice device) {
        // before interacting with a device you need to call init()!
        try {
            device.init();//初始化
            //Only uses the first partition on the device
            Partition partition = device.getPartitions().get(0);
            FileSystem currentFs = partition.getFileSystem();
            //fileSystem.getVolumeLabel()可以获取到设备的标识
            //通过FileSystem可以获取当前U盘的一些存储信息,包括剩余空间大小,容量等等
            UsbFile root = currentFs.getRootDirectory();//获取根目录
            String deviceName = currentFs.getVolumeLabel();//获取设备标签
            Log.i(TAG, "正在读取U盘" + deviceName);
            cFolder = root;//设置当前文件对象
            createDir(device);

        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG,"读取失败,异常:" + e.getMessage());
        }
    }

    private void createDir(UsbMassStorageDevice device) throws IOException {
        String localPath = ConfigManager.getInstance().getConfig().getLocalpath();
        if(localPath.startsWith("/")){
            localPath = localPath.substring(1);
        }

        if(localPath.endsWith("/")){
            localPath = localPath.substring(0, localPath.length()-1);
        }
        String[] dirs =  localPath.split("/");
        if(dirs == null){
            return;
        }


        UsbFile tmpFile;
        for (int i = 0; i < dirs.length; i++ ){
            tmpFile = cFolder.search(dirs[i]);
            if(tmpFile == null){
                cFolder = cFolder.createDirectory(dirs[i]);
            }else {
                cFolder = tmpFile;
            }
        }

        device.close();
    }

 

 

 

 

参考文档:

1、https://developer.android.google.cn/guide/topics/connectivity/usb/host

2、https://github.com/magnusja/libaums

3、https://blog.csdn.net/csdn635406113/article/details/70146041

4、https://blog.csdn.net/weixin_40550094/article/details/80976081

你可能感兴趣的:(Android)