/* ******************************************************************************** *Copyright(C),coolae.net *Author: chenbin *Version: 2.0 *Date: 2017-01-09 *Description: WWW包装 *Others: *History: ********************************************************************************* */ using UnityEngine; using System.Collections; using UnityEngine.Networking; using System.Collections.Generic; namespace Coolape { public enum CLAssetType { text, bytes, texture, assetBundle, audioClip, } public class WWWEx : MonoBehaviour { public static WWWEx self; public static Hashtable wwwMapUrl = new Hashtable(); public static Hashtable wwwMap4Check = new Hashtable(); public static Hashtable wwwMap4Get = new Hashtable(); public int checkTimeOutSec = 5; public delegate void RedCallback(string url); public bool isCheckWWWTimeOut = false; public bool isPrintUrl = false; float lastCheckTimeOutTime = 0; public WWWEx() { self = this; } private void Update() { if (!isCheckWWWTimeOut) return; if (Time.realtimeSinceStartup - lastCheckTimeOutTime > 0) { lastCheckTimeOutTime = Time.realtimeSinceStartup + 3; checkWWWTimeout(); } if (wwwMap4Check.Count <= 0) { isCheckWWWTimeOut = false; } if (wwwMapUrl.Count <= 0) { enabled = false; } } IEnumerator exeWWW(UnityWebRequest www, string url, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes, RedCallback redrectioncallback = null) { if (isPrintUrl && url.StartsWith("http://")) { Debug.LogError(url); } wwwMapUrl[url] = www; if (isCheckTimeout) { addCheckWWWTimeout(www, url, checkTimeOutSec, failedCallback, orgs, maxFailTimes, failedTimes, redrectioncallback); } using (www) { yield return www.SendWebRequest(); try { uncheckWWWTimeout(www, url); if (www.isNetworkError || www.isHttpError) { long retCode = www.responseCode; Debug.LogError(www.error + ",retCode==" + retCode + "," + url); if (retCode == 300 || retCode == 301 || retCode == 302) { // 重定向处理 string url2 = www.GetResponseHeader("Location"); if (string.IsNullOrEmpty(url2)) { Utl.doCallback(failedCallback, null, orgs); } else { if (redrectioncallback != null) { redrectioncallback(url2); } } } else { if (maxFailTimes > failedTimes + 1) { redrectioncallback(url); } else { Utl.doCallback(failedCallback, null, orgs); } } } else { object content = null; switch (type) { case CLAssetType.text: content = www.downloadHandler.text; break; case CLAssetType.bytes: content = www.downloadHandler.data; break; case CLAssetType.texture: content = DownloadHandlerTexture.GetContent(www); break; case CLAssetType.assetBundle: content = DownloadHandlerAssetBundle.GetContent(www); break; case CLAssetType.audioClip: content = DownloadHandlerAudioClip.GetContent(www); break; } Utl.doCallback(successCallback, content, orgs, www); } } catch (System.Exception e) { Debug.LogError(e); if (maxFailTimes > failedTimes + 1) { redrectioncallback(url); } else { Utl.doCallback(failedCallback, null, orgs); } } } wwwMap4Get.Remove(url); wwwMapUrl.Remove(url); if (www != null) { www.Dispose(); www = null; } } public static void setWWWHeader(UnityWebRequest www, object header) { if (header != null) { if (header is XLua.LuaTable) { ((XLua.LuaTable)header).ForEach((key, val) => { www.SetRequestHeader(key, val.ToString()); }); } else if (header is Hashtable) { Hashtable m = ((Hashtable)header); foreach (var k in m.Keys) { www.SetRequestHeader(k.ToString(), m[k].ToString()); } } } } /// /// Get the specified url, type, successCallback, failedCallback, orgs and isCheckTimeout. /// /// The get. /// URL. /// Type. /// Success callback. /// Failed callback. /// Orgs.回调参数 /// If set to true is check timeout. 检测超时 public static UnityWebRequest get(string url, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _get(url, null, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } public static UnityWebRequest get(string url, object header, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _get(url, header, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } public static UnityWebRequest getWithHeader(string url, object header, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _get(url, header, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _get(string url, object header, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes ) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; UnityWebRequest www = null; switch (type) { case CLAssetType.texture: www = UnityWebRequestTexture.GetTexture(url); break; case CLAssetType.assetBundle: www = UnityWebRequestAssetBundle.GetAssetBundle(url); break; default: www = UnityWebRequest.Get(url); break; } setWWWHeader(www, header); Coroutine cor = self.StartCoroutine(self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _get(url2, header, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } public static UnityWebRequest post(string url, object header, string jsonMap, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { Hashtable map = JSON.DecodeMap(jsonMap); return post(url, header, map, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes); } public static UnityWebRequest post(string url, object header, Hashtable map, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { try { self.enabled = true; WWWForm data = new WWWForm(); if (map != null) { foreach (DictionaryEntry cell in map) { if (cell.Value is int) { data.AddField(cell.Key.ToString(), int.Parse(cell.Value.ToString())); } else if (cell.Value is byte[]) { data.AddBinaryData(cell.Key.ToString(), (byte[])(cell.Value)); } else { data.AddField(cell.Key.ToString(), cell.Value.ToString()); } } } return post(url, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes); } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } public static UnityWebRequest post(string url, object header, WWWForm data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _post(url, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _post(string url, object header, WWWForm data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; UnityWebRequest www = UnityWebRequest.Post(url, data); setWWWHeader(www, header); Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _post(url2, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } public static UnityWebRequest postString(string url, object header, string strData, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _postString(url, header, strData, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _postString(string url, object header, string strData, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; UnityWebRequest www = UnityWebRequest.Post(url, strData); setWWWHeader(www, header); Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _postString(url2, header, strData, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } // 因为lua里没有bytes类型,所以不能重载,所以只能通方法名来 public static UnityWebRequest postBytes(string url, object header, byte[] bytes, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _postBytes(url, header, bytes, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _postBytes(string url, object header, byte[] bytes, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { self.enabled = true; UnityWebRequest www = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST); setWWWHeader(www, header); UploadHandlerRaw MyUploadHandler = new UploadHandlerRaw(bytes); DownloadHandlerBuffer downloadHandler = new DownloadHandlerBuffer(); //MyUploadHandler.contentType = "application/x-www-form-urlencoded"; // might work with 'multipart/form-data' www.uploadHandler = MyUploadHandler; www.downloadHandler = downloadHandler; Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _postBytes(url2, header, bytes, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } public static UnityWebRequest put(string url, object header, string data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _put(url, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _put(string url, object header, string data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; UnityWebRequest www = UnityWebRequest.Put(url, data); setWWWHeader(www, header); Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _put(url2, header ,data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } public static UnityWebRequest put(string url, object header, byte[] data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _put(url, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _put(string url, object header, byte[] data, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; UnityWebRequest www = UnityWebRequest.Put(url, data); setWWWHeader(www, header); Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _put(url2, header, data, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } /// /// Uploads the file.上传文件 /// /// The file. /// URL. /// Section name. 对应java里的new FilePart("sectionName", f) /// File name. /// File content. /// Type. /// Success callback. /// Failed callback. /// Orgs. /// If set to true is check timeout. public static UnityWebRequest uploadFile(string url, string sectionName, string fileName, byte[] fileContent, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _uploadFile(url, null, sectionName, fileName, fileContent, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } public static UnityWebRequest uploadFile(string url, object header, string sectionName, string fileName, byte[] fileContent, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout = true, int maxFailTimes = 1) { return _uploadFile(url,header, sectionName, fileName, fileContent, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, 0); } private static UnityWebRequest _uploadFile(string url, object header, string sectionName, string fileName, byte[] fileContent, CLAssetType type, object successCallback, object failedCallback, object orgs, bool isCheckTimeout, int maxFailTimes, int failedTimes) { try { if (string.IsNullOrEmpty(url)) return null; self.enabled = true; MultipartFormFileSection fileSection = new MultipartFormFileSection(sectionName, fileContent, fileName, "Content-Type: multipart/form-data;"); List multForom = new List(); multForom.Add(fileSection); UnityWebRequest www = UnityWebRequest.Post(url, multForom); setWWWHeader(www, header); Coroutine cor = self.StartCoroutine( self.exeWWW(www, url, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes, (url2) => { _uploadFile(url2, header, sectionName, fileName, fileContent, type, successCallback, failedCallback, orgs, isCheckTimeout, maxFailTimes, failedTimes + 1); })); wwwMap4Get[url] = cor; return www; } catch (System.Exception e) { Debug.LogError(e); Utl.doCallback(failedCallback, null, orgs); return null; } } /// /// Checks the WWW timeout. /// /// Www. /// Check progress sec. /// Timeout callback. public static void addCheckWWWTimeout(UnityWebRequest www, string url, float checkProgressSec, object timeoutCallback, object orgs, int maxFailTimes, int failedTimes, RedCallback redrectioncallback) { if (www == null || www.isDone) return; self.enabled = true; self.isCheckWWWTimeOut = true; checkProgressSec = checkProgressSec <= 0 ? 5 : checkProgressSec; //UnityEngine.Coroutine cor = self.StartCoroutine(doCheckWWWTimeout(www, url, checkProgressSec, timeoutCallback, 0, orgs)); NewList list = ObjPool.listPool.borrowObject(); list.Add(url); list.Add(timeoutCallback); list.Add(checkProgressSec); list.Add(orgs); list.Add(0f); list.Add(0f); list.Add(Time.realtimeSinceStartup + checkProgressSec); list.Add(maxFailTimes); list.Add(failedTimes); list.Add(redrectioncallback); wwwMap4Check[www] = list;//DateEx.nowMS + checkProgressSec*1000; } public static void checkWWWTimeout() { NewList keys = ObjPool.listPool.borrowObject(); keys.AddRange(wwwMap4Check.Keys); UnityWebRequest www = null; NewList list = null; for (int i = 0; i < keys.Count; i++) { www = keys[i] as UnityWebRequest; if (www != null) { list = wwwMap4Check[www] as NewList; if (list != null) { doCheckWWWTimeout(www, list); } } } keys.Clear(); ObjPool.listPool.returnObject(keys); keys = null; } public static void doCheckWWWTimeout(UnityWebRequest www, NewList list) { //yield return new WaitForSeconds(checkProgressSec); string url = list[0] as string; object timeoutCallback = list[1]; float checkProgressSec = (float)(list[2]); object orgs = list[3]; float oldProgress = (float)(list[4]); float oldSize = (float)(list[5]); float lastCheckTime = (float)(list[6]); int maxFailTimes = (int)(list[7]); int failedTimes = (int)(list[8]); RedCallback redrectioncallback = list[9] as RedCallback; if (Time.realtimeSinceStartup - lastCheckTime < 0) { return; } try { if (www != null) { if (www.isDone) { wwwMap4Check.Remove(www); list.Clear(); ObjPool.listPool.returnObject(list); } else { float curProgress = 0; float curSize = 0; if (www.method == "PUT") { curProgress = www.uploadProgress; if (www.uploadHandler != null && www.uploadHandler.data != null) { curSize = www.uploadHandler.data.Length; } } else { curProgress = www.downloadProgress; if (www.downloadHandler != null && www.downloadHandler.data != null) { curSize = www.downloadHandler.data.Length; } } if (Mathf.Abs(curProgress - oldProgress) < 0.0001f && Mathf.Abs(curSize - oldSize) < 0.0001f) { //说明没有变化,可能网络不给力 if (maxFailTimes > failedTimes + 1) { if (redrectioncallback != null) { redrectioncallback(url); } } else { Coroutine corout = wwwMap4Get[url] as Coroutine; if (corout != null) { self.StopCoroutine(corout); } wwwMap4Get.Remove(url); wwwMapUrl.Remove(url); list.Clear(); ObjPool.listPool.returnObject(list); wwwMap4Check.Remove(www); www.Abort(); www.Dispose(); www = null; Debug.LogError("www time out! url==" + url); Utl.doCallback(timeoutCallback, null, orgs); } } else { //Coroutine cor = self.StartCoroutine(doCheckWWWTimeout(www, url, checkProgressSec, timeoutCallback, curProgress, orgs)); list[4] = curProgress; list[5] = curSize; list[6] = Time.realtimeSinceStartup + checkProgressSec; wwwMap4Check[www] = list; } } } } catch (System.Exception e) { Debug.LogError(e); } } public static void uncheckWWWTimeout(UnityWebRequest www, string url) { try { if (www != null && !ReferenceEquals(www, null)) { wwwMap4Get.Remove(url); NewList list = wwwMap4Check[www] as NewList; if (list != null) { list.Clear(); ObjPool.listPool.returnObject(list); } wwwMap4Check.Remove(www); } } catch (System.Exception e) { Debug.LogError(e); } } public static UnityWebRequest getWwwByUrl(string Url) { if (string.IsNullOrEmpty(Url)) return null; return wwwMapUrl[Url] as UnityWebRequest; } static void onWWWFailed() { } } }