Unity大版本更新APK下载安装

痞子三分冷 提交于 2019-12-02 02:42:50

当有大的版本更新时候我们会有重新下载安装包的需求


首先需要定义下载的状态和传入下载线程的请求状态,然后是下载的路径(可能还需要文件MD5码)以及安装路径等必要的变量,最后为了显示当前的下载进度、下载速度等,需要开启一个Coroutine或者在Update中不断查询当前下载状态,是否有异常,以及是否已经下载完毕。如果下载完毕,则校验文件,并开始安装。

 using UnityEngine;
 using System;
 using System.Collections;
 using System.Threading;
 using System.IO;
 using System.Net;
 using System.Security.Cryptography;
 using System.Text;
 using System;

namespace LuaFramework
{
  
    public class VersionUpdateManager : Manager
    {

        public class RequestState
        {
            public const int BUFFER_SIZE = 1024;
            public byte[] BufferRead;
            public HttpWebRequest request;
            public HttpWebResponse response;
            public Stream responseStream;
        }

        public enum DownloadState
        {
            DOWNLOADING,
            FINISHED,
            FAILED
        }
      

        public delegate void ProgressCallback(long curr, long length, float rate, DownloadState state);
        public ProgressCallback progressCallback;

        string url = "";
        string installPath = "";
        string apkName = "";
        string errorMsg = "";

        private FileStream fileStream = null;
        private long length = 1;
        private long curr = 0;
        private long last = 0;
        private const float UpdateTime = 0.5f;
        private float rate = 0;
        private DownloadState downState = DownloadState.DOWNLOADING;

        void Awake()
        {
            Debug.LogError("版本更新检测初始化");
            //暂时再此调用
            DownloadApkAsync("安装包地址", "" , Application.persistentDataPath , "test.apk");
        }
      

        public void DownloadApkAsync(string url, string md5, string path, string name)
        {
            this.url = url;
            this.installPath = path;
            this.apkName = name;
            this.errorMsg = "";
            downState = DownloadState.DOWNLOADING;

            DownloadApkAsync();
        }

        private void DownloadApkAsync()
        {
            if (string.IsNullOrEmpty(url)) return;
            if (string.IsNullOrEmpty(installPath)) return;
            if (string.IsNullOrEmpty(apkName)) return;

            string fullpath = installPath + "/" + apkName;

            IAsyncResult result = null;
            try
            {
                fileStream = new FileStream(fullpath, FileMode.Create, FileAccess.Write);

                Uri uri = new Uri(url);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                request.Method = "GET";

                RequestState requestState = new RequestState();
                requestState.BufferRead = new byte[RequestState.BUFFER_SIZE];
                requestState.request = request;

                curr = 0;
                length = 1;
                rate = 0.0f;
                downState = DownloadState.DOWNLOADING;
                result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(ResponeCallback), requestState);
            }
            catch (Exception e)
            {
                errorMsg = "Begin Create Exception!";
                errorMsg += string.Format("Message:{0}", e.Message);
                StopDownload(result);
                downState = DownloadState.FAILED;
                
            }
            StartCoroutine(updateProgress());
        }

        IEnumerator updateProgress()
        {

            while (curr <= length)
            {
                yield return new WaitForSeconds(UpdateTime);
                rate = (curr - last) / UpdateTime;
                last = curr;

                if (downState == DownloadState.FAILED)
                {
                    Debug.LogError(errorMsg);
                    if (fileStream != null)
                        fileStream.Close();
                    if (progressCallback != null)
                        progressCallback(curr, length, rate, DownloadState.FAILED);
                    break;
                }
                if (progressCallback != null)
                    progressCallback(curr, length, rate, DownloadState.DOWNLOADING);

                if (downState == DownloadState.FINISHED)
                {
                    if (progressCallback != null)
                        progressCallback(curr, length, rate, DownloadState.FINISHED);
                    Debug.LogError("下载完成");
                    this.InstallApk();
                    break;
                }
            }
        }

        void StopDownload(IAsyncResult result)
        {
            if (result == null) return;
            RequestState requestState = (RequestState)result.AsyncState;
            requestState.request.Abort();
        }

        void ResponeCallback(IAsyncResult result)
        {
            try
            {
                if (downState != DownloadState.FAILED)
                {
                    RequestState requestState = (RequestState)result.AsyncState;
                    HttpWebRequest request = requestState.request;
                    requestState.response = (HttpWebResponse)request.EndGetResponse(result);

                    Stream responseStream = requestState.response.GetResponseStream();
                    requestState.responseStream = responseStream;

                    length = requestState.response.ContentLength;

                    IAsyncResult readResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE, new AsyncCallback(ReadCallback), requestState);
                    return;
                }
            }
            catch (Exception e)
            {
                string msg = "ResponseCallback exception!\n";
                msg += string.Format("Message:{0}", e.Message);
                StopDownload(result);
                errorMsg = msg;
                downState = DownloadState.FAILED;
            }
        }

        void ReadCallback(IAsyncResult result)
        {
            try
            {
                if (downState != DownloadState.FAILED)
                {
                    RequestState requestState = (RequestState)result.AsyncState;
                    Stream responseStream = requestState.responseStream;
                    int read = responseStream.EndRead(result);
                    if (read > 0)
                    {
                        fileStream.Write(requestState.BufferRead, 0, read);
                        fileStream.Flush();
                        curr += read;

                        IAsyncResult readResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE, new AsyncCallback(ReadCallback), requestState);
                        return;
                    }
                    else
                    {
                        Debug.Log("download end");
                        responseStream.Close();
                        fileStream.Close();

                        downState = DownloadState.FINISHED;
                        Debug.LogError("下载完成111");
                    }
                }
            }
            catch (Exception e)
            {
                string msg = "ReadCallBack exception!";
                msg += string.Format("Message:{0}", e.Message);
                StopDownload(result);
                downState = DownloadState.FAILED;
            }
        }

        private AndroidJavaObject _GetCurrentAndroidJavaObject()
        {
            AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            return jc.GetStatic<AndroidJavaObject>("currentActivity");
        }

        public void InstallApk()
        {
            Debug.LogError("开始安装");
#if UNITY_ANDROID && !UNITY_EDITOR         
            AndroidJavaObject jo = _GetCurrentAndroidJavaObject();
            string path = Application.persistentDataPath + "/test.apk";
             Debug.LogError("begin install" + path);
            bool b = jo.CallStatic<bool>("installAPK", new object[] { path });
            if (b == true)
            {
                Debug.LogError("安装成功");
            }else
                Debug.LogError("安装失败");
            //using (AndroidJavaObject jo = new AndroidJavaObject("com.kevonyang.androidhelper.AndroidHelper"))
            //{
            //    if (jo == null)
            //    {
            //        Debug.LogError("VersionUpdater: Failed to get com.kevonyang.androidhelper.AndroidHelper");
            //        return;
            //    }
            //    using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            //    {
            //        if (jc == null)
            //        {
            //            Debug.LogError("VersionUpdater: Failed to get com.unity3d.player.UnityPlayer");
            //            return;
            //        }
            //        AndroidJavaObject m_jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
            //        if (m_jo == null)
            //        {
            //            Debug.LogError("VersionUpdater: Failed to get currentActivity");
            //            return;
            //        }

            //        jo.CallStatic("InstallApk", m_jo, installPath, apkName);
            //    }
            //}          
#endif
        }
    }
}

 

在下载完毕后,需要写一个java类,并在里面调用安装接口。内容很简单,只需要简单的启动一个安装的Intent就可以了,随后就会出现系统提示,是否覆盖安装。至此,游戏内的下载及安装全部完成,等待覆盖安装完毕即可从新的客户端启动。

    public static boolean installAPK(String apkPath)
    {
        File apkFile = new File(apkPath);
        if (apkFile.exists())
        {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            if (Build.VERSION.SDK_INT >= 24)
            {
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                Uri contentUri = FileProvider.getUriForFile(UnityPlayer.currentActivity, UnityPlayer.currentActivity.getPackageName() + ".fileprovider", apkFile);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
            }
            else
            {
                intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            // if (UnityPlayer.currentActivity.getPackageManager().queryIntentActivities(intent, 0).size() > 0) {
            UnityPlayer.currentActivity.startActivity(intent);
            //  }
            return true;
        }
        else
        {
            return false;
        }
    }

AndroidManifest文件添加权限


<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!