下載器斷點下載-方便遊戲強更 原

Unity下的版本,設計是遊戲內嵌 一個下載器 下載 遊戲 方便遊戲強更

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using UnityEngine;
using System.IO;
using System;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Specialized;
using System.Reflection;

namespace Patches2
{
    //just android suport  IOS直接跳轉app-store 即可
    //用於遊戲內置的下載器 下載
    public class MAX_VERSION
    {
        public string Version = "";
        public string MD5 = "";
        public int FileSize = 5000;//這個file size 只是給玩家看的 實際下載 不用到該變量
        public string Url = "";
        public string RollBackUrl = "";//下載回滾頁面 比如下載fatal error 會直接opel url 
        //this data is legal or illegal 
        public bool IsLegal()
        {
            if (Version != null && MD5 != null && FileSize > 0 && Url != null)
            {
                if (Version.Length >= 5 && MD5.Length > 0 && Url.Length > 5)
                {
                    return true;
                }
            }
            return false;
        }
    }


    //安裝包下載器 支持斷點續傳 支持遊戲內置 下載  下載完成後 調用native api進行安裝
    //其實只需要android 平臺即可 IOS直接跳轉 app-store
    public class InstallerDownloader
    {
        //下載的 apk 存放名字
        public const string ApkName = "hcr.apk";
        //調用該函數 開始安裝  只能在 unity主線程調用
        public static void StartInstallApk(string full_file_path)
        {
#if UNITY_ANDROID
            NativeApi.InstallApk(full_file_path);
#endif
        }
        public enum Status
        {
            None = 0,//未知
            Error, // 下載錯誤  或者超時 
            Downloading, // 下載中  外部可以讀取靜態變量 來顯示下載進度
            Checking,// 處理 下載前邏輯中
            Verifying, // 校驗文件中 可能是下載前 可能是下載後
            OK,//下載完成 可以開始執行安裝操作了
        }
        public class DownloadParam
        {
            public string url;
            public string path_to_save;
            public string file_name;
            public bool enable_break_point;//是否開啓斷點續傳功能
            public string md5;//md5 用於校驗安裝包的完整性
            public bool IsRedirect = false;//是否是重定向 是重定向的話 會忽略 失敗次數統計
        }
        Thread t_download = null;
        public void Terminal()
        {
            if (t_download != null)
            {
                try
                {
                    t_download.Abort();
                }
                catch (Exception e)
                {
                    Debug.LogWarning(e.Message);
                }
                t_download = null;
            }
            CurrentSize = 0;
            TotalSize = 0;
            _Status = Status.None;
        }
        // 需要下載的大小  內部減去了 斷點續傳的 部分
        public static int GetLeftSize(string path_to_save, string file_name, int total_size)
        {
            string full_path = path_to_save + "/" + file_name;
            if (File.Exists(full_path))
            {

                var info = new FileInfo(full_path);
                if (info != null)
                {
                    if (total_size < info.Length)
                    {
                        try
                        {
                            File.Delete(full_path);
                        }
                        catch (Exception e)
                        {

                        }
                        return total_size;
                    }
                    else
                    {
                        return total_size - (int)info.Length;
                    }
                }
            }
            return total_size;
        }
        //改變量只能在 unity主線程調用
        public static string InstallRootDir
        {
            get
            {
#if !UNITY_EDITOR
                return Application.persistentDataPath + "/Installer";
#else
                return "Installer";
#endif
            }
        }
        public void StartDownload(string url, string path_to_save, string file_name, string md5, bool enable_break_point = true)
        {
            if (t_download != null)
            {
                try
                {
                    t_download.Abort();
                }
                catch (Exception e)
                {
                    Debug.LogWarning(e.Message);
                }
            }
            t_download = new Thread(new ParameterizedThreadStart(ThreadFunc));
            IsThreadRunning = true;
            DownloadParam _param = new DownloadParam
            {
                url = url,
                path_to_save = path_to_save,
                file_name = file_name,
                enable_break_point = enable_break_point,
                md5 = md5
            };
            try_times = 0;
            _Status = Status.Checking;
            t_download.Start(_param);
        }
        bool IsThreadRunning = false;

        public static Status _Status = Status.None;
        public int HttpRetCode = 0;

        public static int TotalSize = 0; // 總大小
        public static int CurrentSize = 0; // 當前大小 可用於進度顯示

        int try_times = 0;


        private void DownloadOK()
        {
            _Status = Status.OK;

            //開始安裝流程  調用native api 開始安裝
            Debug.LogWarning("download ok");

        }

        private void ThreadFunc(object _param_call)
        {
            CurrentSize = 0;
            TotalSize = 0;
            Debug.LogWarning("start to download");


            DownloadParam _param = _param_call as DownloadParam;
            if (_param == null)
            {
                IsThreadRunning = false;
                _Status = Status.Error;
                return;
            }
            if (_param.IsRedirect)
            {
                //重定向的話 不處理 失敗 重試次數
                _param.IsRedirect = false;
            }
            else
            {
                //重新下載 或者 分批下載 都會重試計次
                ++try_times;
            }
            if (try_times > 10)
            {
                //fatal error or net error
                _Status = Status.Error;
                return;
            }
            try
            {
                _Status = Status.Verifying;
                if (File.Exists(_param.path_to_save + "/" + _param.file_name))
                {
                    //文件存在的話 檢查一下 是否成功  不成功的話 纔開始下載
                    _Status = Status.Verifying;
                    if (string.IsNullOrEmpty(_param.md5) == false && _param.md5 == Patches.MD5Code.GetMD5HashFromFile(_param.path_to_save + "/" + _param.file_name))
                    {
                        //ok
                        _Status = Status.OK;
                        this.DownloadOK();
                        return;
                    }
                    else
                    {
                        //md5 verify error 需要處理下載 (or斷點下載) 下載完成後 才 再次校驗
                    }
                }
            }
            catch (Exception e)
            {

            }
            _Status = Status.Checking;

            if (_param.enable_break_point == false)
            {
                //無需斷點下載 嘗試暴力刪除文件
                try
                {
                    Directory.Delete(_param.path_to_save, true);
                }
                catch (Exception e)
                {
                    Debug.LogWarning(e.Message);
                }
            }
            if (Directory.Exists(_param.path_to_save) == false)
            {
                try
                {
                    Directory.CreateDirectory(_param.path_to_save);
                }
                catch (Exception e)
                {
                    Debug.LogWarning(e.Message);
                }
            }
            //先打開文件
            Stream file = null;
            using (file = (File.Exists(_param.path_to_save + "/" + _param.file_name)) ? File.OpenWrite(_param.path_to_save + "/" + _param.file_name) : file = File.Create(_param.path_to_save + "/" + _param.file_name))
            {
                /*  try
                  {
                      if (File.Exists(_param.path_to_save + "/" + _param.file_name))
                      {
                          file = File.OpenWrite(_param.path_to_save + "/" + _param.file_name);
                      }
                      else
                      {
                          file = File.Create(_param.path_to_save + "/" + _param.file_name);
                      }
                  }
                  catch (Exception e)
                  {
                      Debug.LogWarning(e.Message);
                  }*/
                try
                {
                    long current_size = file.Length;
                    if (current_size > 0)
                    {
                        file.Seek(current_size, SeekOrigin.Begin);
                    }
                    HttpWebRequest request = null;

                    //如果是發送HTTPS請求  
                    if (_param.url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                    {
                        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                        request = (HttpWebRequest)WebRequest.Create(_param.url);
                    }
                    else
                    {
                        request = (HttpWebRequest)WebRequest.Create(_param.url);
                    }
                    request.ProtocolVersion = new System.Version(1, 1);
                    if (current_size > 0)
                    {
                        request.AddRange((int)current_size);
                        CurrentSize = (int)current_size;
                    }
                    HttpWebResponse response = null;
                    request.Timeout = 5000;
                    request.ReadWriteTimeout = 5000;
                    request.Method = "GET";
                    request.KeepAlive = false;
                    response = (HttpWebResponse)request.GetResponse();

                    var HttpRetCode = response.StatusCode;
                    Debug.Log("InstallDownloader http " + HttpRetCode);


                    if (HttpRetCode == HttpStatusCode.Redirect)
                    {
                        //重定向
                        _param.url = response.Headers["Location"].Trim();
                        response.Close();
                        response = null;
                        request.Abort();
                        request = null;
                        try
                        {
                            file.Close();
                        }
                        catch (Exception e)
                        {
                            Debug.LogWarning(e.Message);
                        }
                        Debug.Log("Redirect " + _param.url);
                        _param.IsRedirect = true;
                        ThreadFunc(_param);
                        return;

                    }
                    else if (HttpRetCode == HttpStatusCode.GatewayTimeout || HttpRetCode == HttpStatusCode.RequestTimeout)
                    {
                        //net error
                        response.Close();
                        response = null;
                        request.Abort();
                        request = null;
                        try
                        {
                            file.Close();
                        }
                        catch (Exception e)
                        {
                            Debug.LogWarning(e.Message);
                        }
                        Debug.Log("timeout");

                        return;

                    }
                    else if (HttpRetCode == HttpStatusCode.OK || HttpRetCode == HttpStatusCode.Created || HttpRetCode == HttpStatusCode.Accepted || HttpRetCode == HttpStatusCode.NonAuthoritativeInformation || HttpRetCode == HttpStatusCode.NoContent || HttpRetCode == HttpStatusCode.ResetContent || HttpRetCode == HttpStatusCode.PartialContent)
                    {
                        if (HttpRetCode != HttpStatusCode.PartialContent)
                        {
                            //如果不是斷點下載 或者服務器不支持 那麼需要 重新下載完整文件
                            try
                            {
                                file.Close();
                                file = null;
                            }
                            catch (Exception e)
                            {
                            }
                            try
                            {
                                Directory.Delete(_param.path_to_save, true);
                            }
                            catch (Exception e)
                            {
                            }
                            try
                            {
                                Directory.CreateDirectory(_param.path_to_save);
                            }
                            catch (Exception e)
                            {
                            }
                            file = File.Create(_param.path_to_save + "/" + _param.file_name);
                        }
                    }
                    else
                    {
                        //req error
                        response.Close();
                        response = null;
                        request.Abort();
                        request = null;
                        try
                        {
                            file.Close();
                        }
                        catch (Exception e)
                        {
                            Debug.LogWarning(e.Message);
                        }
                        Debug.LogWarning("error");
                        return;
                    }

                    //web 請求處理完成了 開始處理 接受數據了
                    long total_len = response.ContentLength;

                    TotalSize = (int)total_len + (int)current_size;
                    if (current_size < TotalSize)
                    {
                        if (current_size > 0)
                        {
                            //   request.AddRange((int)current_size);
                            CurrentSize = (int)current_size;
                        }
                        Stream web = request.GetResponse().GetResponseStream();
                        byte[] _cache = new byte[10240]; // 10kb
                        int down_size = 0;
                        int read_size = web.Read(_cache, 0, 10240);
                        int total_read_size = 0;
                        _Status = Status.Downloading;
                        while (read_size > 0)
                        {
                            _Status = Status.Downloading;
                            file.Write(_cache, 0, read_size);
                            total_read_size += read_size;

                            down_size += read_size;
                            CurrentSize += read_size;
                            //    Debug.LogError("download ing " + CurrentSize + "         " + TotalSize);
                            file.Flush();
                            read_size = web.Read(_cache, 0, 10240);
                        }
                        file.Close();
                        file = null;
                        web.Close();
                        web = null;
                        response.Close();
                        response = null;
                        request.Abort();
                        request = null;


                        if (current_size + down_size < TotalSize)
                        {
                            //下載文件 長度不夠 需要重新下載
                            Debug.LogWarning("file is smaller will re-try");
                            ThreadFunc(_param);
                            return;
                        }
                        else if (current_size + down_size > TotalSize)
                        {
                            //下載的長度 超過了 實際長度 文件已經損壞 重新下載把
                            try
                            {
                                Directory.Delete(_param.path_to_save, true);
                            }
                            catch (Exception e)
                            {
                                Debug.LogWarning(e.Message);
                            }
                            Debug.LogWarning("file is bigger will delete and re-download");

                            ThreadFunc(_param);
                            return;
                        }
                        else
                        {
                            //下載文件成功 開始校驗MD5
                            _Status = Status.Verifying;

                            if (string.IsNullOrEmpty(_param.md5) == false && _param.md5 == Patches.MD5Code.GetMD5HashFromFile(_param.path_to_save + "/" + _param.file_name))
                            {
                                //ok
                            }
                            else
                            {
                                //md5 verify error 嘗試重新下載
                                try
                                {
                                    file.Close();
                                    file = null;
                                    response.Close();
                                    response = null;
                                    request.Abort();
                                    request = null;
                                }
                                catch (Exception e)
                                {
                                }
                                try
                                {
                                    Directory.Delete(_param.path_to_save, true);
                                }
                                catch (Exception e)
                                {
                                    Debug.LogWarning(e.Message);
                                }
                                ThreadFunc(_param);
                                return;
                            }
                            _Status = Status.OK;
                        }
                    }
                    else if (current_size == total_len)
                    {//當前文件和 服務器文件大小一樣 默認爲 下載完成 需要校驗MD5

                        try
                        {
                            file.Close();
                            file = null;
                            response.Close();
                            response = null;
                            request.Abort();
                            request = null;
                        }
                        catch (Exception e)
                        {
                        }
                        Debug.LogWarning("file is  req just done");
                        _Status = Status.Verifying;

                        if (string.IsNullOrEmpty(_param.md5) == false && _param.md5 == Patches.MD5Code.GetMD5HashFromFile(_param.path_to_save + "/" + _param.file_name))
                        {
                            //ok
                        }
                        else
                        {
                            //md5 verify error 嘗試重新下載
                            try
                            {
                                file.Close();
                                file = null;
                                response.Close();
                                response = null;
                                request.Abort();
                                request = null;
                            }
                            catch (Exception e)
                            {
                            }
                            try
                            {
                                Directory.Delete(_param.path_to_save, true);
                            }
                            catch (Exception e)
                            {
                                Debug.LogWarning(e.Message);
                            }
                            ThreadFunc(_param);
                            return;
                        }
                        _Status = Status.OK;
                    }
                    else
                    {
                        //當前文件超過了 大小 需要重新下載
                        try
                        {
                            Directory.Delete(_param.path_to_save, true);
                        }
                        catch (Exception e)
                        {
                            Debug.LogWarning(e.Message);
                        }
                        Debug.LogWarning("file is bigger will delete and re-download  2");

                        try
                        {
                            file.Close();
                            file = null;
                            response.Close();
                            response = null;
                            request.Abort();
                            request = null;
                        }
                        catch (Exception e)
                        {
                        }

                        ThreadFunc(_param);
                        return;
                    }
                    //走到了這裏 都當作文件下載成功 並且校驗成功 可以開始安裝了
                    _Status = Status.OK;
                    this.DownloadOK();
                }
                catch (Exception ee)
                {
                    //整個下載流程出了異常錯誤 
                    Debug.LogWarning(ee.Message);
                    _Status = Status.Checking;
                    try
                    {
                        if (file != null)
                        {
                            file.Close();
                            file = null;
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.LogWarning(e.Message);
                    }
                    ThreadFunc(_param);
                    return;
                }
            }
        }
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章