android免root读写u盘最新方法,支持安卓Q+

android读写u盘支持安卓10以上的最新方法

本人是在写一个app需要读取u盘文件列表,网上找了好多方法,要不就是没有media权限,要不就是收不到广播,全部用不了,就这样搁置了一段时间终于又找到了一个大佬的方法,在这做个笔记

谷歌从Android5.0以上已经不支持开发者随便读写手机的外部存储(包含tf卡、otg外接u盘等),换句话说5.0以下我们还是可以直接读写usb设备的。

当你直接拿到u盘挂载路径,去操作的时候,File类已经读取不到任何东西,因为缺少了以下这个权限

 <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE"/>

当然如果你是root用户,也可以直接修改系统配置文件,/system/etc/permissions/platform.xml文件中有两组配置,其中

    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
        <group gid="media_rw" />
    </permission>

是u盘等外接媒体的权限,而

<permission name="android.permission.READ_EXTERNAL_STORAGE" />
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" />

这两组就是手机内置的外部存储,除了系统使用的内部存储,其他一切都是外部存储,所以读写u盘也需要用到他们,那要怎么改呢,从我了解下来,实际上大概样子就是如下

<permission name="android.permission.WRITE_EXTERNAL_STORAGE">
	<group gid="media_rw" />
	<group gid="sdcard_rw" />
</permission>

<permission name="android.permission.WRITE_MEDIA_STORAGE" >
    <group gid="media_rw" />
    <group gid="sdcard_rw" />
</permission>

当然没有root的用户看看就好了,接下来说说非root用户。

针对非root用户,有些比如ES文件浏览器,他们可以直接操作u盘,实际上是通过google的特定方法,SAF框架操作外置sd卡,也就是DocumentFile类,假如不用这个类,直接想操作,那只能向rom厂商申请系统签名,加入白名单,成为系统应用。

SAF框架,你只需要在AndroidManifest.xml加上,想了解可以去官网看看https://developer.android.com/guide/topics/providers/document-provider.html

<provider
    android:name="com.github.mjdev.libaums.storageprovider.UsbDocumentProvider"
    android:authorities="com.github.mjdev.libaums.storageprovider.documents"
    android:exported="true"
    android:grantUriPermissions="true"
    android:permission="android.permission.MANAGE_DOCUMENTS"
    android:enabled="@bool/isAtLeastKitKat">
    <intent-filter>
        <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
    </intent-filter>
</provider>

重点来了,废话不多说,以上的方法仅供了解,下面才是真正的开始,采用第三方框架 libaums

//https://github.com/magnusja/libaums
implementation 'me.jahnen.libaums:core:0.9.1'

具体实现如下:

/**
     * 动态注册监听USB设备的广播。
     * 由于耗电等原因,8.0不能对大部分的广播进行静态注册
     */
    private void registerUsbReceiver() {
    
    
        USBBroadCastReceiver usbBroadCastReceiver = new USBBroadCastReceiver(getActivity());

        usbBroadCastReceiver.setOnPermListener(new USBBroadCastReceiver.OnPermListener() {
    
    
            @Override
            public void onRemove() {
    
    
                updateUdiskView();
            }

            @Override
            public void onConnect() {
    
    
                updateUdiskView();
            }
        });

        IntentFilter filter = new IntentFilter(USBBroadCastReceiver.ACTION_USB_PERMISSION);
        filter.addAction("android.hardware.usb.action.USB_STATE");
        filter.addAction("android.hardware.usb.action.USB_DEVICE_ATTACHED");
        filter.addAction("android.hardware.usb.action.USB_DEVICE_DETACHED");
        getActivity().registerReceiver(usbBroadCastReceiver, filter);

        /**
         * 启动软件尝试读取u盘
         */
        usbBroadCastReceiver.redUDiskDeviceList();
    }
package com.zj.ruokeplayer.receive;

import static android.hardware.usb.UsbManager.ACTION_USB_DEVICE_ATTACHED;
import static android.hardware.usb.UsbManager.ACTION_USB_DEVICE_DETACHED;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.util.Log;

import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.zj.jplayercore.controller.JPlayer;
import com.zj.ruokeplayer.model.GlobalConstant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;

import me.jahnen.libaums.core.UsbMassStorageDevice;
import me.jahnen.libaums.core.fs.FileSystem;
import me.jahnen.libaums.core.fs.UsbFile;
import me.jahnen.libaums.core.fs.UsbFileStreamFactory;
import me.jahnen.libaums.core.partition.Partition;

/**
 * usb设备处理
 */
public class USBBroadCastReceiver extends BroadcastReceiver {
    
    

    public static final String ACTION_USB_PERMISSION = "com.android.rkplayer.USB_PERMISSION";
    private UsbMassStorageDevice[] storageDevices;
    private final String TAG = "rkplayer_usb";

    private Context context;
    private OnPermListener onPermListener;

    public USBBroadCastReceiver(Context context) {
    
    
        this.context = context;
    }

    public void setOnPermListener(OnPermListener onPermListener) {
    
    
        this.onPermListener = onPermListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String intentAction = intent.getAction();
        UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
        switch (intentAction) {
    
    
            case ACTION_USB_PERMISSION:
                //自定义Action
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
    
    
//                    LogUtils.i(TAG, "用户同意USB设备访问权限");
                    ToastUtils.showShort("您已同意USB设备访问");
                    readDevice(getUsbMass(device));
                } else {
    
    
//                    LogUtils.i(TAG, "用户拒绝USB设备访问权限");
                    ToastUtils.showShort("您已拒绝USB设备访问权限");
                    GlobalConstant.usbInited = false;
                    onPermListener.onRemove();
                }
                break;
            case ACTION_USB_DEVICE_ATTACHED:
//                LogUtils.i(TAG, "U盘设备插入");
                ToastUtils.showShort("U盘设备插入");
                if (device != null) {
    
    
                    redUDiskDeviceList();
                }
                break;
            case ACTION_USB_DEVICE_DETACHED:
                ToastUtils.showShort("U盘设备移除");
                GlobalConstant.usbInited = false;
                onPermListener.onRemove();
//                LogUtils.i(TAG, "U盘设备移除");
                break;
            default:
                //。。。
        }
    }

    /**
     * 获取存储设备
     * @param usbDevice 与android设备连接在一起的USB设备
     * @return Usb设备的一个包装类
     */
    private UsbMassStorageDevice getUsbMass(UsbDevice usbDevice) {
    
    
        for (UsbMassStorageDevice device : storageDevices) {
    
    
            if (usbDevice.equals(device.getUsbDevice())) {
    
    
                return device;
            }
        }
        return null;
    }

    /**
     * USB设备读取
     */
    public void redUDiskDeviceList() {
    
    
        //设备管理器
        UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        //获取U盘存储设备
        storageDevices = UsbMassStorageDevice.getMassStorageDevices(context);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
        //一般手机只有1个OTG插口
        if (storageDevices.length <= 0) {
    
    
            return;
        }
        UsbMassStorageDevice device = storageDevices[0];
        //读取设备是否有权限
        if (usbManager.hasPermission(device.getUsbDevice())) {
    
    
            readDevice(device);
        } else {
    
    
            //没有权限,进行申请
            usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
        }
    }

    /**
     * 初始化USB设备
     * @param device USB设备
     */
    private void readDevice(UsbMassStorageDevice device) {
    
    
        try {
    
    
            device.init();//初始化
            //设备分区
            Partition partition = device.getPartitions().get(0);
            //文件系统
            FileSystem currentFs = partition.getFileSystem();
            //可以获取到设备的标识
            currentFs.getVolumeLabel();
            //通过FileSystem可以获取当前U盘的一些存储信息,包括剩余空间大小,容量等等
            LogUtils.e("Volume Label: ", currentFs.getVolumeLabel());
            LogUtils.e("Capacity: ", fSize(currentFs.getCapacity()));
            LogUtils.e("Occupied Space: ", fSize(currentFs.getOccupiedSpace()));
            LogUtils.e("Free Space: ", fSize(currentFs.getFreeSpace()));
            LogUtils.e("Chunk size: ", fSize(currentFs.getChunkSize()));

            GlobalConstant.usbInited = true;
            readAndWrite(currentFs);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 格式化
     * @param sizeInByte
     * @return
     */
    public static String fSize(long sizeInByte) {
    
    
        if (sizeInByte < 1024) {
    
    
            return String.format("%s", sizeInByte);
        } else if (sizeInByte < 1024 * 1024) {
    
    
            return String.format(Locale.CANADA, "%.2fKB", sizeInByte / 1024.);
        } else if (sizeInByte < 1024 * 1024 * 1024) {
    
    
            return String.format(Locale.CANADA, "%.2fMB", sizeInByte / 1024. / 1024);
        } else {
    
    
            return String.format(Locale.CANADA, "%.2fGB", sizeInByte / 1024. / 1024 / 1024);
        }
    }

    /**
     * 读写文件
     *
     * @param currentFs
     */
    public void readAndWrite(FileSystem currentFs) {
    
    
        onPermListener.onConnect();
        try {
    
    
            //设置当前文件对象为根目录
            UsbFile usbFile = currentFs.getRootDirectory();
            UsbFile[] files = usbFile.listFiles();
            for (UsbFile file : files) {
    
    
                LogUtils.i(TAG,  file.getName());
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

    }

    /**
     * 回调
     * @param currentFs
     */
    public interface OnPermListener {
    
    
        public void onRemove();
        public void onConnect();
    }
}

应用中会唤起读取u盘的权限,基本就到这里结束了

猜你喜欢

转载自blog.csdn.net/Janix520/article/details/128012178