最近研究了一下游戏内apk包更新的方法。

ios对于应用的管理比较严格,除非热更新脚本,不太可能做到端内大版本包的更新。然而安卓端则没有此限制。因此可以做到不跳到网页或应用商店,就覆盖更新apk包。

Unity最常用的脚本语言就是C#,不做断点续传的情况下,采用C#的网络库,还是比较简单的。重点就是做好相应的异常处理。

C#用于网络访问的方法主要有两种:WebRequest和封装好的WebClient。为了将来能做更多的扩展,我采用更灵活的HttpWebRequest进行请求。为了不阻塞主线程,使用异步接口。

基本做法可参考官方文档https://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest.begingetresponse(v=vs.110).aspx

然而我们知道,Unity4.X对于多线程的支持是很弱的,不推荐使用。因此,无法在下载线程中回调相应的事件。我将回调写在主线程中,用Coroutine去轮询当前的下载状态和进度,并做相应的处理。

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

  1 using UnityEngine;
  2 using System;
  3 using System.Collections;
  4 using System.Threading;
  5 using System.IO;
  6 using System.Net;
  7 using System.Security.Cryptography;
  8 using System.Text;
  9 using System;
 10
 11 public class VersionUpdater : MonoBehaviour
 12 {
 13     public class RequestState
 14     {
 15         public const int BUFFER_SIZE = 1024;
 16         public byte[] BufferRead;
 17         public HttpWebRequest request;
 18         public HttpWebResponse response;
 19         public Stream responseStream;
 20     }
 21
 22     public enum DownloadState
 23     {
 24         DOWNLOADING,
 25         FINISHED,
 26         FAILED
 27     }
 28
 29     public delegate void ProgressCallback(long curr, long length, float rate, DownloadState state);
 30     public ProgressCallback progressCallback;
 31
 32     string url = "";
 33     string installPath = "";
 34     string apkName = "";
 35     string errorMsg = "";
 36
 37     private FileStream fileStream = null;
 38     private long length = 1;
 39     private long curr = 0;
 40     private long last = 0;
 41     private const float UpdateTime = 0.5f;
 42     private float rate = 0;
 43     private DownloadState downState = DownloadState.DOWNLOADING;
 44
 45
 46     public void DownloadApkAsync(string url, string md5, string path, string name)
 47     {
 48         this.url = url;
 49         this.installPath = path;
 50         this.apkName = name;
 51         this.errorMsg = "";
 52         downState = DownloadState.DOWNLOADING;
 53
 54         DownloadApkAsync();
 55     }
 56
 57     private void DownloadApkAsync()
 58     {
 59         if (string.IsNullOrEmpty(url)) return;
 60         if (string.IsNullOrEmpty(installPath)) return;
 61         if (string.IsNullOrEmpty(apkName)) return;
 62
 63         string fullpath = installPath + "/" + apkName;
 64
 65         IAsyncResult result = null;
 66         try
 67         {
 68             fileStream = new FileStream(fullpath, FileMode.Create, FileAccess.Write);
 69
 70             Uri uri = new Uri(url);
 71             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
 72
 73             request.Method = "GET";
 74
 75             RequestState requestState = new RequestState();
 76             requestState.BufferRead = new byte[RequestState.BUFFER_SIZE];
 77             requestState.request = request;
 78
 79             curr = 0;
 80             length = 1;
 81             rate = 0.0f;
 82             downState = DownloadState.DOWNLOADING;
 83             result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(ResponeCallback), requestState);
 84         }
 85         catch (Exception e)
 86         {
 87             errorMsg = "Begin Create Exception!";
 88             errorMsg += string.Format("Message:{0}", e.Message);
 89             StopDownload(result);
 90             downState = DownloadState.FAILED;
 91         }
 92
 93         StartCoroutine(updateProgress());
 94     }
 95
 96     IEnumerator updateProgress()
 97     {
 98         while (curr <= length)
 99         {
100             yield return new WaitForSeconds(UpdateTime);
101
102             rate = (curr - last) / UpdateTime;
103             last = curr;
104
105             if (downState == DownloadState.FAILED)
106             {
107                 Debug.LogError(errorMsg);
108                 if (fileStream != null)
109                     fileStream.Close();
110                 if (progressCallback != null)
111                     progressCallback( curr, length, rate, DownloadState.FAILED);
112                 break;
113             }
114
115             if (progressCallback != null)
116                 progressCallback( curr, length, rate, DownloadState.DOWNLOADING);
117
118             if (downState == DownloadState.FINISHED)
119             {
120                 if (progressCallback != null)
121                     progressCallback( curr, length, rate, DownloadState.FINISHED);
122                 break;
123             }
124         }
125     }
126
127     void StopDownload(IAsyncResult result)
128     {
129         if (result == null) return;
130         RequestState requestState = (RequestState)result.AsyncState;
131         requestState.request.Abort();
132     }
133
134     void ResponeCallback(IAsyncResult result)
135     {
136         try
137         {
138             if (downState != DownloadState.FAILED)
139             {
140                 RequestState requestState = (RequestState)result.AsyncState;
141                 HttpWebRequest request = requestState.request;
142                 requestState.response = (HttpWebResponse)request.EndGetResponse(result);
143
144                 Stream responseStream = requestState.response.GetResponseStream();
145                 requestState.responseStream = responseStream;
146
147                 length = requestState.response.ContentLength;
148
149                 IAsyncResult readResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE, new AsyncCallback(ReadCallback), requestState);
150                 return;
151             }
152         }
153         catch (Exception e)
154         {
155             string msg = "ResponseCallback exception!\n";
156             msg += string.Format("Message:{0}", e.Message);
157             StopDownload(result);
158             errorMsg = msg;
159             downState = DownloadState.FAILED;
160         }
161     }
162
163     void ReadCallback(IAsyncResult result)
164     {
165         try
166         {
167             if (downState != DownloadState.FAILED)
168             {
169                 RequestState requestState = (RequestState)result.AsyncState;
170                 Stream responseStream = requestState.responseStream;
171                 int read = responseStream.EndRead(result);
172                 if (read > 0)
173                 {
174                     fileStream.Write(requestState.BufferRead, 0, read);
175                     fileStream.Flush();
176                     curr += read;
177
178                     IAsyncResult readResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE, new AsyncCallback(ReadCallback), requestState);
179                     return;
180                 }
181                 else
182                 {
183                     Debug.Log("download end");
184                     responseStream.Close();
185                     fileStream.Close();
186
187                     downState = DownloadState.FINISHED;
188                 }
189             }
190         }
191         catch (Exception e)
192         {
193             string msg = "ReadCallBack exception!";
194             msg += string.Format("Message:{0}", e.Message);
195             StopDownload(result);
196             errorMsg = msg;
197             downState = DownloadState.FAILED;
198         }
199     }
200
201
202     public void InstallApk()
203     {
204 #if UNITY_ANDROID && !UNITY_EDITOR
205         Debug.Log("begin install");
206         using (AndroidJavaObject jo = new AndroidJavaObject("com.kevonyang.androidhelper.AndroidHelper"))
207         {
208             if (jo == null)
209             {
210                 WMDebug.Debug.LogError("VersionUpdater: Failed to get com.kevonyang.androidhelper.AndroidHelper");
211                 return;
212             }
213             using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
214             {
215                 if (jc == null)
216                 {
217                     WMDebug.Debug.LogError("VersionUpdater: Failed to get com.unity3d.player.UnityPlayer");
218                     return;
219                 }
220                 AndroidJavaObject m_jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
221                 if (m_jo == null)
222                 {
223                     WMDebug.Debug.LogError("VersionUpdater: Failed to get currentActivity");
224                     return;
225                 }
226
227                 jo.CallStatic("InstallApk", m_jo, installPath, apkName);
228             }
229         }
230 #endif
231     }
232 }

View Code

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

1     public static void InstallApk(Context context, String path, String name) {
2         Intent intent = new Intent(Intent.ACTION_VIEW);
3         intent.setDataAndType(Uri.fromFile(new File(path, name)), "application/vnd.android.package-archive");
4         context.startActivity(intent);
5     }

View Code

转载于:https://www.cnblogs.com/kevonyang/p/5026690.html

Unity游戏内版本更新相关推荐

  1. unity 游戏内实现3连击动画(状态机)

    上节课讲了unity 游戏内实现3连击动画的实现,因为在游戏中我们的连击动画可能会有很多,为了避免使用较多的if  else 我们这节课开始引用状态机来更好的实现效果,那么接下来我们就开始状态机的讲解 ...

  2. unity 游戏内大额数值换算K、M、B、T

    unity 游戏内大额数值换算K.M.B.T 下文是从第六位开始换算,自己根据需求自行修改 /// <summary>/// 数字换算/// </summary>/// < ...

  3. unity游戏内拍照保存

    public class CaptureScreenshotMgr : Utility.Singleton<CaptureScreenshotMgr> { #if UNITY_IPHONE ...

  4. unity 游戏内实现3连击动画

    public class Demo_01 : MonoBehaviour {Animator animator;void Start(){animator = GetComponent<Anim ...

  5. unity热更- 2 游戏大版本更新和热更新

    游戏上线后,遇见bug或者需要更新内容(包括资源,玩法,数值调整,游戏脚本等)的时候,一般有2种做法.第一种,发个新包,然后让玩家下载新的版本:第二种,在游戏内更新,游戏启动时去下载需要更新的资源.第 ...

  6. unity里如何在点击UI时,避免触发游戏内操作。

    如果在游戏中同时有点击UI和检测鼠标点击的操作时,要避免在点击UI时,避免触发游戏内操作. 用eventsystem去检测是否点到ui,方法如下: if (Input.GetMouseButtonDo ...

  7. Unity IOS游戏内好评

    在开发时,所有评分请求都会通过,也就是说每次请求评分,评分对话框都会显示,但无法提交评分.在 Testflight 中,请求都不会被通过,所以如果 Testflight 测试时评分对话框没有正确显示, ...

  8. 《Unity 游戏案例开发大全》一6.5 游戏主场景

    本节书摘来异步社区<Unity 游戏案例开发大全>一书中的第6章,第6.1节,作者: 吴亚峰 , 杜化美 , 于复兴 责编: 张涛,更多章节内容可以访问云栖社区"异步社区&quo ...

  9. Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动

    Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动 使用cookie类型的纹理模拟云层的移动 现实生活中,当阳光直射大地,而天空中又有很多云时,云层的影子总是会投射在大地上,风吹着 ...

  10. Unity 游戏开发技巧集锦之创建自发光材质

    Unity 游戏开发技巧集锦之创建自发光材质 创建自发光材质 自发光材质(self-illuminated material)是指自己会发光的材质.生活中与之相似的例子,就是液晶显示屏上显示的信息,文 ...

最新文章

  1. OpenCV+python:像素运算
  2. Linux环境搭建 手把手教你配置Linux虚拟机
  3. HD_1232畅通工程
  4. HTML禁用Flash文件右键
  5. akka2.5_发布Akka Toolkit 2.3
  6. ubuntu meld比较文件差异
  7. python 灰度直方图_python3+opencv 使用灰度直方图来判断图片的亮暗操作
  8. 非计算机专业《Python程序设计基础》教学参考大纲
  9. Android 给TextView中的字体加上“中间线”
  10. Error--解决使用Application Loader提交ipa包审核时的报错:ERROR ITMS-90168: The binary you uploaded was invalid....
  11. 计算点到SVM超平面的距离
  12. 给定一个序列,判断该序列是否为二叉树查找树的后序遍历序列
  13. 在thinkphp中引入自定义的敏感词库
  14. MySQL数据库介绍
  15. 如何关闭 Mac 版 QQ 上线离线提示音?
  16. 不用工具直接从微软官网下载Win10正式版ISO镜像的技巧
  17. 高三班主任写给学生的一封信(在读大学的要看完)
  18. 联发科:心态决定未来走势
  19. KEAZ128 时钟配置
  20. XP系统启动时滚动条总是时间很长

热门文章

  1. 新版“大伦敦规划”中的交通发展策略
  2. 数据库(一)--数据库系统的核心知识点
  3. Android开发之WebDav
  4. 数据可视化Matplotlib库
  5. tt作曲家简谱打谱软件_每个人的本地作曲家! 会议友好的满意设置
  6. 图机器学习——2.1 节点嵌入:基于随机游走
  7. Python去除小数点后面多余的0
  8. 伏羲六十四卦+36D
  9. 程序员成长之旅——进程间通信(IPC)
  10. 终端数据防泄漏案例分析