Android手机外置SD卡路径

需求

由于公司的项目里有个视频下载的功能,而且这个是产品比较重要的功能。但是,由于众所周知的原因,通过传统方式获取的SD卡路径,在不同厂商的设备上都不准确,可能SD卡和内存存储介质倒置了,也可能获取出来的路径无法读写。就算是相同厂商不同的产品,获取出来的SD卡路径和内置存储路径都是五花八门。
网上到处找资料,还是没法完全解决上述问题,连有些主流的机型都无法覆盖。经过一段时间探索,算是解决了问题。

解决了部分乱七八糟的厂商SD卡路径乱放导致无法读取的问题
参考:https://zh.wikipedia.org/wiki/UPnP

直接上源码

将StorageUtils和StorageBean代码copy到自己的工程。

ArrayList storageDatas = StorageUtils.getStorageData(this);//获取所有存储介质
//遍历storageDatas,得到StorageBean

//是否可移除,是则是外置存储,USB或SD卡
storageData.getRemovable();

//是否已挂载
storageData.getMounted().equalsIgnoreCase("mounted");

//获取此存储介质的真实路径
storageData.getPath();

主要是利用反射获取每个存储介质的StorageVolume及其属性

public static ArrayList getStorageData(Context pContext) {
        final StorageManager storageManager = (StorageManager) pContext.getSystemService(Context.STORAGE_SERVICE);
        try {
            //得到StorageManager中的getVolumeList()方法的对象
            final Method getVolumeList = storageManager.getClass().getMethod("getVolumeList");
            //---------------------------------------------------------------------

            //得到StorageVolume类的对象
            final Class storageValumeClazz = Class.forName("android.os.storage.StorageVolume");
            //---------------------------------------------------------------------
            //获得StorageVolume中的一些方法
            final Method getPath = storageValumeClazz.getMethod("getPath");
            Method isRemovable = storageValumeClazz.getMethod("isRemovable");

            Method mGetState = null;
            //getState 方法是在4.4_r1之后的版本加的,之前版本(含4.4_r1)没有
            // (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/Environment.java/)
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
                try {
                    mGetState = storageValumeClazz.getMethod("getState");
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
            //---------------------------------------------------------------------

            //调用getVolumeList方法,参数为:“谁”中调用这个方法
            final Object invokeVolumeList = getVolumeList.invoke(storageManager);
            //---------------------------------------------------------------------
            final int length = Array.getLength(invokeVolumeList);
            ArrayList list = new ArrayList<>();
            for (int i = 0; i < length; i++) {
                final Object storageValume = Array.get(invokeVolumeList, i);//得到StorageVolume对象
                final String path = (String) getPath.invoke(storageValume);
                final boolean removable = (Boolean) isRemovable.invoke(storageValume);
                String state = null;
                if (mGetState != null) {
                    state = (String) mGetState.invoke(storageValume);
                } else {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        state = Environment.getStorageState(new File(path));
                    } else {
                        if (removable) {
                            state = EnvironmentCompat.getStorageState(new File(path));
                        } else {
                            //不能移除的存储介质,一直是mounted
                            state = Environment.MEDIA_MOUNTED;
                        }
                        final File externalStorageDirectory = Environment.getExternalStorageDirectory();
                        Log.e(TAG, "externalStorageDirectory==" + externalStorageDirectory);
                    }
                }
                long totalSize = 0;
                long availaleSize = 0;
                if (Environment.MEDIA_MOUNTED.equals(state)) {
                    totalSize = StorageUtils.getTotalSize(path);
                    availaleSize = StorageUtils.getAvailaleSize(path);
                }
                
                StorageBean storageBean = new StorageBean();
                storageBean.setAvailableSize(availaleSize);
                storageBean.setTotalSize(totalSize);
                storageBean.setMounted(state);
                storageBean.setPath(path);
                storageBean.setRemovable(removable);
                list.add(storageBean);
            }
            return list;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

注意

关注Google发布的最新版本的Android源代码,StorageManager的getVolumeList方法是否发生变化,或重命名,关注StorageVolume的属性是否发生变更。不过一般不会大变,如果会变,也会在提前几个版本中用

你可能感兴趣的:(Android手机外置SD卡路径)