关于获取SD卡路径Permission denied的问题

最近在适配各种Android设备(非手机),都是深度定制过。需要往SD卡不停地写入实时音视频文件,但在对SD卡写文件时,都报Permission denied的错,前前后后调了很久才调通,现在写个文章来记录下,以备不时之需。

第一步是按内部存储和外部存储的区分来获取路径。下面这段代码是根据条件获取内、外存储路径:

/**
     * 获取Android内部存储或外置SD卡路径
     *
     * @param context    上下文
     * @param isRemovale true获取的是外部存储,false获取的是内部存储
     * @return
     */
    public static String getStoragePath(Context context, boolean isRemovale) {
        // 拿到StorageManager
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        Class<?> storageVolumeClazz = null;
        try {
            // 反射获得StorageVolume
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            // 反射获得StorageManager的getVolumeList方法
            Method getVolumeList = storageManager.getClass().getMethod("getVolumeList");
            // 反射获得StorageVolume的getPath方法
            Method getPath = storageVolumeClazz.getMethod("getPath");
            // 拿到StorageVolume的isRemovable方法
            Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
            Object result = getVolumeList.invoke(storageManager); // 得到Storage Volume数组
            final int length = Array.getLength(result);
            for (int i = 0; i < length; i++) {  // 遍历数组,拿到StorageVolume中的路径mPath
                Object storageVolume = Array.get(result, i);
                String path = (String) getPath.invoke(storageVolume);
                // 判断是否是可移除的,可移除表示是sdcard
                boolean removable = (Boolean) isRemovable.invoke(storageVolume);
                if (isRemovale == removable) { // isRemovale为true返回sdcard路径,false返回内部存储路径
                    return path;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

这里我直接获取外部存储路径,即SD卡的路径:

/**
     * 优先获取SD卡路径,若SD卡无,则返回内部存储路径
     *
     * @param context 上下文
     * @return 返回可用路径
     */
    public static String getActivePath(Context context) {
        String sdCardPath = getStoragePath(context, true);//返回SD卡路径
        String innerCPath = getStoragePath(context, false);//返回内部存储路径

        Log.e("TAG", "sdCardPath=" + sdCardPath);
        Log.e("TAG", "innerCPath=" + innerCPath);

        if (sdCardPath != null && innerCPath != null) {
            long sdCardSize = getTotalMemorySize(sdCardPath);
            long innerCSize = getTotalMemorySize(innerCPath);

            Log.e("TAG", "sdCardSize=" + sdCardSize + ",innerCSize=" + innerCSize);

            if (sdCardSize > innerCSize) {

                return sdCardPath;
            } else {

                return innerCPath;
            }
        }
        return innerCPath;//否则返回
    }

获取该存储大小:

/**
     * 获取该存储空间大小
     *
     * @param path 存储路径
     * @return 返回该存储路径的空间大小,大小为字节
     */
    private static long getTotalMemorySize(String path) {
        try {
            //系统的空间描述类
            StatFs stat = new StatFs(path);
            //每个区块占字节数
            long blockSize = stat.getBlockSize();
            //区块总数
            long totalBlocks = stat.getBlockCount();
            return totalBlocks * blockSize;
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

在需要调用的地方直接写  getActivePath(context)。一般来说,这样获取出来的路径都可用:

但是有时即使这样,当向SD卡读写文件时,依旧报错:Permission denied

这个权限的报错,网上很多人说需要添加相应的权限,但确定项目已经添加,但依旧报错。

扫描二维码关注公众号,回复: 5010308 查看本文章

后来才知道,该Android设备已被厂商深度定制过,很多权限都直接掐掉了。

解决方法有两个:

一是与厂商沟通,让其开放权限给你的App,但这样费时又费力;

二是直接在代码里写死路径:"/mnt/m_external_sd"(但发现此方法也不是万能,在有些设备上可行,某些设备上又不可以= =)

目前我的做法是直接写死路径,大家有更好的办法可以告诉下~

猜你喜欢

转载自blog.csdn.net/toyauko/article/details/84645904