下载器断点下载-方便游戏强更

梦想游戏人
目录:
游戏开发
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;
        }
    }
}
Scroll Up