Unity Threadダウンロードエンジン　No アセットバンドル

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.IO;
using System.Net;
using Api;
using Extention;


namespace Helper
{
    /// <summary>
    /// Content download engine.
    /// </summary>
	public sealed class ContentDownloadEngine : SingletonMonoBehaviourFast<ContentDownloadEngine>
	{
		#region シリアライズ変数
		[SerializeField]
		private GameObject _progressObj;

		[SerializeField]
		private UISlider progressBar;

		[SerializeField]
		private UILabel progressLabel;

		[SerializeField]
		private UILabel _fileCheckLabel;

		#endregion

	    #region Private Fields
		public static bool _isLoadFin = false;
		public static string _udid = "";

		private List<ContentsEntity.Contents> _cacheContentsList;

		private volatile int  _currentDownloadCount = 0;
		private volatile int  _downloadListCount = 0;

		private volatile bool _exeptionFlag = false;
		private volatile bool _displayErrorPopupFlag = false;
		private volatile bool _displayNetworkPopupFlag = false;

		private int _setProgress;
		private object _lockObj = new object();
		private delegate void ThreadDownloadDelegate(List<Dictionary<string, string>> content, int threadId);
		private List<IAsyncResult> _asyncResultList;
		private volatile int _threadQueueCounter = 0;
		private volatile int  _threadCounter = 0;
		private volatile int _tryCounter = 0;
		private volatile int _autoRetry = 0;

		private readonly int threadSplitCount = 5;
		private readonly int mHttpRequestTimeout = 15 * 1000; // 15 Sec
		private readonly string mHttpRequestUserAgent  = "";

	    #endregion

	    #region Unity Events

//		void OnApplicationPause (bool pauseStatus)
//        {
//			if (pauseStatus == true) {
//				CacheAssetContentsPrefs.CacheAssetContentsFlush ();
//            }
//        }

	    void Start()
	    {
			_currentDownloadCount = 0;
			_tryCounter = 0;
			_autoRetry = 0;
//Debug.Log ("ベンチマーク開始");
StartTime(); //ベンチマーク計測用
			//ダウンロードの速度最適化用設定。
		    System.Net.ServicePointManager.UseNagleAlgorithm = false;
		    System.Net.ServicePointManager.DefaultConnectionLimit = 8;
			//file save proccess init
		    CacheAssetContentsPrefs.Init ();
	    }

	    void Update ()
		{
			//例外が起きた場合の処理
			if (_exeptionFlag == true)
            {
				if (_displayNetworkPopupFlag == false && _threadQueueCounter == 0) {
					_displayNetworkPopupFlag = true;
					HttpIoOrNetworkErrorPopup ();
				} else {
					if (_displayNetworkPopupFlag == false) {
						Debug.Log ("displayNetworkPopupFlag : " + _displayNetworkPopupFlag);
						Debug.Log ("Last Thread Counter : " + _threadQueueCounter);
					}
				}

				lock (_lockObj){
				    _exeptionFlag = false;
				}
				return;
			}
			// ProgressBar
			if (progressBar != null && _isLoadFin == false)
			{
				if (_currentDownloadCount != 0 && _cacheContentsList != null && _downloadListCount > 0)
				{
					progressBar.value = ((float)_currentDownloadCount / (float)_downloadListCount) * 2;

					if (progressBar.value <= 0) {
						_progressObj.SetActive (false);
					} else {
						_progressObj.SetActive (true);
					}

					// マイナスと100%越えは見栄えが悪いので範囲更新
					_setProgress = ((int)(((float)_currentDownloadCount / (float)_downloadListCount) * 100) * 2);

					if (0 <= _setProgress && _setProgress <= 100 ) {
						if (_setProgress <= 0) {
							progressLabel.text = "100%";
						} else {
							progressLabel.text = _setProgress.ToString () + "%";
						}

						_fileCheckLabel.gameObject.SetActive (false);
					} else if (0 <= _setProgress && _setProgress <= (100 * 2)) {
					    //ファイルチェック中導入。
						progressLabel.text = "100%";
						progressBar.value = 1.0f;
						_fileCheckLabel.gameObject.SetActive (true);
					} else {
						progressLabel.gameObject.SetActive (false);
					}
				} else {
					_progressObj.SetActive (false); //ちらつき防止。
				}
			} else if (_isLoadFin == true) {
				if (_progressObj != null) {
					_progressObj.SetActive (false); //通信処理終わってたらFalse
				}
			}
	    }
	    #endregion

	    #region 外部用メソッド
		public void MultipleDownload(object _list, bool _popupRetry = false)
		{
			_udid = UiidManager.GetUdid ();

			if (NetworkCheck () == false) {
//				_exeptionFlag = true;
//				_displayNetworkPopupFlag = false;
				_displayNetworkPopupFlag = true;
				StartCoroutine(deferredInvoke(0.3f, ()=>{
					HttpIoOrNetworkErrorPopup ();
				}));
				return;
			}

			if (_threadQueueCounter != 0) {
				Debug.Log ("Async execute now : " + _threadQueueCounter);
				_exeptionFlag = true;
				return;
			}

			List<ContentsEntity.Contents> _contentsList = (List<ContentsEntity.Contents>)_list;
			List<ContentsEntity.Contents> brushedUpList = new List<ContentsEntity.Contents> ();

			_exeptionFlag = false;

			if (_contentsList != null) {
				foreach (var list in _contentsList) {
					if (IsMultipleDownloadIgnore (list) == true)
						continue;

                    string fullPath = string.Format ("{0}{1}{2}", StreamingAssetsHelper.GetDownLoadPath (), list.directory, list.file_name);

					if (File.Exists (fullPath)) {
						if (CacheAssetContentsPrefs.CacheAssetContentsGetString (list.file_path) != list.release_id) { //バージョン番号が一致しない場合。
							brushedUpList.Add (list);
						}
					} else if (!File.Exists (fullPath)) { //ファイルが存在しない場合
						brushedUpList.Add (list);
					}
				}
			}

Debug.Log (brushedUpList.Count + " ダウンロード精査されたリスト数 ");

			if (brushedUpList.Count <= 0) 
			{
Debug.Log (" 入ってる、次のシーンに飛ぶ。 ");
				_isLoadFin = true;
				return;
			}

			_cacheContentsList = brushedUpList;
			_downloadListCount = _cacheContentsList.Count;
			List<Dictionary<string,string>> dic = new List<Dictionary<string, string>> ();

			//分散出来るように処理書く
			Dictionary<int, List<ContentsEntity.Contents>> _pacialContentsList = new Dictionary<int, List<ContentsEntity.Contents>>();
			List<ContentsEntity.Contents> tmpC = new List<ContentsEntity.Contents> ();
			int count = 0;
			int inCount = 1;

			// 端末別に分割数を調整
			int mThreadSplitCount = threadSplitCount;
			#if UNITY_IPHONE && !UNITY_EDITOR
				string deviceModel = SystemInfo.deviceModel;
				Debug.Log (deviceModel);
				if (deviceModel != null && deviceModel != "") {
					if (deviceModel.IndexOf("iPhone3") != -1 || deviceModel.IndexOf("iPhone4") != -1) {
						mThreadSplitCount = 2;
					} else if (deviceModel.IndexOf("iPhone5") != -1 || deviceModel.IndexOf("iPhone6") != -1) {
						mThreadSplitCount = 4;
					} else if (deviceModel.IndexOf("iPad2") != -1) {
						mThreadSplitCount = 2;
					} else if (deviceModel.IndexOf("iPad3") != -1) {
						mThreadSplitCount = 3;
					} else if (deviceModel.IndexOf("iPad4") != -1) {
						mThreadSplitCount = 4;
					} else if (deviceModel.IndexOf("iPod") != -1) {
						mThreadSplitCount = 1;
					}
					Debug.Log("DeviceModel : " + deviceModel + " ThreadCount : " + mThreadSplitCount);
				}
			#elif UNITY_ANDROID && !UNITY_EDITOR
				var cls = new AndroidJavaClass("android.os.Build$VERSION");
				int apiLevel = cls.GetStatic<int>("SDK_INT");
				if (14 <= apiLevel && apiLevel < 17) {
					mThreadSplitCount = 1;
				} else if (17 <= apiLevel && apiLevel < 19) {
					mThreadSplitCount = 3;
				} else if (19 <= apiLevel && apiLevel < 21) {
					mThreadSplitCount = 4;
				}
				Debug.Log("ApiLevel : " + apiLevel + " ThreadCount : " + mThreadSplitCount);
			#endif

			int splitCount = _cacheContentsList.Count / mThreadSplitCount;

			if (splitCount == 0) {
				splitCount = _cacheContentsList.Count;
			}

			foreach (var cList in _cacheContentsList)
			{
				count++;
				tmpC.Add (cList);

				if (splitCount <= count && count % splitCount == 0 && inCount != mThreadSplitCount) {
					_pacialContentsList.Add (inCount, tmpC);
					tmpC = new List<ContentsEntity.Contents> ();
					//Debug.Log ("list add : " + inCount);
					inCount++;
				} else if (_cacheContentsList.Count == count) {
					//Debug.Log ("mod all add");
					_pacialContentsList.Add (inCount, tmpC);
				}
			}

			_asyncResultList = new List<IAsyncResult>();
			foreach (var pC in _pacialContentsList)
			{
				// Create Download List
				foreach (var cList in pC.Value) {
					dic.Add (new Dictionary<string, string> (){
						{"_awsS3Url", string.Format ("{0}{1}", ApiData.GetContentsDataURL (ApiData.API_CONTENTS_REQUEST_URI), cList.file_path)},
						{"dir", string.Format ("{0}{1}/", StreamingAssetsHelper.GetDownLoadPath (), cList.directory)},
						{"file_name",  cList.file_name},
						{"releaseId",  cList.release_id},
						{"versionKey", cList.file_path},
						{"hashFile",   cList.file_hash}
					});
			    }
				List<Dictionary<string, string>> handOf = new List<Dictionary<string, string>> ();
				handOf.AddRange (dic);

				// Async Excute
				_threadQueueCounter++;
				ThreadDownloadDelegate tdDelegate = new ThreadDownloadDelegate (StreamLargeFile);
				IAsyncResult asyncResult = tdDelegate.BeginInvoke (handOf, _threadQueueCounter, new AsyncCallback(DownloadThreadFinished), null);
				_asyncResultList.Add (asyncResult);

				// dic init
				dic = new List<Dictionary<string, string>> ();
			}
			Debug.Log ("Total Thread Count : " + _threadQueueCounter);
		}

	    #endregion

	    #region Private Helper Functions
	    /// <summary>
	    /// Streams the large file.
		/// Calling this function again when the "DownloadProgress" key in the PlayerPrefs present will 
	    ///	continue the download
	    /// </summary>
	    /// <param name="_contentsList">Contents list.</param>
		//private void StreamLargeFile(ContentsEntity.Contents _content)
		private void StreamLargeFile (List<Dictionary<string, string>> _contents, int _threadId)
		{
			string _awsS3Url;
			string dir;
			string file_name;
			string releaseId; //
			string versionKey;//filePath
			string hashFile; //ハッシュ値
			string saveFileName;

			HttpWebResponse tHttpWebResponse = null;
			Stream tHttpWebResponseStream = null;
			byte[] tResponseBytes = null;

			Debug.Log ("StreamLargeFile Thread Start NO." + _threadId);
			Debug.Log (_contents.Count);
			foreach (var _content in _contents) {

				if (_exeptionFlag == true) {
					Debug.LogError ("ThreadId " + _threadId + " / Already Exception at Start");
					break;
				}

				_awsS3Url = null;
				dir = null;
				file_name = null;
				releaseId = null;
				versionKey = null; //filePath
				hashFile = null; //ハッシュ値
				saveFileName = null;

				if (_content.TryGetValue ("_awsS3Url", out _awsS3Url) == true &&
				    _content.TryGetValue ("dir", out dir) == true &&
					_content.TryGetValue ("file_name", out file_name) == true &&
					_content.TryGetValue ("releaseId", out releaseId) == true &&
					_content.TryGetValue ("versionKey", out versionKey) == true &&
					_content.TryGetValue ("hashFile", out hashFile) == true
				    ) {
					if (!File.Exists (dir))
						System.IO.Directory.CreateDirectory (dir);

					saveFileName = string.Format ("{0}", file_name);

					tHttpWebResponse = null;
					tHttpWebResponseStream = null;
					tResponseBytes = null;

					try
					{
						// get resource
						//Debug.Log("取得URL : " + _awsS3Url + "?realse_id=" + releaseId);
						sendHttpRequest (ref tHttpWebResponse, _awsS3Url + "?realse_id=" + releaseId);

						if (tHttpWebResponse.StatusCode != null) {
							if (tHttpWebResponse.StatusCode == HttpStatusCode.OK) {
								FileStream fs = new FileStream (System.IO.Path.Combine(dir, saveFileName), FileMode.Create, FileAccess.Write);
								tHttpWebResponseStream     = tHttpWebResponse.GetResponseStream ();
								BinaryReader tBinaryReader = new BinaryReader (tHttpWebResponseStream);
								tResponseBytes = tBinaryReader.ReadBytes ((int)tHttpWebResponse.ContentLength);
								WriteFromBytesToFile(fs, tResponseBytes, System.IO.Path.Combine(dir, saveFileName));
							}
						}
					}
					catch (Exception tException)
					{
						//Debug.LogError ("DownloadEngine.threadLoop: Exception: " + tException.ToString ());
						Debug.LogError ("ThreadId " + _threadId + " / Exception");
						_exeptionFlag = true;
						break;
					}
					finally
					{
						if (tHttpWebResponseStream != null)
							tHttpWebResponseStream.Close ();
						if (tHttpWebResponse != null)
							tHttpWebResponse.Close ();
					}

					if (_exeptionFlag == true) {
						Debug.LogError ("ThreadId " + _threadId + " / Already Exception at Http After");
						break;
					}

					if (File.Exists (System.IO.Path.Combine(dir, saveFileName)))
					{
						//ハッシュファイルが既存
						if (CacheAssetContentsPrefs.CacheAssetContentsGetString (System.IO.Path.Combine(dir, saveFileName)) != null && CacheAssetContentsPrefs.CacheAssetContentsGetString (System.IO.Path.Combine(dir, saveFileName)) != "")
						{
						    //既にユーザーがローカルにハッシュデータと正確なコンテンツファイルを持っている場合の処理。
						    //バージョンチェック

//Debug.Log (" リリースIDチェック " + releaseId + " == " + CacheAssetContentsPrefs.CacheAssetContentsGetString (versionKey));

							if (releaseId != CacheAssetContentsPrefs.CacheAssetContentsGetString (versionKey) && CacheAssetContentsPrefs.CacheAssetContentsGetString (versionKey) != null && CacheAssetContentsPrefs.CacheAssetContentsGetString (versionKey) != "")
							{
						        // バージョンが違えば再度、新しくローカルに保存されたファイルを直接ハッシュ値を見る処理を入れる。
								// ハッシュファイルが違えばもう一度、再処理
								if (calcMd5 (System.IO.Path.Combine(dir, saveFileName)) != hashFile)
								{
Debug.Log ("不整合0");
Debug.LogError ("不整合0:" + calcMd5 (System.IO.Path.Combine(dir, saveFileName)) + " == " + hashFile);
									// 失敗している
									CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), "");
									CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, "");
									RetryMultipleDownloadCount ();
								}
								else
								{
									//成功している
//Debug.Log ("成功0: " + versionKey);
									CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), hashFile);
									CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, releaseId);
									DownloadCountUp ();
								}
							}
							else if (CacheAssetContentsPrefs.CacheAssetContentsGetString (System.IO.Path.Combine(dir, saveFileName)) != hashFile && releaseId == CacheAssetContentsPrefs.CacheAssetContentsGetString (versionKey))
							{
							    //ハッシュファイルが違えばもう一度、再処理
Debug.Log ("不整合1");
Debug.LogError ("不整合1:" + CacheAssetContentsPrefs.CacheAssetContentsGetString (System.IO.Path.Combine(dir, saveFileName)) + " == " + hashFile);
								// 失敗している
								CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), "");
								CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, "");
								RetryMultipleDownloadCount ();
							}
							else
							{
								// 成功している
//Debug.Log ("成功1: " + versionKey);
								CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), hashFile); 
								CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, releaseId);
								DownloadCountUp ();
							}
					    }
					    else
					    {
						    //新規ユーザーや、キャッシュ削除時に入っていく処理。
							if (calcMd5 (System.IO.Path.Combine(dir, saveFileName)) != hashFile)
							{
							    // ハッシュファイルが違えばもう一度、再処理
Debug.Log ("不整合2");
Debug.LogError (calcMd5 (System.IO.Path.Combine(dir, saveFileName)) + " == " + hashFile);
								// 失敗している
								CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), "");
								CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, "");
								RetryMultipleDownloadCount ();
							}
							else
							{
								//成功している
//Debug.Log ("成功2: " + versionKey);
								CacheAssetContentsPrefs.CacheAssetContentsSetString (System.IO.Path.Combine(dir, saveFileName), hashFile);
								CacheAssetContentsPrefs.CacheAssetContentsSetString (versionKey, releaseId);
								DownloadCountUp ();
							}
						}
					}

					//Debug.Log ("ThreadId " + _threadId + " / " + _currentDownloadCount.ToString() + " FIX 実行ファイルカウント");

				} else {
				    Debug.LogError ("データ渡せてない。");
					_exeptionFlag = true;
					break;
				}
			    
			}
			//System.GC.Collect ();
			Debug.Log ("StreamLargeFile Thread Finish NO." + _threadId);
	    }

		/// <summary>
		/// Writes from bytes to file.
		/// </summary>
		/// <param name="pDestinationFileStream">P destination file stream.</param>
		/// <param name="pSourceBuffer">P source buffer.</param>
		/// <param name="saveFullPath">Save full path.</param>
		public void WriteFromBytesToFile(FileStream pDestinationFileStream, byte[] pSourceBuffer, string saveFullPath)
		{
			try {
				long tLength = pSourceBuffer.Length;
				long tBeforeLength = pDestinationFileStream.Length;

				pDestinationFileStream.Seek(0, SeekOrigin.Begin);
				if (tLength <= 0) {
					_exeptionFlag = true;
				} else {
					pDestinationFileStream.Write(pSourceBuffer, 0, (int)tLength);

					if (tBeforeLength > tLength) {
						pDestinationFileStream.SetLength(tLength);
					}
				}
			} catch (IOException pException) {
				Debug.LogError("IOException:" + pException.Message);
			} finally {
				pDestinationFileStream.Close ();
			}
		}

		/// <summary>
	    /// Downloads the thread finished.
	    /// </summary>
	    /// <param name="dtAsynResult">Dt asyn result.</param>
		private  void DownloadThreadFinished(IAsyncResult dtAsynResult)
		{
			AsyncResult dtCastedAsyncResult = (AsyncResult)dtAsynResult;
			ThreadDownloadDelegate tdDelegate = (ThreadDownloadDelegate)dtCastedAsyncResult.AsyncDelegate;
			tdDelegate.EndInvoke (dtAsynResult);

			//dtCastedAsyncResult.AsyncWaitHandle.WaitOne();
			if (dtAsynResult.IsCompleted == true) {
				
				_threadQueueCounter = _threadQueueCounter - 1;
//				Debug.Log ("Thread Queue Counter : " + _threadQueueCounter);
//				Debug.Log ("DownloadFinished Get Counter : " + GetDownloadCount ());
//				Debug.Log ("Download Counter : " + _downloadListCount);

				if (GetDownloadCount () == _downloadListCount) {
					StopTime ();
					Debug.Log (ElapsedTime + " >>> 経過時間 "); //どれくらいでダウンロード処理終わったか？
					Debug.Log ("ALL FInished Downloaded > " + _currentDownloadCount);
					Debug.Log ("ALL FInished File Check Error > " + _tryCounter);

					_currentDownloadCount = 0;
					_tryCounter = 0;
					if (_tryCounter == 0) {
						_isLoadFin = true; //完了通知用。
						CacheAssetContentsPrefs.CacheAssetContentsFlush (); //データをダウンロードするかどうかの判定等をするためのローカル保存用データ。
					} else {
						Debug.Log ("Download fix broken");
						CacheAssetContentsPrefs.CacheAssetContentsFlush ();
						_exeptionFlag = true;
					}
					return;
				} else {
					if (_threadQueueCounter == 0) {
						Debug.Log ("Counter not fix");
//						Debug.Log ("DownloadFinished Get Counter : " + GetDownloadCount ());
//						Debug.Log ("Download Counter : " + _downloadListCount);
						// AutoRetry
						if (_displayErrorPopupFlag == false && _exeptionFlag == false) {
							Debug.Log ("Counter not fix Auto Retry");
							//_currentDownloadCount = 0;
							CacheAssetContentsPrefs.CacheAssetContentsFlush ();
							_exeptionFlag = true;
						}
					}
				}
			}
		}
		private static IEnumerator deferredInvoke(float seconds, System.Action action)
		{
			yield return new WaitForSeconds(seconds);
			action ();
		}
	    #endregion


	    #region 簡易的なリクエスト処理。

		/// <summary>
	    /// Sends the http request.
	    /// </summary>
	    /// <param name="pDestinationWebResponse">P destination web response.</param>
	    /// <param name="pSourceUrl">P source URL.</param>
		public void sendHttpRequest(ref HttpWebResponse pDestinationWebResponse, string pSourceUrl)
		{
			int tTimeout = mHttpRequestTimeout;
			string tUserAgent = mHttpRequestUserAgent;

			HttpWebRequest tHttpWebRequest = null;
			if (pDestinationWebResponse != null) {
				pDestinationWebResponse.Close ();
				pDestinationWebResponse = null;
			}

			try {
				Uri tUrl = new Uri(pSourceUrl);
				tHttpWebRequest = (HttpWebRequest)WebRequest.Create(tUrl);
				tHttpWebRequest.Timeout = tTimeout;
				tHttpWebRequest.UserAgent = tUserAgent;

				if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) {
					//Debug.Log ("Network conect status : " + System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable());
					pDestinationWebResponse = (HttpWebResponse)tHttpWebRequest.GetResponse();

					// Check response.
					if (pDestinationWebResponse.StatusCode == HttpStatusCode.OK) {						
						return;
					}
				} else {
					Debug.Log ("Network disconect");
					_exeptionFlag = true;
					return;
				}
			} catch (WebException tWebException) {
				pDestinationWebResponse = (HttpWebResponse)tWebException.Response;
				if (pDestinationWebResponse == null) {
					_autoRetry++;
					Debug.LogError ("sendHttpRequest : HttpWebResponse Error {" + tWebException.Message + "}");
					if (_autoRetry <= 3) {
						Debug.Log ("AutoRetry : " + _autoRetry);
						sendHttpRequest (ref pDestinationWebResponse, pSourceUrl);
					} else {
						_exeptionFlag = true;
					}
					return;
				} else {
					if (tWebException.Status == System.Net.WebExceptionStatus.ProtocolError) {
						System.Net.HttpWebResponse errorResponse = (System.Net.HttpWebResponse)tWebException.Response;
						Debug.LogError ("DownloadEngine.sendHttpRequest: {" + tWebException.Message + "} pSourceUrl={" + pSourceUrl + "} StatusCode={" + errorResponse.StatusCode + "} StatusDescription={" + errorResponse.StatusDescription + "}");
					} else {
						Debug.LogError ("sendHttpRequest: {" + tWebException.Message + "} pSourceUrl={" + pSourceUrl + "} ExceptionStatus = {" + tWebException.Status.ToString () + "}");
					}
					_exeptionFlag = true;
					return;
				}
			}
		}

		/// <summary>
		/// Networks the check.
		/// </summary>
		/// <returns><c>true</c>, if check was networked, <c>false</c> otherwise.</returns>
		private bool NetworkCheck() {

			string host = "";
			if (ApiData._env == "product") {
				host = string.Format("http://{0}", ApiData.Instance.PRODUCT_DOMAIN);
			} else if (ApiData._env == "staging") {
				host = string.Format("http://{0}", ApiData.Instance.STG_DOMAIN);
			} else {
				host = string.Format("http://{0}", ApiData.Instance.DEV_DOMAIN);
			}

			HttpWebRequest webreq = null;
			HttpWebResponse webres = null;
			try
			{
				//HttpWebRequestの作成
				webreq = (HttpWebRequest)WebRequest.Create(host);
				//メソッドをHEADにする
				webreq.Method = "HEAD";
				//受信する
				webres = (HttpWebResponse)webreq.GetResponse();
				//応答ステータスコードを表示
				Debug.Log ("NetworkCheck OK : " + webres.StatusCode);
				return true;
			}
			catch (WebException tWebException)
			{
				Debug.Log ("NetworkCheck Error : " + tWebException.Message);
				return false;
			}
			finally
			{
				if (webres != null)
					webres.Close();
			}
		}
		#endregion

		#region 再処理
		private void DownloadCountUp ()
		{
			lock (_lockObj){
				_currentDownloadCount++;
			}
		}
		private int GetDownloadCount ()
		{
			lock (_lockObj){
				return _currentDownloadCount;
			}
		}
		private void RetryMultipleDownloadCount ()
		{
			lock (_lockObj){
			    _tryCounter++;
			}
		}
		#endregion


		#region 共通ポップアップ
		/// <summary>
		/// Https the error popup.
		/// </summary>
		private void HttpIoOrNetworkErrorPopup ()
		{
			GameObject.FindGameObjectWithTag (CommonConstants.NGUI_CAMERA_TAG).GetComponent<UICamera> ().enabled = false;
			new NguiPopupHelper ().CommonPopUpHelper 
			(
				LocalMsgConst.CONECTION_ERROR_TITLE,
				LocalMsgConst.CONECTION_ERROR_TEXT,
				this.gameObject,
				this.gameObject,
				"ReDownload",
				"CancelButton",
				CommonConstants.NGUI_COMMON_POPUP_2CHOICE
			);
		}

		/// <summary>
		/// Res the download.
		/// </summary>
		public void ReDownload ()
		{
			/** SE再生 */
			CriSoundManager.sePlayCue (SoundConstants.CRIADX2_SE_COM_CANCEL);

			_displayNetworkPopupFlag = false;
			_currentDownloadCount = 0;

			CacheAssetContentsPrefs.CacheAssetContentsFlush ();
			MultipleDownload (_cacheContentsList, true);
		}

		public void CancelButton ()
		{
			/** SE再生 */
			CriSoundManager.sePlayCue(SoundConstants.CRIADX2_SE_COM_CANCEL);

			Extention.CommonPlayerPrefs.CommonSetString (LocalConstants.SCENE_BEFORE_QUEUE_SAVE_KEY, Application.loadedLevelName);
			Extention.CommonPlayerPrefs.CommonSetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY, CommonConstants.SCENE_START);
			SceneManager.NextSceneRedirect (CommonConstants.SCENE_START);
		}
		#endregion

		#region ベンチマーク計測用関数群
		public DateTime mStartedDateTime;  //時間計測用
		/// <summary>
		/// 計測された経過時間を返します
		/// </summary>
		public string ElapsedTime { get; private set; }

		/// <summary>
		/// 経過時間の計測を開始します
		/// </summary>
		public void StartTime()
		{
		    mStartedDateTime = DateTime.Now;
		}

		/// <summary>
		/// 経過時間の計測を停止します
		/// </summary>
		public void StopTime()
		{
		    var ts = DateTime.Now - mStartedDateTime;
		    ElapsedTime = string.Format(
		        "{0:00}:{1:00}:{2:00}.{3:00}",
		        ts.Hours, 
		        ts.Minutes, 
		        ts.Seconds,
		        ts.Milliseconds / 10
		    );
		}
		#endregion

		#region ファイルハッシュ値計算関数
		/// <summary>
		/// Calculates the File By md5.
		/// </summary>
		/// <returns>The md5.</returns>
		/// <param name="filename">Filename.</param>
		private string calcMd5 (string path)
		{
			string result;
			using (var stream = new FileStream (path, FileMode.Open,
				                    FileAccess.Read,
				                    FileShare.Read))
			{
				byte[] bytehash = System.Security.Cryptography.MD5.Create ().ComputeHash (stream);
				result = BitConverter.ToString (bytehash).Replace ("-", string.Empty);
				stream.Close ();
			}
			return result;
		}

		#endregion



		#region 試験的に試している箇所。
		/// <summary>
		/// Texures the load set.
		/// ローディングシーンの負荷を減らすため
		/// スポットでダウンロードして表示させる処理を入れる
		/// 現在：[武器アイコン], [ユニットアイコン]、[ユニットDetail], [UnitNo_deck]のpng
		/// </summary>
		/// <param name="targetId">Target identifier.</param>
		/// <param name="type">Type.</param>
		/// <param name="_contents">Contents.</param>
		/// <param name="targetObj">Target object.</param>
		public void TexureLoadSet (string targetId, int type, List<ContentsEntity.Contents> _contents, GameObject targetObj, string option="")
		{
			ContentsEntity.Contents content = new ContentsEntity.Contents ();
			string path = "";
			if (option != "") 
			{
				content = ContentsHandler.GetContentsList (targetId, type.ToString (), _contents, option);
			} else {
				content = ContentsHandler.GetContentsList (targetId, type.ToString (), _contents, targetId);
			}

			if (content != null ) {
				path = string.Format ("{0}{1}{2}", StreamingAssetsHelper.GetDownLoadPath (), content.directory, content.file_name);
				string dir = string.Format ("{0}{1}", StreamingAssetsHelper.GetDownLoadPath (), content.directory);
				if (!File.Exists (dir))
					Directory.CreateDirectory (dir);
				
				//ファイルが存在する場合は、そのままレンダリング。
				if (File.Exists (path) == true) {
					if (CacheAssetContentsPrefs.CacheAssetContentsGetString (content.file_path) == content.release_id)
					{
						Texture2D tex = new Texture2D (4, 4, TextureFormat.ARGB32, false, false);
						tex.LoadImage (GetBinaryLocalLoad (path));
						tex.Apply (true, true);
						targetObj.GetComponent<UITexture> ().mainTexture = tex;
					} else {
						StartCoroutine (SaveAndRendering (targetId, type, _contents, content, targetObj, path, option));
					}
					//ファイルが存在しない場合、データ保管して表示処理。
				} else if (File.Exists (path) == false) {
					StartCoroutine (SaveAndRendering (targetId, type, _contents, content, targetObj, path, option));
				}
			}
        }

		

		//Dictionary <string, GameObject> 
        /// <summary>
        /// Saves to rendering.
        /// </summary>
        /// <param name="targetId">Target identifier.</param>
        /// <param name="type">Type.</param>
        /// <param name="_contents">Contents.</param>
        /// <param name="content">Content.</param>
        /// <param name="targetObj">Target object.</param>
        /// <param name="path">Path.</param>
		private GameObject loadObj;
		private IEnumerator SaveAndRendering (string targetId, int type, List<ContentsEntity.Contents> _contents, ContentsEntity.Contents content, GameObject targetObj, string path, string option = "") 
        {
			GameObject.FindGameObjectWithTag (CommonConstants.NGUI_CAMERA_TAG).GetComponent<UICamera> ().enabled = false;
			//アニメションセット
			if (loadObj == null) {
				loadObj = Instantiate (Resources.Load (ResoucesLoadConst.API_LOADING), Vector3.zero, Quaternion.identity) as GameObject;
				loadObj.transform.localPosition = new Vector3 (0.0f, -20.0f, 0.0f);
			}

			using (WWW www = new WWW(string.Format ("{0}{1}{2}", ApiData.GetContentsDataURL (ApiData.API_CONTENTS_REQUEST_URI), content.file_path, "?realse_id=" + content.release_id))) {
				while (www == null)
				    yield return (www != null);

				while (www.isDone == false)
				    yield return (www.isDone);

				//non texture file
				if (string.IsNullOrEmpty(www.error) == false) {
					Destroy (loadObj);
			        GameObject.FindGameObjectWithTag (CommonConstants.NGUI_CAMERA_TAG).GetComponent<UICamera> ().enabled = true;
					Debug.LogError (www.error);
					yield break;
				} else {
					StartCoroutine (SavedLocalData(path, www.bytes, content));
				}
				while (targetObj == null)
					yield return (targetObj != null);

				targetObj.GetComponent<UITexture> ().mainTexture = www.texture;
			}

			//File.WriteAllBytes (path, www.bytes);

Debug.Log (string.Format ("{0}{1}{2}", ApiData.GetContentsDataURL (ApiData.API_CONTENTS_REQUEST_URI), content.file_path, "?realse_id=" + content.release_id)); 
        }

        /// <summary>
        /// Saveds the local data.
        /// </summary>
        /// <returns>The local data.</returns>
        /// <param name="path">Path.</param>
        /// <param name="bytes">Bytes.</param>
		private IEnumerator SavedLocalData (string path, byte[] bytes, ContentsEntity.Contents content)
		{
			yield return new WaitForSeconds(2.2f);

			File.WriteAllBytes (path, bytes);

			while (File.Exists (path) == false)
				yield return (File.Exists (path) == true);

			if (calcMd5(path) == content.file_hash) {
Debug.Log ("hash save file proccessing.......");
				CacheAssetContentsPrefs.CacheAssetContentsSetString (path, content.file_hash);
				CacheAssetContentsPrefs.CacheAssetContentsSetString (content.file_path, content.release_id);
				CacheAssetContentsPrefs.CacheAssetContentsFlush ();
			} else {
Debug.Log (" no hash file ....... ");
				File.Delete (path);
				CacheAssetContentsPrefs.CacheAssetContentsSetString (path, "");
				CacheAssetContentsPrefs.CacheAssetContentsSetString (content.file_path, "");
				CacheAssetContentsPrefs.CacheAssetContentsFlush ();
			}
Debug.Log ("file save finished");
			Destroy (loadObj);
			GameObject.FindGameObjectWithTag (CommonConstants.NGUI_CAMERA_TAG).GetComponent<UICamera> ().enabled = true;
			
        }


		/// <summary>
        /// Gets the binary locla load.
        /// </summary>
        /// <returns>The Binary Local Load.</returns>
        private byte[] GetBinaryLocalLoad (string path) 
        {
			FileStream   fs = new FileStream(path, FileMode.Open);
			BinaryReader br = new BinaryReader(fs);
            byte[] buf = br.ReadBytes((int)br.BaseStream.Length);
            br.Close();
            return buf;
        }


		/// <summary>
        /// Ises the multiple download ignore.
		/// Loadingシーンのコンテンダウンロードに含めない
        /// </summary>
        /// <returns><c>true</c>, if multiple download ignore was ised, <c>false</c> otherwise.</returns>
		private bool IsMultipleDownloadIgnore (ContentsEntity.Contents contents)
		{
			bool isIgnore = false;
			string exDir = "co/un/dt/0/";
			List<string> ignoreStrList = new List<string> () {
				"co/un/dt",  //ユニットの詳細テキスチャー（ディレクトリ名）
				//"co/un/ic",  //ユニットアイコン（ディレクトリ名）
				"co/wp"   //weapon icon, texture
			};

			//Scent to Scene Filtering
			if (CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY)    == CommonConstants.SCENE_FRIDND
				|| CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY) == CommonConstants.SCENE_STRENGTHENING 
				|| CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY) == CommonConstants.SCENE_USER_STATUS
				|| CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY) == CommonConstants.SCENE_MAIN_QUEST
				|| CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY) == CommonConstants.SCENE_DOMESTICAFFAIRS
//				|| CommonPlayerPrefs.CommonGetString (LocalConstants.SCENE_AFTER_QUEUE_SAVE_KEY) == CommonConstants.SCENE_RAID_BOSS
			)
			{
			   //Debug.Log ("scene jump koko koko ");
				foreach (var list in ignoreStrList)
				{
					//Exeption
					if (contents.directory.Contains (exDir)) 
					{
						isIgnore = false;
						break;
					}

					if (contents.directory.Contains (list))
					{
						//Debug.Log (" マッチしました。 ");
						isIgnore = true;
						break;
					}
					else
					{
						//Debug.Log ("non match");
					}
				}
			}

			return isIgnore;
		} 
		#endregion
	}
}