[MUI]初识mui之版本打包与升级

MUI版本打包与升级

打包

云打包:直接发行原生APP即可,选择DCloud和越狱包选项可不使用开发者证书完成打包APP

  • 注:此处建议用HBuilderX打包,

离线打包:需要熟悉eclipse,Android开发环境或集成版的android studio,以及离线打包Android版SDK(安卓环境不熟悉,优先级低)

升级

  • 整包升级:适用于大版本更新,新增5+模块时必须使用此类更新方法 (apk)
  • 应用资源升级:适用于小版本更新 (wgt)
  • 应用资源差量升级:适用于小版本更新(wgtu)

更新模式:

  1. 客户端判断是否有升级
    客户端从服务器获取最新的版本号,本地js判断是否需要升级。
  2. 服务器判断是否有升级
    客户端提交版本到服务器,有服务器判断返回是否需要升级。
    前者的优点是否服务器压力小,静态返回最新客户端版本即可,后者的优点则升级控制会更灵活,可以根据其它条件动态控制部分用户先升级(灰度发布)等。有条件的情况推荐采用第二种方式进行判断。

实现

在笔者使用时为偷懒,暂时只尝试了整包升级的方式,更新模式采用第二种,此处只贴出demo代码

//该段非原创,只修改了部分,亲测可用
document.getElementById("test1").addEventListener("tap", function () {
    // mui.toast("22222222222");
    plus.runtime.getProperty(plus.runtime.appid, function (inf) {
        var settings = app.getSettings();
        ver = inf.version;
        mui.toast(ver);
        var url = 'http://******/getversion/';//注意,此处配合自己写的后端路由前面要加http://
        var client;
        var ua = navigator.userAgent.toLowerCase();
        // 公司没有配备苹果设备,苹果部分暂未使用,后续验证完确认可用会取消掉注释
        // if(/iphone|ipad|ipod/.test(ua)) {    //苹果手机
        //     $.ajax({
        //         type:"get",
        //         dataType:'json',
        //         url:"https://itunes.apple.com/lookup?id=*******",//获取当前上架APPStore版本信息
        //         data:{
        //             id:********* //APP唯一标识ID
        //         },
        //         contentType:'application/x-www-form-urlencoded;charset=UTF-8',
        //         success:function(data){
        //             console.log("jsjsjsjs"+json2string(data));
        //             $.each(data, function(i,norms) {
        //                 $.each(norms, function(key,value) {
        //                     $.each(value, function(j, normItem) {
        //                         if(j=="version"){
        //                             if(normItem>ver){
        //                                  alert("发现新版本:V"+normItem);
        //                                    document.location.href='https://itunes.apple.com/cn/app/san-gu-hui/id**********?mt=8'; //上新APPStore下载地址
        //                             }
        //                         }
        //                     });
        //                 });
        //             });
        //             return ;
        //         }
        //     });
        // }else if(/android/.test(ua)) {
        if (/android/.test(ua)) {
            mui.ajax(url, {
                data: {
                    apkVersion: ver,
                },
                dataType: 'json',
                type: 'POST',
                timeout: 10000,
                success: function (data) {
                	// mui.toast(data.version);
                	// mui.toast(data.apkUrl);
                    if (data.needUpdate == "1") {
                        mui.toast("发现新版本:V" + data.version);//获取远程数据库中上新andriod版本号
                        var dtask = plus.downloader.createDownload(data.apkUrl, {}, function (d, status) {
                            if (status == 200) {
                                plus.nativeUI.toast("正在准备环境,请稍后!");
                                sleep(1000);
                                var path = d.filename;//下载apk
                                plus.runtime.install(path); // 自动安装apk文件
                            } else {
                                alert('版本更新失败:' + status);
                            }
                        });
                        dtask.start();
                    } else if(data.needUpdate == "0"){
                        mui.toast('当前版本号已是最新');
                        return;
                    }
                },
                error: function (xhr, type, errerThrown) {
                    mui.toast('网络异常,请稍候再试');
                }
            });
        }
    });
});

以下为django后台代码,只贴出demo,后续有需要可自行扩展:

def getversion(request):
    phoneVersion = float(request.POST.get("apkVersion", "0.0"))# 为方便,此处版本号采用单小数点形式的
    print phoneVersion
    if phoneVersion < 1.09:
        ret = {"needUpdate": "1", "version": "1.09",
               "apkUrl": "https://service.dcloud.net.cn/build/download/********************************"}
    else:
        ret = {"needUpdate": "0"}
    return getJSResponse(ret)

urlpatterns = [
    url(r'getversion/$', getversion),
]

一个比较完善的例子

后续笔者经同事分享,得到一个比较完善的例子,该例子主要是通过后端向前端传送新版本信息,前端将其保存成json文件存在手机中。然后跟自己的当前版本进行比较,再进行弹窗由用户选择是否需要更新。还有进行忽略版本升级的选项,会将是否忽略的选项暂存在keyAbort中,检测时间也会存在本地缓存中。

优点是即插即用,配置好后端请求后可以直接使用;其次一些配置什么的都在前端进行,相关配置文件不用每次打开检测页面都进行后端请求,并且可以忽略版本。后端的配置也十分的容易,只需返回注释中的json数据即可。

此例为同事分享,暂未去找原帖,等后续找到后会贴出原帖,有知道的小伙伴麻烦指路一下。

/**
 * 判断应用升级模块,从url地址下载升级描述文件到本地local路径
 * [email protected]
 * 
 * 升级文件为JSON格式数据,如下:
{
	"appid":"HelloH5",
    "iOS":{
    	"version":"iOS新版本号,如:1.0.0",
    	"note":"iOS新版本描述信息,多行使用\n分割",
    	"url":"Appstore路径,如:itms-apps://itunes.apple.com/cn/app/hello-h5+/id682211190?l=zh&mt=8"
    },
    "Android":{
    	"version":"Android新版本号,如:1.0.1",
    	"note":"Android新版本描述信息,多行使用\n分割",
    	"url":"apk文件下载地址,如:http://www.dcloud.io/helloh5p/HelloH5.apk"
    }
}
 *
 */
(function(w){
var server="http://www.dcloud.io/helloh5/update.json",//获取升级描述文件服务器地址
localDir="update",localFile="update.json",//本地保存升级描述目录和文件名
keyUpdate="updateCheck",//取消升级键名
keyAbort="updateAbort",//忽略版本键名
checkInterval=604800000,//升级检查间隔,单位为ms,7天为7*24*60*60*1000=604800000, 如果每次启动需要检查设置值为0
dir=null;

/**
 * 准备升级操作
 * 创建升级文件保存目录
 */
function initUpdate(){
	// 在流应用模式下不需要检测升级操作
	if(navigator.userAgent.indexOf('StreamApp')>=0){
		return;
	}
	// 打开doc根目录
	plus.io.requestFileSystem( plus.io.PRIVATE_DOC, function(fs){
		fs.root.getDirectory( localDir, {create:true}, function(entry){
			dir = entry;
			checkUpdate();
		}, function(e){
			console.log( "准备升级操作,打开update目录失败:"+e.message );
		});
	},function(e){
		console.log( "准备升级操作,打开doc目录失败:"+e.message );
	});
}

/**
 * 检测程序升级
 */
function checkUpdate() {
	// 判断升级检测是否过期
	var lastcheck = plus.storage.getItem( keyUpdate );
	if ( lastcheck ) {
		var dc = parseInt( lastcheck );
		var dn = (new Date()).getTime();
		if ( dn-dc < checkInterval ) {	// 未超过上次升级检测间隔,不需要进行升级检查
			return;
		}
		// 取消已过期,删除取消标记
		plus.storage.removeItem( keyUpdate );
	}
	// 读取本地升级文件
	dir.getFile( localFile, {create:false}, function(fentry){
		fentry.file( function(file){
			var reader = new plus.io.FileReader();
			reader.onloadend = function ( e ) {
				fentry.remove();
				var data = null;
				try{
					data=JSON.parse(e.target.result);
				}catch(e){
					console.log( "读取本地升级文件,数据格式错误!" );
					return;
				}
				checkUpdateData( data );
			}
			reader.readAsText(file);
		}, function(e){
			console.log( "读取本地升级文件,获取文件对象失败:"+e.message );
			fentry.remove();
		} );
	}, function(e){
		// 失败表示文件不存在,从服务器获取升级数据
		getUpdateData();
	});
}

/**
 * 检查升级数据
 */
function checkUpdateData( j ){
	var curVer=plus.runtime.version,
	inf = j[plus.os.name];
	if ( inf ){
		var srvVer = inf.version;
		// 判断是否存在忽略版本号
		var vabort = plus.storage.getItem( keyAbort );
		if ( vabort && srvVer==vabort ) {
			// 忽略此版本
			return;
		}
		// 判断是否需要升级
		if ( compareVersion(curVer,srvVer) ) {
			// 提示用户是否升级
			plus.nativeUI.confirm( inf.note, function(i){
				if ( 0==i.index ) {
					plus.runtime.openURL( inf.url );
				} else if ( 1==i.index ) {
					plus.storage.setItem( keyAbort, srvVer );
					plus.storage.setItem( keyUpdate, (new Date()).getTime().toString() );
				} else {
					plus.storage.setItem( keyUpdate, (new Date()).getTime().toString() );
				}
			}, inf.title, ["立即更新","跳过此版本","取  消"] );
		}
	}
}

/**
 * 从服务器获取升级数据
 */
function getUpdateData(){
	var xhr = new plus.net.XMLHttpRequest();
	xhr.onreadystatechange = function () {
        switch ( xhr.readyState ) {
            case 4:
                if ( xhr.status == 200 ) {
                	// 保存到本地文件中
                	dir.getFile( localFile, {create:true}, function(fentry){
                		fentry.createWriter( function(writer){
                			writer.onerror = function(){
                				console.log( "获取升级数据,保存文件失败!" );
                			}
                			writer.write( xhr.responseText );
                		}, function(e){
                			console.log( "获取升级数据,创建写文件对象失败:"+e.message );
                		} );
                	}, function(e){
                		console.log( "获取升级数据,打开保存文件失败:"+e.message );
                	});
                } else {
                	console.log( "获取升级数据,联网请求失败:"+xhr.status );
                }
                break;
            default :
                break;
        }
	}
	xhr.open( "GET", server );
	xhr.send();
}

/**
 * 比较版本大小,如果新版本nv大于旧版本ov则返回true,否则返回false
 * @param {String} ov
 * @param {String} nv
 * @return {Boolean} 
 */
function compareVersion( ov, nv ){
	if ( !ov || !nv || ov=="" || nv=="" ){
		return false;
	}
	var b=false,
	ova = ov.split(".",4),
	nva = nv.split(".",4);
	for ( var i=0; ino || sn.length>so.length  ) {
			return true;
		} else if ( nnova.length && 0==nv.indexOf(ov) ) {
		return true;
	}
}

if ( w.plus ) {
	initUpdate();
} else {
	document.addEventListener("plusready", initUpdate, false );
}

})(window);

其他更新方式

暂未尝试,以下贴出比较不错的博客或问答地址:

  • 说说App资源在线升级更新的坑

  • 路人对无法更新版本号问题解释

    plus.runtime.version获取的是apk/ipa的版本信息,此版本号通过wgt或wgtu升级都无法更新(只能通过更新整包安装apk/ipa)来更新。
    如果是wgt或者wgtu升级更新的是应用资源的版本号,需要通过以下方式获取:
    function getWidgetInfo() {
    plus.runtime.getProperty( plus.runtime.appid, function ( wgtinfo ) {
    //version属性
    console.log( “version:”+wgtinfo.version );
    } );
    }

  • 差量升级插件模式

  • 离线打包

你可能感兴趣的:(MUI)