Unity3D 学习笔记之九:如何获取 Android 外置 SD 卡的路径

423 阅读2分钟

1. 问题描述

上次在文章《打包的Android应用如何播放本地视频及外置SD卡的视频》中整理了一下读取并播放外置 SD 卡中的视频的方法。

上篇文章侧重于解决读取并播放外置 SD 卡中的本地视频,而本文会详细讲解如何在 Unity 中自动获取 SD 卡的路径(因为不同的 SD 卡,它的路径不同,所以最好的方法是让程序自动获取 SD 路径而不是代码中写死)。

总体思路就是,在 Android 中将获取 SD 卡路径的方法打成 Jar 包,然后在 Unity 中调用。

2. 解决方法

2.1 打 Jar 包

在 Android 中获取外置 SD 卡路径的代码,在之前的文章中已经说过。这里对其进行了削微的改动,然后将其打成 Jar 包。

public class GetSdcardNameUtil {

    private static final String TAG = GetSdcardNameUtil.class.getSimpleName();

    /**
     * @param mContext    context对象,传入activty对象即可
     * @param is_removale 存储否可以移除,如果是外置sdcard,is_removale应该传入true
     * @return
     */
    public static String getStoragePath(Context mContext, boolean is_removale) {

        StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
        Class<?> storageVolumeClazz = null;
        try {
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
            Method getPath = storageVolumeClazz.getMethod("getPath");
            Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
            Object result = getVolumeList.invoke(mStorageManager);
            final int length = Array.getLength(result);
            for (int i = 0; i < length; i++) {
                Object storageVolumeElement = Array.get(result, i);
                String path = (String) getPath.invoke(storageVolumeElement);
                Log.d(TAG, "path = " + path);
                boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
                if (is_removale == removable) {
                    return path;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Jar 包打包的具体过程就不讲了,毕竟我不是擅长这个的,打包过程中你们万一有啥问题我也回答不来,干脆不写了,你们自行找其他教程学吧。

2.2 在 Unity 中调用 Jar 包中的方法 

 首先,将 Jar 包放入 Unity 的 Plugins 目录下。

然后,打开 Plugins / Android 文件夹下的 AndroidManifest.xml 文件,添加两行代码,申请读写存储权限。

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

然后创建脚本,脚本中添加一个 getSdPath() 函数。

private string getSdPath()
{
    AndroidJavaClass jc = new AndroidJavaClass("com.vivedu.sdcardget.GetSdcardNameUtil");
    AndroidJavaObject context = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
    string path = jc.CallStatic<string>("getStoragePath", context, true);

    return path;
}

调用该函数后,返回的 SD 卡根目录路径,形如:

/storage/3686-3696

然后就可以使用啦。

3. 常见问题

 1. 在 Unity 中直接运行时,会报错 Exception: JNI: Init'd AndroidJavaClass with null ptr!

这个是因为 Unity 中不是 Android 真机环境,这个错误可以不用理会,打包后在 Android 环境下运行就没问题了。

  1. 还是有必要解释一下 getSdPath 函数中的代码。 
AndroidJavaClass jc = new AndroidJavaClass("com.vivedu.sdcardget.GetSdcardNameUtil");
AndroidJavaObject context = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
string path = jc.CallStatic<string>("getStoragePath", context, true);

 第一行代码中的 com.vivedu.sdcardget.GetSdcardNameUtil ,是 包名.类名,如果 Jar 包是自己打包的话,这个参数根据自己的实际情况进行修改。

第三行代码中的 getStoragePath 是函数名,后面的 contexttrue 分别是函数的两个参数。

public static String getStoragePath(Context mContext, boolean is_removale) 
  1. Unity 打包得到 Android 应用并安装后,别忘记给应用授权相应的读写本地存储的权限哦。