Blankj / AndroidUtilCode

:fire: Android developers should collect the following utils(updating).
https://blankj.com/2016/07/31/android-utils-code/
Apache License 2.0
33.26k stars 10.68k forks source link

SDCardUtils下获取SD卡路径在Android 6.0以上存在兼容性问题 #125

Closed panden closed 6 years ago

panden commented 7 years ago

自己测试在三星 S7 Edge(Android 6.0)下,执行cat /proc/mounts,返回的数据里有包含sdcard的数据,但是里面不包含android_secure,但是手机是已经插入了外置SD卡的。因此使用你那种方法在这个手机上是无法正常获取到路径的;然而Environment.getExternalStorageDirectory().getPath() + File.separator返回的也不是正确的路径。推荐作者在6.0以上使用反射的方式去反射android.os.storage.DiskInfo判断存储设备的类型和反射android.os.storage.VolumeInfo.GetPath去获取其对应的路径。

panden commented 7 years ago

以下是在三星 S7 Edge(Android 6.0)下执行cat /proc/mounts后返回的数据: rootfs / rootfs ro,seclabel,size=1662316k,nr_inodes=415579 0 0 tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,size=1734720k,nr_inodes=433680,mode=755 0 0 devpts /dev/pts devpts rw,seclabel,relatime,mode=600 0 0 none /dev/cpuctl cgroup rw,relatime,cpu 0 0 adb /dev/usb-ffs/adb functionfs rw,relatime 0 0 proc /proc proc rw,relatime 0 0 sysfs /sys sysfs rw,seclabel,relatime 0 0 selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0 debugfs /sys/kernel/debug debugfs rw,seclabel,relatime 0 0 none /sys/fs/cgroup tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=750,gid=1000 0 0 none /acct cgroup rw,relatime,cpuacct 0 0 tmpfs /mnt tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=755,gid=1000 0 0 tmpfs /mnt/secure tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=700 0 0 tmpfs /mnt/secure/asec tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=700 0 0 /data/knox/tmp_sdcard /mnt/knox sdcardfs rw,seclabel,nosuid,nodev,relatime,mask=0077 0 0 /data/knox/sdcard /mnt/knox/default/knox-emulated sdcardfs rw,seclabel,nosuid,nodev,relatime,low_uid=1000,low_gid=1000,gid=9997,multi_user,mask=0006 0 0 /data/knox/sdcard /mnt/knox/read/knox-emulated sdcardfs rw,seclabel,nosuid,nodev,relatime,low_uid=1000,low_gid=1000,gid=9997,multi_user,mask=0027 0 0 /data/knox/sdcard /mnt/knox/write/knox-emulated sdcardfs rw,seclabel,nosuid,nodev,relatime,low_uid=1000,low_gid=1000,gid=9997,multi_user,mask=0007 0 0 /data/knox/secure_fs/enc_media /mnt/shell/enc_media sdcardfs rw,seclabel,nosuid,nodev,relatime,low_uid=1000,low_gid=1000,gid=9997,multi_user,reserved=20MB 0 0 /data/media /mnt/runtime/default/emulated sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=1015,multi_user,mask=0006,reserved=20MB 0 0 /data/media /mnt/runtime/read/emulated sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,multi_user,mask=0027,reserved=20MB 0 0 /data/media /mnt/runtime/write/emulated sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,multi_user,mask=0007,reserved=20MB 0 0 /dev/block/vold/public:179,1 /mnt/media_rw/5699-0226 vfat rw,dirsync,nosuid,nodev,noexec,noatime,nodiratime,uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=0020,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 /mnt/media_rw/5699-0226 /mnt/runtime/default/5699-0226 sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=1015,mask=0006 0 0 /mnt/media_rw/5699-0226 /mnt/runtime/read/5699-0226 sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,mask=0022 0 0 /mnt/media_rw/5699-0226 /mnt/runtime/write/5699-0226 sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,mask=0022 0 0 /mnt/shell/enc_media /mnt/shell/enc_emulated ecryptfs rw,seclabel,nodev,relatime,ecryptfs_fnek_sig=692023e47af0fd70,ecryptfs_sig=692023e47af0fd70,userid=0,sdp_enabled,partition_id=1,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_enable_cc,ecryptfs_passthrough,base=,label= 0 0 /dev/block/dm-0 /system ext4 ro,seclabel,relatime,norecovery 0 0 /dev/block/bootdevice/by-name/efs /efs ext4 rw,seclabel,nosuid,nodev,noatime,discard,journal_checksum,journal_async_commit,noauto_da_alloc,data=ordered 0 0 /dev/block/bootdevice/by-name/cache /cache ext4 rw,seclabel,nosuid,nodev,noatime,discard,journal_checksum,journal_async_commit,noauto_da_alloc,data=ordered 0 0 /dev/block/bootdevice/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,noatime,discard,journal_checksum,journal_async_commit,noauto_da_alloc,data=ordered 0 0 /dev/block/bootdevice/by-name/dsp /dsp ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0 /dev/block/bootdevice/by-name/apnhlos /firmware vfat ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,gid=1000,fmask=0337,dmask=0227,codepage=437,iocharset=iso8859-1,shortname=lower,errors=remount-ro 0 0 /dev/block/bootdevice/by-name/modem /firmware-modem vfat ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,gid=1000,fmask=0337,dmask=0227,codepage=437,iocharset=iso8859-1,shortname=lower,errors=remount-ro 0 0 /dev/block/bootdevice/by-name/persdata /persdata/absolute ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0 /dev/block/dm-1 /data ext4 rw,seclabel,nosuid,nodev,noatime,discard,journal_checksum,journal_async_commit,noauto_da_alloc,debug_bdinfo,data=ordered 0 0 /data/knox/secure_fs/enc_user /data/enc_user ecryptfs rw,seclabel,nodev,relatime,ecryptfs_fnek_sig=692023e47af0fd70,ecryptfs_sig=692023e47af0fd70,userid=0,sdp_enabled,partition_id=0,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_enable_cc,ecryptfs_passthrough,base=,label= 0 0 tmpfs /storage tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=755,gid=1000 0 0 /data/media /storage/emulated sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,multi_user,mask=0007,reserved=20MB 0 0 /mnt/media_rw/5699-0226 /storage/5699-0226 sdcardfs rw,seclabel,nosuid,nodev,noexec,relatime,low_uid=1023,low_gid=1023,gid=9997,mask=0022 0 0 tmpfs /storage/self tmpfs rw,seclabel,relatime,size=1734720k,nr_inodes=433680,mode=755,gid=1000 0 0

Blankj commented 7 years ago

6.0还没完善呢,之后会完善的

panden commented 7 years ago

这个是自己用过的一个在Android 6.0以上去获取路径的代码,作者可以参考下; `//API 23 Android 6.0 获取外置SD卡和USB设备的路径,能获取外置和usb设备的路径 private String getStoragePath23(Context context, boolean isUsb){

    String path="";

    if(Build.VERSION.SDK_INT<23)return path;

    StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
    Class<?> volumeInfoClazz=null;
    Class<?> diskInfoClaszz=null;

    try {
        volumeInfoClazz = Class.forName("android.os.storage.VolumeInfo");
        diskInfoClaszz = Class.forName("android.os.storage.DiskInfo");

        Method StorageManager_getVolumes=Class.forName("android.os.storage.StorageManager").getMethod("getVolumes");
        Method VolumeInfo_GetDisk = volumeInfoClazz.getMethod("getDisk");
        Method VolumeInfo_GetPath = volumeInfoClazz.getMethod("getPath");
        Method DiskInfo_IsUsb = diskInfoClaszz.getMethod("isUsb");
        Method DiskInfo_IsSd = diskInfoClaszz.getMethod("isSd");

        List<Object> List_VolumeInfo = (List<Object>) StorageManager_getVolumes.invoke(mStorageManager);
        for(int i=0; i<List_VolumeInfo.size(); i++){
            Object volumeInfo = List_VolumeInfo.get(i);
            Object diskInfo = VolumeInfo_GetDisk.invoke(volumeInfo);

            if(diskInfo==null)continue;

            boolean sd= (boolean) DiskInfo_IsSd.invoke(diskInfo);
            boolean usb= (boolean) DiskInfo_IsUsb.invoke(diskInfo);

            File file= (File) VolumeInfo_GetPath.invoke(volumeInfo);
           // Logger.d("diskinfo="+file.getAbsolutePath()+"; is_usb="+usb+";  is_sd="+sd);

            if(isUsb == usb){//usb
                path=file.getAbsolutePath();
                break;
            }else if(!isUsb == sd){//sd
                path=file.getAbsolutePath();
                break;
            }

        }

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return path;
}`
Blankj commented 7 years ago

:+1:

wanghc0 commented 7 years ago

已经加上去了吗? 怎么使用呢?

moter commented 7 years ago

@panden 你的这个方法也存在局限性,在小米6.0系统上亲测不适用。我参考了很多大神的,现在用的方法如下 public static List getExtSDCardPath(Context context) { StorageManager storageManager = (StorageManager) context.getSystemService(Context .STORAGE_SERVICE); ArrayList paths = new ArrayList(); String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath(); try { Class<?>[] paramClasses = {}; Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", paramClasses); getVolumePathsMethod.setAccessible(true); Object[] params = {}; Object invoke = getVolumePathsMethod.invoke(storageManager, params); paths = new ArrayList(Arrays.asList((String[]) invoke)); } catch (NoSuchMethodException e1) { e1.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } if (!paths.contains(rootPath)) paths.add(0, rootPath); return paths; }