web打包app(h5+app)版本自动更新的实现-ITB运维部落—http://www.itbcn.cn—ITB运维技术交流之家平台
记录工作点滴
分享运维知识

web打包app(h5+app)版本自动更新的实现

背景说明

web打包的app(也称为h5+app),是指将基于html5等移动端web技术,开发的web应用打包成的app。区别于原生app,5+app相当于给web应用加上了一层本地程序(ios、android等)的壳子。其原理是,使用了原生程序的webview组件,即在原生程序内部调用内置浏览器,实现应用的核心功能。h5+app打包app使用的hbuiderx打包的,打包相关的方法可以参考,本人文章:
将H5站点打包成app完美攻略

原生app自动更新实现

原生app主要是基于ios和android的原生平台app,其打包原理,主要源于平台分发管理的不同和行业通用做法。ios是闭源的独立平台,apple store只有一个平台;android碎片化比较严重,世面上有上万家app store。各平台审核机制又不一样。这些方面都决定了ios和android的app,更新策略有所不同。
行业经验
Android 和 iOS 应用的更新都可以不用做,可以让第三方应用商店来帮你做,你只需更改应用的版本就行了。目前 Android 的通用做法是,在应用内检查版本号,通过跟服务器的版本号来对比,版本号不同就更新,具体的做法是可以在应用内写个下载程序,也可以在弹出浏览器来下载。iOS 应用如果要上传到 app store,是不允许在应用内检查更新的,否则不让上架,iOS 的更新更简单,让苹果 app store 来做就行了,你在 build 的时候,改变版本号就行,希望对你有帮助。

以下ios和android app自动更新的实现,都是基于行业最佳实践。

android自动更新实现

在服务器需要一个json或xml文件,如:check.json。

#check.json
[
  {
    "version":1, 
    "name":1.0, 
    "miniVersion":1,
    "description":"asdfas/n", 
    "forceUpdate":false,   
    "size":3065,  
    "uri":"h5app-1.0.apk" 
  },
  {
    "version":2,
    "name":1.1,
    "miniVersion":1,
    "description":"bbb/n",
    "forceUpdate":"true",
    "size":3065,
    "uri":"h5app-1.1.apk"
  },
  {
    "version":3,
    "name":1.1,
    "miniVersion":1,
    "description":"bbb/n",
    "forceUpdate":"false",
    "size":3065,
    "uri":"h5app-1.1.apk"
  }
]

以上文件维护平台app的发布版本,基于些版本,提供apk自动更新。

“version”:1, #int 类型版本号,版本是递增的
“name”:1.0,
“miniVersion”:1, #平台支持最小的版本号,小于些的版本都会强制更新
“description”:“asdfas/n”, #版本说明
“forceUpdate”:false, #版本是否强制更新
“size”:3065, #app大小,单位kb
“uri”:“h5app-1.0.apk” #app下载路径

程序文件结构如下:
image.png
version:发布apk包目录。
check.json:apk版本配置文件。

相关接口如下

 /**
     * h5app 版本检查[android]:方法只提供android版本的app,版本检查,对于ios,依赖apple store的版本管理,进行版本检查和更新。目前,苹果store app上架审核不允许程序进行自动版本更新。
     * @return AppVersionBean 
     * version 更新版本,始终为平台最新版本app
     * uri为app下载的url
     */
    @RequestMapping("h5app/check")
    @ResponseBody
    public AppVersionBean h5appCheck(String currentVersion) {
        AppVersionBean result = new AppVersionBean();
        return result;
    }

    /**
     * h5app下载
     * @return
     */
    @RequestMapping("h5app")
    @ResponseBody
    public Object h5app(HttpRequest request) {
        //request 请求设备类型,ios 、android做不同的返回
        return null;
    }

    /**
     * h5app 应用版本更新下载[android]:
     * @param uri 文件名
     * @return
     */
    
   /**
   * uri为程序下载文件名
   */
    @RequestMapping("h5app/{uri}")
    public void getH5app(@PathVariable String uri) {
        //下载实现

    }

    /**
     * app版本信息实体类
     */
    @Data
    class AppVersionBean {

        Integer version;
        String name;
        Integer miniVersion;
        String description;
        //是否强制更新
        boolean forceUpdate;
        Long size;
        String uri;
        //是否有更新
        boolean isUpdate;
    }

如上接口,app检查更新接口传入currentVersion。服务端根据currentVersion和服务端版本管理配置(miniVersion,forceUpdate等)确定app是否更新和是否强制更新。
app启动或者提供检查更新按钮,调用后台检查更新接口。

image.png

客户端保存currentVersion和忽略版本列表,用于来检查更新,忽略的版本不再提示更新。立即更新,调用下载apk接口下载程序,完成更新。具体本地android代码,不在此提供,网上有很多。

ios自动更新实现

ios apk自动更新,基于apple store来实现。基于现在的上架审核策略,不允许使用检查更新,让苹果 app store 来做就行了,你在 build 的时候,改变版本号就行。

当然如果审核能通过,可以加入检查更新的逻辑,主要思路如下:
1.版本自动更新一般采用API对应的方式 获取当前App Store上版本号 于本地存储的版本号对比。
2.由服务端返回版本控制升级(容易审核不通过)
参考地址(很详细)
https://blog.csdn.net/lcg910978041/article/details/51426084
问题:
https://www.jianshu.com/p/9e237cd62129

h5+app的特点说明

h5+app的特点是本地app只是壳子,应用整体在web服务上。app更新比较少,但是也可能涉及打包更新,更新需要在h5的web服务实现。

h5+app自动更新实现

image.png
如上为打包配置(配置实现版本更新):
var H5_SERVER = “http://www.h5net.com/m/?origin=app&currentVersion=1”;
origin:标志h5,是app访问,配置使web服务能兼容手机web和app使用。
currentVersion:app当前发布版本号。
打包参考:将H5站点打包成app完美攻略

更新的核心逻辑原理跟原生app一致,核心实现检查更新代码,可以参考如下:

//app热更新下载
//假定字符串的每节数都在5位以下
function toNum(a) {
	//也可以这样写 var c=a.split(/\./);
	var c = a.split('.');
	var num_place = ["", "0", "00", "000", "0000"],
		r = num_place.reverse();
	for(var i = 0; i < c.length; i++) {
		var len = c[i].length;
		c[i] = r[len] + c[i];
	}
	var res = c.join('');
	return res;
}
 
var btn = ["确定升级", "取消"];
//获取app系统更新[是否手动点击获取更新]
function appUpdate(Index) {
	console.log('appUpdate');
	mui.plusReady(function() {
		plus.runtime.getProperty(plus.runtime.appid, function(inf) {
			ver = inf.version + '';
			console.log('ver:' + ver);
			var client;
			var ua = navigator.userAgent.toLowerCase();
			if(/iphone|ipad|ipod/.test(ua)) { //苹果手机            
				mui.ajax({
					type: "get",
					dataType: 'json',
					url: "https://itunes.apple.com/lookup?id=1462614850", //获取当前上架APPStore版本信息
					data: {
						id: 1462614850 //APP唯一标识ID
					},
					contentType: 'application/x-www-form-urlencoded;charset=UTF-8',
					success: function(data) {
						console.log('data:' + JSON.stringify(data));
						var resultCount = data.resultCount;
						for(var i = 0; i < resultCount; i++) {
							var normItem = data.results[i].version;
							console.log('normItem:' + normItem)
							if(normItem > ver) {
								var _msg = "发现新版本:V" + normItem;
								//plus.nativeUI.alert("发现新版本:V" + normItem);
								mui.confirm(_msg, '升级确认', btn, function(e) {
									if(e.index == 0) { //执行升级操作
										document.location.href = 'https://itunes.apple.com/cn/app/%E5%AD%A9%E5%84%BF%E6%AC%A2/id1462614850?mt=8'; //上新APPStore下载地址
									}
								});
								return;
							}
						}
						if(ismanual) {
							mui.toast('当前版本号已是最新');
						}
						return;
					}
				});
			} else if(/android/.test(ua)) {
				mui.ajax(ip + "APIVApp/SelectVApp", {
					data: {
						apkVersion: ver,
					},
					dataType: 'json',
					type: 'get',
					timeout: 10000,
					success: function(data) {
						console.log('data:' + JSON.stringify(data))
						console.log(toNum(ver))
						if(toNum(data[0]._vname) > toNum(ver)) {
							var _msg = "发现新版本:V" + data[0]._vname;
							mui.confirm(_msg, '升级确认', btn, function(e) {
								if(e.index == 0) { //执行升级操作
									downWgt();
								}
							});
						} else {
							console.log(Index);
							if(Index) {
								mui.toast('当前版本号已是最新');
							}
							return;
						}
					},
					error: function(xhr, type, errerThrown) {
						mui.toast('网络异常,请稍候再试');
					}
				});
			}
		});
	});
}
 
// 下载wgt文件
function downWgt() {
	var wgtUrl = ip + "app/H5750CDB5.wgt";
	plus.nativeUI.showWaiting("下载更新文件...");  
	plus.downloader.createDownload(wgtUrl, {
		filename: "_doc/update/"
	}, function(d, status) {    
		if(status == 200) {       
			console.log("下载更新文件成功:" + d.filename);      
			installWgt(d.filename); //安装wgt包
			    
		} else {      
			console.log("下载失败!");      
			plus.nativeUI.alert("下载失败!");    
		}    
		plus.nativeUI.closeWaiting();  
	}).start();
}
 
function installWgt(path) {  
	plus.nativeUI.showWaiting("安装更新文件...");  
	plus.runtime.install(path, {}, function() {    
		plus.nativeUI.closeWaiting();    
		console.log("安装更新文件成功!");    
		plus.nativeUI.alert("应用资源更新完成!", function() {      
			plus.runtime.restart();    
		});  
	}, function(e) {    
		plus.nativeUI.closeWaiting();    
		console.log("安装更新文件失败[" + e.code + "]:" + e.message);    
		plus.nativeUI.alert("安装更新文件失败[" + e.code + "]:" + e.message);    
		if(e.code == 10) {    
			alert('请清除临时目录');    
		}  
	});
}
 

本文是实践的一些总结,希望对你有所帮助。有什么问题可以留言讨论,有更好的实践方法也欢迎斧正指导。

参考:
h5打包app实现版本自动更新
https://www.cnblogs.com/lijia-kapok/p/6553823.html
https://blog.csdn.net/weixin_41472521/article/details/90274142
android:
https://www.cnblogs.com/zhujiabin/p/7384902.html
ios:
https://www.jianshu.com/p/9e237cd62129

臭味相投的朋友们,我在这里:
猿in小站:http://www.yuanin.net
csdn博客:https://blog.csdn.net/jiabeis
简书:https://www.jianshu.com/u/4cb7d664ec4b
微信免费订阅号“猿in”
猿in

未经允许不得转载:ITB运维部落—http://www.itbcn.cn—ITB运维技术交流之家平台 » web打包app(h5+app)版本自动更新的实现

如果文章对你有帮助,欢迎点击上方按钮打赏作者

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址