IEnumerator LoadAssetBundleFromLocalPath <T>(
            AssetBundleSettings.AssetBundleInfo abInfo,
            Action <T> onFinish,
            Action <string> onFailed) where T : UnityEngine.Object
        {
            string path = AssetBundleSettings.localFolderPathSaveAB + "/" + abInfo.assetBundle + abInfo.extension;

            if (File.Exists(path))
            {
                System.Uri url  = new System.Uri(path);
                WWW        _www = new WWW(url.AbsoluteUri);
                yield return(new WaitUntil(() => {
                    return _www.isDone;
                }));

                if (string.IsNullOrEmpty(_www.error))
                {
                    StartCoroutine(ExtractAssetObjectFromAssetBundle(_www, abInfo, path, onFinish, onFailed));
                    _www.Dispose();
                }
                else
                {
                    onFailed("Not Loaded『" + abInfo.assetBundle + "』In LocalPath: " + path);
                }
            }
            else
            {
                onFailed("Not Found『" + abInfo.assetBundle + "』In LocalPath: " + path);
            }
        }
        IEnumerator ExtractAssetObjectFromAssetBundle <T>(
            WWW www,
            AssetBundleSettings.AssetBundleInfo abInfo,
            string path,
            Action <T> onFinish,
            Action <string> onFailed) where T : UnityEngine.Object
        {
            string      assetName   = System.IO.Path.GetFileNameWithoutExtension(abInfo.assetBundle);
            AssetBundle assetBundle = null;

            if (AssetBundleSettings.IsEncryptAssetBundle)
            {
                byte[] decryptedBytes = EncryptDecryptUtil.DecryptBytesToBytes(www.bytes, AssetBundleSettings.PASSWORD_ENCRYPT_DECRYPT_ASSETBUNDLE);
                AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromMemoryAsync(decryptedBytes);
                yield return(assetBundleCreateRequest);

                assetBundle = assetBundleCreateRequest.assetBundle;
            }
            else
            {
                assetBundle = www.assetBundle;
            }

            // Load the object asynchronously
            AssetBundleRequest request = assetBundle.LoadAssetAsync(assetName);

            // Wait for completion
            while (!request.isDone)
            {
                yield return(null);
            }
            yield return(new WaitForEndOfFrame());

            UnityEngine.Object obj = request.asset;
            if (obj != null)
            {
                if (obj is Texture2D && typeof(T) == typeof(Sprite))
                {
                    Texture2D texture = request.asset as Texture2D;
                    Sprite    spr     = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
                    onFinish(spr as T);
                }
                else
                {
                    onFinish(obj as T);
                }
                new WaitForEndOfFrame();
                assetBundle.Unload(false);
                yield break;
            }
            else
            {
                onFailed("Can not extract『" + abInfo.assetBundle + "』from LocalPath: " + path);
            }
        }
 public AssetBundleFileDownload(string urlStr, AssetBundleSettings.AssetBundleInfo abFileInfo)
 {
     _www    = null;
     _urlStr = urlStr;
     if (!_urlStr.EndsWith("/"))
     {
         _urlStr += "/";
     }
     _retryCount  = 0;
     isProcessing = false;
     fileInfo     = abFileInfo;
 }
        IEnumerator ExtractSceneNameAndLoadSceneFromAssetBundle(
            WWW www,
            AssetBundleSettings.AssetBundleInfo abInfo,
            string path,
            UnityEngine.SceneManagement.LoadSceneMode loadSceneMode,
            Action <string> onFinish,
            Action <string> onFailed)
        {
            // Load the object asynchronously
            AssetBundle assetBundle = null;

            if (AssetBundleSettings.IsEncryptAssetBundle)
            {
                byte[] decryptedBytes = EncryptDecryptUtil.DecryptBytesToBytes(www.bytes, AssetBundleSettings.PASSWORD_ENCRYPT_DECRYPT_ASSETBUNDLE);
                AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromMemoryAsync(decryptedBytes);
                yield return(assetBundleCreateRequest);

                assetBundle = assetBundleCreateRequest.assetBundle;
            }
            else
            {
                assetBundle = www.assetBundle;
            }
            if (assetBundle != null)
            {
                string[] scenePath = assetBundle.GetAllScenePaths();
                string   sceneName = Path.GetFileNameWithoutExtension(scenePath [0]);
                var      asyncLoad = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(sceneName, loadSceneMode);
                yield return(asyncLoad);

                onFinish(sceneName);
                assetBundle.Unload(false);
            }
            else
            {
                onFailed("Can not extract『" + abInfo.assetBundle + "』from LocalPath: " + path);
            }
        }
        /// <summary>
        /// Settings the download AB list. Get total size needed to be downloaded
        /// </summary>
        IEnumerator SettingDownloadABList(byte[] newAssetBundleAssetVersion)
        {
            //Load local assetbundle version
            string path = AssetBundleSettings.localFolderPathSaveAB + "/" + AssetBundleSettings.ASSETBUNDLE_VERSION_FILE_NAME;

            if (File.Exists(path))
            {
                System.Uri url  = new System.Uri(path);
                WWW        _www = new WWW(url.AbsoluteUri);
                yield return(new WaitUntil(() => {
                    return _www.isDone;
                }));

                AssetBundleSettings.AssetBundleTargetDB _oldVersionDB = null;
                if (AssetBundleSettings.IsEncryptAssetBundle)
                {
                    byte[] decryptedBytes = EncryptDecryptUtil.DecryptBytesToBytes(_www.bytes, AssetBundleSettings.PASSWORD_ENCRYPT_DECRYPT_ASSETBUNDLE);
                    _oldVersionDB = _objectPacker.Unpack <AssetBundleSettings.AssetBundleTargetDB> (decryptedBytes);
                }
                else
                {
                    _oldVersionDB = _objectPacker.Unpack <AssetBundleSettings.AssetBundleTargetDB> (_www.bytes);
                }

                _downloadList = new List <AssetBundleSettings.AssetBundleInfo> ();
                foreach (var assetBundleInfo  in _assetBundleVersionDB.lstAssetBundleInfo)
                {
                    AssetBundleSettings.AssetBundleInfo oldABInfo = _oldVersionDB.lstAssetBundleInfo.Where(_ => _.assetBundle == assetBundleInfo.assetBundle).FirstOrDefault();
                    if (oldABInfo == null)
                    {
                        _downloadList.Add(assetBundleInfo);
                    }
                    else
                    {
                        if (assetBundleInfo.version != oldABInfo.version)
                        {
                            _downloadList.Add(assetBundleInfo);
                        }
                        else if (assetBundleInfo.hashAssetBundle != oldABInfo.hashAssetBundle)
                        {
                            _downloadList.Add(assetBundleInfo);
                        }
                    }
                }
            }
            else
            {
                _downloadList = new List <AssetBundleSettings.AssetBundleInfo> (_assetBundleVersionDB.lstAssetBundleInfo);
            }

            if (!Directory.Exists(AssetBundleSettings.localFolderPathSaveAB))
            {
                Directory.CreateDirectory(AssetBundleSettings.localFolderPathSaveAB);
            }
            #if UNITY_IPHONE
            //No backup to cloud
            UnityEngine.iOS.Device.SetNoBackupFlag(path);
            #endif
            yield return(null);

            File.WriteAllBytes(path, newAssetBundleAssetVersion);

            totalSize = 0;
            foreach (var item in _downloadList)
            {
                totalSize += item.size;
            }

            yield return(null);
        }
        /// <summary>
        /// Loads the scene async from AssetBundle
        /// </summary>
        /// <returns>The scene async.</returns>
        /// <param name="assetBundle">AssetBundle file.</param>
        /// <param name="loadSceneMode">Load scene mode.</param>
        /// <param name="onFinish">onFinish callback. Return name of scene has just loaded</param>
        /// <param name="onFailed">onFailed callback Return error reason.</param>
        public IEnumerator LoadSceneAsync(
            string assetBundle,
            UnityEngine.SceneManagement.LoadSceneMode loadSceneMode,
            Action <string> onFinish, Action <string> onFailed)
        {
            bool isSuccess       = false;
            bool isProcessFinish = false;

            //Load AssetBundle version first
            if (_assetBundleVersionDB == null)
            {
                StartCoroutine(GetAssetBundleVersionFile((fileUrl) => {
                    Debug.Log("Download version file OK " + fileUrl);
                    isSuccess       = true;
                    isProcessFinish = true;
                }, (downloadPath, error) => {
                    isProcessFinish = true;
                    Debug.LogError("Can not download version file from: " + downloadPath);
                    onFailed(error);
                }));

                yield return(new WaitUntil(() => {
                    return isProcessFinish;
                }));

                if (!isSuccess)
                {
                    yield break;
                }
            }

            //Check AssetBundle existed in version database or not?
            AssetBundleSettings.AssetBundleInfo abInfo = _assetBundleVersionDB.lstAssetBundleInfo.Where(_ => _.assetBundle == assetBundle).FirstOrDefault();
            if (abInfo == null)
            {
                Debug.Log("Not found『" + assetBundle + "』in AssetBundles Version Database");
                onFailed("Not found『" + assetBundle + "』in AssetBundles Version Database");
                yield break;
            }

            //Load from local
            string path = AssetBundleSettings.localFolderPathSaveAB + "/" + abInfo.assetBundle + abInfo.extension;

            if (File.Exists(path))
            {
                System.Uri url  = new System.Uri(path);
                WWW        _www = new WWW(url.AbsoluteUri);
                yield return(new WaitUntil(() => {
                    return _www.isDone;
                }));

                if (string.IsNullOrEmpty(_www.error))
                {
                    isSuccess       = false;
                    isProcessFinish = false;
                    StartCoroutine(ExtractSceneNameAndLoadSceneFromAssetBundle(_www, abInfo, path, loadSceneMode,
                                                                               (sceneName) => {
                        isSuccess       = true;
                        isProcessFinish = true;
                        onFinish(sceneName);
                    }, (err) => {
                        isSuccess       = false;
                        isProcessFinish = true;
                    }));
                    _www.Dispose();
                    yield return(new WaitUntil(() => {
                        return isProcessFinish;
                    }));

                    if (isSuccess)
                    {
                        yield break;
                    }
                }
                else
                {
                    onFailed("Not Found『" + abInfo.assetBundle + "』In LocalPath: " + path);
                    yield break;
                }
            }
            else
            {
                Debug.Log("NOT FOUND " + assetBundle);
            }

            //Can not be loaded from local, so need download from server
            AssetBundleFileDownload dlObj = new AssetBundleFileDownload(AssetBundleSettings.GetAssetBundleServerURL(), abInfo);

            DownloadFile(true, dlObj,
                         (www) => {
                string pathLocal = AssetBundleSettings.localFolderPathSaveAB + "/" + abInfo.assetBundle + abInfo.extension;
                StartCoroutine(ExtractSceneNameAndLoadSceneFromAssetBundle(www, abInfo, pathLocal, loadSceneMode, onFinish, onFailed));
                dlObj.Dispose();
            }, (errMsg) => {
                onFailed(errMsg);
            });
        }
        /// <summary>
        /// Loads asset object from AssetBundles
        /// </summary>
        /// <returns>The asset async.</returns>
        /// <param name="assetBundle">AssetBundle file.</param>
        /// <param name="onFinish">onFinish callback. Return object was loaded.</param>
        /// <param name="onFailed">onFailed callback. Return error reason.</param>
        /// <typeparam name="T">The 1st type parameter.</typeparam>
        public IEnumerator LoadAssetAsync <T>(
            string assetBundle,
            Action <T> onFinish,
            Action <string> onFailed) where T : UnityEngine.Object
        {
            if (_assetBundleVersionDB == null)
            {
                //Load AssetBundle version first
                bool isSuccess = false;
                bool isDownloadVersionFileFinish = false;
                StartCoroutine(GetAssetBundleVersionFile((fileUrl) => {
                    Debug.Log("Download version file OK " + fileUrl);
                    isSuccess = true;
                    isDownloadVersionFileFinish = true;
                }, (downloadPath, error) => {
                    isDownloadVersionFileFinish = true;
                    Debug.LogError("Can not download version file from: " + downloadPath);
                    onFailed(error);
                }));

                yield return(new WaitUntil(() => {
                    return isDownloadVersionFileFinish;
                }));

                if (!isSuccess)
                {
                    yield break;
                }
            }

            //Check AssetBundle existed in version database or not?
            AssetBundleSettings.AssetBundleInfo abInfo = _assetBundleVersionDB.lstAssetBundleInfo.Where(_ => _.assetBundle == assetBundle).FirstOrDefault();
            if (abInfo == null)
            {
                Debug.Log("Not found『" + assetBundle + "』in AssetBundles Version Database");
                onFailed("Not found『" + assetBundle + "』in AssetBundles Version Database");
                yield break;
            }

            //Load from local
            bool isFinish = false;
            bool isLoaded = false;

            StartCoroutine(LoadAssetBundleFromLocalPath <T>(abInfo,
                                                            (obj) => {
                isFinish = true;
                isLoaded = true;
                onFinish(obj);
            }, (err) => {
                isFinish = true;
                isLoaded = false;
                onFailed(err);
            }));
            yield return(new WaitUntil(() => {
                return isFinish;
            }));

            if (isLoaded)
            {
                yield break;
            }

            //Can not be loaded from local, so need download from server
            AssetBundleFileDownload dlObj = new AssetBundleFileDownload(AssetBundleSettings.GetAssetBundleServerURL(), abInfo);

            DownloadFile(true, dlObj,
                         (www) => {
                string path = AssetBundleSettings.localFolderPathSaveAB + "/" + abInfo.assetBundle + abInfo.extension;
                StartCoroutine(ExtractAssetObjectFromAssetBundle(www, abInfo, path, onFinish, onFailed));
                dlObj.Dispose();
            }, (errMsg) => {
                onFailed(errMsg);
            });
        }