天天看點

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

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

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

6、發現 sdcard 或者 storage/ 或者 storage/emulated/0/ 好似都可以加載根目錄檔案

四、簡單實作步驟

1、建立Unity 工程,簡單搭建場景

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

2、建立腳本,擷取sdcard 對應檔案夾下的檔案資訊,并簡單使用三種方式加載對應圖檔

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

3、把腳本添加到場景中

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

4、在 PlayerSettings 添加對應sdcard 讀寫權限,Write Permission 設定為 External(SDCard)

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

 5、為了避免可能由于不同 Android 手機版本,可能出現給了權限依舊無法讀取的報錯

Publishing Setting 勾選 Custom Main Mainifest ,在工程中顯示 AndroidManifest.xml,并添加android:requestLegacyExternalStorage="true"

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:
Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:
Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

 6、打包運作到Android手機,效果如下

Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理Unity Android 之 讀取下載下傳擷取移動端 sdcard 路徑下的指定檔案夾的所有圖檔的幾種方式的簡單整理附錄:

五、關鍵代碼

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 :