Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理
目錄
Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理
一、簡單介紹
二、實作原理
三、注意事項
四、簡單實作步驟
五、關鍵代碼
附錄:
一、不同平台使用宏區分路徑加載
二、Unity3D中的資源路徑
三、Unity3D各平台路徑(包括手機内置存儲路徑、SD卡等等)
一、簡單介紹
Unity中的一些基礎知識點,便于後期檢視學習。
本節介紹,加載Android手機移動端sdcard 上指定檔案上的圖檔檔案的簡單方式整理,方法不唯一,僅供參考。
二、實作原理
1、首先 使用 DirectoryInfo 擷取該檔案夾下的所有檔案資訊
DirectoryInfo direction = new DirectoryInfo(SD_URL2);
//傳回的指定數組 = 傳回目前目錄的所有檔案清單的名字加格式數組
FileInfo[] files = direction.GetFiles("*");
2、然後,根據檔案字尾,判斷是否是圖檔,然後進行對應圖檔的加載
string ext = files[i].Extension;
Debug.Log(" ext " + ext);
if (ext.EndsWith("jpg") || ext.EndsWith("png") || ext.EndsWith("jpeg"))
3、然後使用三種方式進行加載
- WWW w = new WWW(path);
- UnityWebRequest uwr = new UnityWebRequest(url);
- 檔案讀取的方式:FileStream files = new FileStream(imagePath, FileMode.Open);
三、注意事項
1、Android 移動端擷取檔案夾下的檔案資訊時,不用添加 "jar:file://" 字首
2、Android 移動端使用 WWW 或者 UnityWebRequest 加載圖檔檔案時,注意添加 "jar:file://" 字首
3、Android 移動端使用檔案IO讀取檔案時,不用添加 "jar:file://" 字首
4、讀取 sdcard 檔案的時候,注意添加對應權限
5、不同Android手機版本問題,雖然添加了 讀取 sdcard 權限,依然沒有權限讀取,在 AndroidManifest.xml 添加如下進行處理
<application android:requestLegacyExternalStorage="true">
權限報錯:Unity: IOException: Permission denied
6、發現 sdcard 或者 storage/ 或者 storage/emulated/0/ 好似都可以加載根目錄檔案
四、簡單實作步驟
1、建立Unity 工程,簡單搭建場景
2、建立腳本,擷取sdcard 對應檔案夾下的檔案資訊,并簡單使用三種方式加載對應圖檔
3、把腳本添加到場景中
4、在 PlayerSettings 添加對應sdcard 讀寫權限,Write Permission 設定為 External(SDCard)
5、為了避免可能由于不同 Android 手機版本,可能出現給了權限依舊無法讀取的報錯
Publishing Setting 勾選 Custom Main Mainifest ,在工程中顯示 AndroidManifest.xml,并添加android:requestLegacyExternalStorage="true"
6、打包運作到Android手機,效果如下
五、關鍵代碼
1、LoadAndroidImgs.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class LoadAndroidImgs : MonoBehaviour
{
string URL = "file://" + "/storage/emulated/0/TestLauncherImages/";
string SD_URL = "/storage/emulated/0/TestLauncherImages/";
string SD_URL2 = "/sdcard/TestLauncherImages/";
// Start is called before the first frame update
void Start()
{
Load();
GetTexture("https://scpic.chinaz.net/files/pic/pic9/201706/zzpic4354.jpg", (t) => {
GameObject.Find("Canvas/RawImage (1)").GetComponent<RawImage>().texture = t;
});
}
// Update is called once per frame
void Update()
{
}
void Load(){
DirectoryInfo direction = new DirectoryInfo(SD_URL2);
//傳回的指定數組 = 傳回目前目錄的所有檔案清單的名字加格式數組
FileInfo[] files = direction.GetFiles("*");
//存儲讀取圖檔的名字字元串
List<string> imageNames = new List<string>();
for (int i = 0; i < files.Length; i++)
{
//判斷圖檔的格式字元串是否與指定的字元串不比對。
if (!files[i].Name.EndsWith(".meta"))
{
//Debug.LogFormat("圖檔{0}的名字:{1}", i, files[i].FullName);
//添加圖檔路徑和名字字元串到泛型數組
imageNames.Add(files[i].FullName);
Debug.Log(files[i].FullName);
string ext = files[i].Extension;
Debug.Log(" ext " + ext);
if (ext.EndsWith("jpg") || ext.EndsWith("png") || ext.EndsWith("jpeg"))
{
//StartCoroutine(doLoadByWWW("jar:file://" + files[i].FullName));
GetTexture("jar:file://"+files[i].FullName, (t) => {
GameObject.Find("Canvas/RawImage").GetComponent<RawImage>().texture = t;
});
//Texture2D tx = new Texture2D(100, 100);
//tx.LoadImage(getImageByte(files[i].FullName));
//GameObject.Find("Canvas/RawImage").GetComponent<RawImage>().texture = (tx);
}
}
}
}
IEnumerator doLoadByWWW(String path)
{
WWW w = new WWW(path);
yield return w;
if (w.isDone)
{
Sprite sprite = Sprite.Create(w.texture, new Rect(0, 0, w.texture.width, w.texture.height), new Vector2(0.5f, 0.5f));
GameObject.Find("Canvas/Image").GetComponent<Image>().sprite = sprite;
}
}
/// <summary>
/// 請求圖檔
/// </summary>
/// <param name="url">圖檔位址,like 'http://www.my-server.com/image.png '</param>
/// <param name="action">請求發起後處理回調結果的委托,處理請求結果的圖檔</param>
/// <returns></returns>
public void GetTexture(string url, Action<Texture2D> actionResult)
{
StartCoroutine(_GetTexture(url, actionResult));
}
/// <summary>
/// 請求圖檔
/// </summary>
/// <param name="url">圖檔位址,like 'http://www.my-server.com/image.png '</param>
/// <param name="action">請求發起後處理回調結果的委托,處理請求結果的圖檔</param>
/// <returns></returns>
IEnumerator _GetTexture(string url, Action<Texture2D> actionResult)
{
UnityWebRequest uwr = new UnityWebRequest(url);
DownloadHandlerTexture downloadTexture = new DownloadHandlerTexture(true);
uwr.downloadHandler = downloadTexture;
yield return uwr.SendWebRequest();
Texture2D t = null;
if (!(uwr.isNetworkError || uwr.isHttpError))
{
t = downloadTexture.texture;
}
else
{
Debug.Log("下載下傳失敗,請檢查網絡,或者下載下傳位址是否正确: "+ uwr.error);
}
if (actionResult != null)
{
actionResult(t);
}
}
/// <summary>
/// 根據圖檔路徑傳回圖檔的位元組流byte[]
/// </summary>
/// <param name="imagePath">圖檔路徑</param>
/// <returns>傳回的位元組流</returns>
private static byte[] getImageByte(string imagePath)
{
FileStream files = new FileStream(imagePath, FileMode.Open);
byte[] imgByte = new byte[files.Length];
files.Read(imgByte, 0, imgByte.Length);
files.Close();
return imgByte;
}
}
2、AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application android:requestLegacyExternalStorage="true">
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>
附錄:
一、不同平台使用宏區分路徑加載
#if UNITY_EDITOR
filepath = Application.dataPath + "/StreamingAssets";
#elif UNITY_IOS || UNITY_IPHONE
filepath = "file://" + Application.streamingAssetsPath;
#elif UNITY_ANDROID
filepath = "jar:file://" + Application.dataPath + "!/assets";
#endif
二、Unity3D中的資源路徑
- Application.dataPath 此屬性用于傳回程式的資料檔案所在檔案夾的路徑。例如在Editor中就是Assets了。
- Application.streamingAssetsPath 此屬性用于傳回流資料的緩存目錄,傳回路徑為相對路徑,适合設定一些外部資料檔案的路徑。
- Application.persistentDataPath 此屬性用于傳回一個持久化資料存儲目錄的路徑,可以在此路徑下存儲一些持久化的資料檔案。
- Application.temporaryCachePath 此屬性用于傳回一個臨時資料的緩存目錄。
三、Unity3D各平台路徑(包括手機内置存儲路徑、SD卡等等)
關于Unity3D在各平台上的路徑問題,網上有好多的資料,如下是比較好的參考資料:
1、http://www.manew.com/thread-23491-1-1.html
2、#你好Unity3D#手機上的路徑(來自我的長微網誌) | 雨松MOMO程式研究院
這裡我不詳細解釋和路徑的用法,隻把各個路徑對應的位置和通路方式總結一下。
1、Resources路徑
Resources檔案夾是Unity裡自動識别的一種檔案夾,可在Unity編輯器的Project視窗裡建立,并将資源放置在裡面。Resources檔案夾下的資源不管是否有用,全部會打包進.apk或者.ipa,并且打包時會将裡面的資源壓縮處理。加載方法是Resources.Load<T>(檔案名),需要注意:檔案名不包括擴充名,打包後不能更改Resources下的資源内容,但是從Resources檔案夾中加載出來的資源可以更改。
2、Application.dataPath路徑
這個屬性傳回的是程式的資料檔案所在檔案夾的路徑,例如在Editor中就是項目的Assets檔案夾的路徑,通過這個路徑可以通路項目中任何檔案夾中的資源,但是在移動端它是完全沒用。
3、Application.streamingAssetsPath路徑
這個屬性用于傳回流資料的緩存目錄,傳回路徑為相對路徑,适合設定一些外部資料檔案的路徑。在Unity工程的Assets目錄下起一個名為“StreamingAssets”的檔案夾即可,然後用Application.streamingAssetsPath通路,這個檔案夾中的資源在打包時會原封不動的打包進去,不會壓縮,一般放置一些資源資料。在PC/MAC中可實作對檔案的“增删改查”等操作,但在移動端是一個隻讀路徑。
4、Application.persistentDataPath路徑(推薦使用)
此屬性傳回一個持久化資料存儲目錄的路徑,可以在此路徑下存儲一些持久化的資料檔案。這個路徑可讀、可寫,但是隻能在程式運作時才能讀寫操作,不能提前将資料放入這個路徑。在IOS上是應用程式的沙盒,可以被iCloud自動備份,可以通過同步推送一類的助手直接取出檔案;在Android上的位置是根據Project Setting裡設定的Write Access路徑,可以設定是程式沙盒還是sdcard,注意:如果在Android設定儲存在沙盒中,那麼就必須root以後才能用電腦取出檔案,是以建議寫入sdcard裡。一般情況下,建議将獲得的檔案儲存在這個路徑下,例如可以從StreamingAsset中讀取的二進制檔案或者從AssetBundle讀取的檔案寫入PersistentDatapath。
5、Application.temporaryCachePath路徑
此屬性傳回一個臨時資料的緩存目錄,跟Application.persistentDataPath類似,但是在IOS上不能被自動備份。
6、/sdcard/..路徑
表示Android手機的SD卡根目錄。
7、/storage/emulated/0/..路徑(這個路徑我查找了好久……)
表示Android手機的内置存儲根目錄。
以上各路徑中的資源加載方式都可以用WWW類加載,但要注意各個平台路徑需要加的通路名稱,例如Android平台的路徑前要加"jar:file://",其他平台使用"file://"。以下是各路徑在各平台中的具體位置資訊:
Android平台
Application.dataPath : /data/app/xxx.xxx.xxx.apk
Application.streamingAssetsPath : jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
Application.persistentDataPath : /data/data/xxx.xxx.xxx/files
Application.temporaryCachePath : /data/data/xxx.xxx.xxx/cache
IOS平台
Application.dataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
Application.streamingAssetsPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
Application.persistentDataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
Application.temporaryCachePath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches
Windows Web Player
Application.dataPath : file:///D:/MyGame/WebPlayer (即導包後儲存的檔案夾,html檔案所在檔案夾)
Application.streamingAssetsPath :
Application.persistentDataPath :
Application.temporaryCachePath :