2016-11-29 14:01:19 jingsi1991 阅读数 1760

本文为cordova混合开发apk更新的系列文章的第一篇文章:H5部分的更新。

混合应用的开发也已经火到了一定程度了,大家写h5的技术也到了炉火纯青的地步了。那么对于对原生了解比较少的小伙伴来说,apk的更新、发包可能还是一笔糊涂账。对于混合开发来讲,一般更新分为两种:h5部分的更新,原生外壳的更新。下面我们来讲一下基于插件的h5部分热更新的实现流程及注意事项。

一、Cordova热更新的原理

1、热更新

是指不让用户去应用市场上面重新下载安装包,或者重新安装升级包,实现 APP 的更新升级

2、cordova的热更新

一个 cordova 应用包括(HTML,JavaScript,CSS 文件和其他资源),传统的更新是我 们把我们的程序提交到应用市场,然后用户才可以下载更新。我们每改一个小功能 都需要上传到 appstore 然后用户的手机提示更新下载等等

cordova 的 cordova-hot-code-push 插件让这些原本很复杂很麻烦的工作变得简单。我 们用 codepush 插件可以直接实现不上传 appstore 更新我们的应用

3、原理

cordova-hot-code-push的核心原理说简单的就是以时间戳为h5部分的版本号,以各个文件生成的hash值作为是否更新的依据生成一个配置文件。
核心原理步骤:
    1、比较文件系统中h5部分的版本号和本地的版本号。如果文件系统的版本号大于本地,进行下一步,否则不更新;
    2、本地各个文件的hash值和服务端文件的hash值,不相同则拉取该文件替换本地文件进行更新;
    3、等所有的文件对比完成后,在拉取配置文件生成一个新的h5包;
    4、根据设置的更新时机,替换原有的h5包

整个过程的原理图如下:
这里写图片描述

下面我们来看看插件具体怎么使用吧。

二、热更新插件的使用

1、插件地址

http://www.phonegap100.com/plugininfo_46.html

https://github.com/nordnet/cordova-hot-code-push

2、插件的安装

1)、在APP目录下运行cordova plugin add cordova-hot-code-push-plugin

2)、在APP目录下运行cordova plugin add cordova-hot-code-push-local-dev-addon

3)、安装CLI:npm install -g cordova-hot-code-push-cli
    主要是用这个生成检测配置文件,也就是动态生成 chcp.json 和chcp.manifest 生成 两个文件 

3、具体操作

**第一步**:新开一个cmd窗口执行cordova-hcp server命令,对应安装的CLI,用来在www目录下生成两个配置文件和检测文件的变化更新配置文件;
    chcp.json
        {
          "autogenerated": true,
          "release": "2016.11.29-11.09.38",
          "content_url": "https://ad71cba3.ngrok.io",//WWW文件夹所在远程地址
          "update": "now"
          // start - app启动时安装更新. 默认值.
          // resume - app从后台切换过来的时候安装更新.
          // now - web内容下载完毕即安装更新.
        }
    chcp.manifest
        [
          {
            "file": "css/iconfont/iconfont.css",
            "hash": "9b801ad1eb80f20265b8cbcc11435707"
          },
          {
            "file": "css/iconfont/iconfont.eot",
            "hash": "2bd6f9b32b3606ac39b46dacb0d8427c"
          },
          ....
        ]
    同时会在config.xml文件中添加一个参数:
      <chcp>
        <config-file url="https://ad71cba3.ngrok.io/chcp.json"/>
        <local-development enabled="true"/>
      </chcp>

    此外还会在项目根目录下有一个文件生成哦.chcpenv:
        {
          "content_url": "https://ad71cba3.ngrok.io",
          "config_url": "https://ad71cba3.ngrok.io/chcp.json"
        }   

    注意事项:config_url为chcp.json文件的地址;content_url为更新包的地址;config.xml中一定要加<local-development enabled="true"/>
    这个哦,否则文件修改后不会更新配置文件

第二步:运行cordova build/ionic build。

到这一步客户端热更新的准备工作已经完成了。下面就是服务器端的工作了。

第三步:在cordova-hcp server命令运行着的前提下,修改www下的文件,你会发现dos里面会有更新了哪些文件的信息。同时会发现chcp.json和chcp.manifest文件发生了变化。

第四步:把第三步中的www目录上传到content_url所指向的服务器目录下。然后打开第二步中生成的apk,你会奇迹的发现,页面更新了,变成了你打包后修改的样子了。

以上测试是在window上进行的android项目的热更新测试。先这样吧,后面有时间了再完善。下一篇写写原生外壳的更新吧。

2016-07-22 10:43:54 qq_23334071 阅读数 1840

WebAPP实现自动更新功能–后台下载APK,下载完成后自动打开

1.准备工作:添加cordova插件(cordova-plugin-filecordova-plugin-file-transfercordova-plugin-file-opener2cordova-plugin-app-version

2.直接上代码实现自动更新功能

1>、第一步 判断APP版本号是否相同
  cordova.getAppVersion().then(function (version) {
        var serverAppVersion = result.data.version;
        console.log(version+"     "+serverAppVersion);
        //如果本地于服务端的APP版本不符合
    if (version != serverAppVersion) {
        $.ckjIndex.showUpdateConfirm(result.data.update_remake);
    }
   });
2>、第二步 显示模板,提问是否需要升级
  showUpdateConfirm: function(APPdesc) {
    $.ui.popup({
        title:"版本升级",
                message: APPdesc, //从服务端获取更新的内容
                cancelText:"忽略",
                cancelCallback: null,
                doneText:"升级",
                supressFooter:false,
                cancelClass:'button',
                doneClass:'button',
                doneCallback: function () {
                    $.ckjIndex.getappUpdataINFO();                 
                },
                cancelOnly:false,
                blockUI:true
    });
   }
3>、第三步 调用下载方法,将APP下载到本地并用open方法打开需要安装的APP报,进行新包的安装
  getappUpdataINFO: function() {
    var fileTransfer = new FileTransfer();
    var url = $.ckjIndex.cfg.APPurl;
    var targetPath = cordova.file.externalRootDirectory+'fengchaoEshequ.apk';
    fileTransfer.download(
        url,
                targetPath,
                function(success) {
                    console.log("download complete: " + success.fullPath);
                    cordova.plugins.fileOpener2.open(       
                        targetPath,        
                        "application/vnd.android.package-archive",       
                        {       
                            success: successCallback,  
                            error: errorCallback,     
                        }       
                    );
                },
                function(error) {
                    console.log(error);
                    $.vv.tip({content: '下载APP失败', time:1000});
                }
    );
    function successCallback(){
        console.log("****************/打开成功/******************");
    }
        function errorCallback(e){
        console.log("****************/打开失败/******************");
                console.log(e);
    }
  }

3.自动更新功能实现(若有疑问可QQ:992899491)

4.效果图
自动更新效果图

2018-12-12 16:10:27 BADAO_LIUMANG_QIZHI 阅读数 230

场景

假设vue项目已经搭建好,要将其打包成apk。

实现

编译vue项目

在vue项目目录下打开cmd,输入:

npm run build

新建cordova项目

来到要新建cordova项目的目录下,输入:

cordova create corova-app com.badao mapp

其中cordova-app是项目名

com.badado是包名

mapp是apk名字

然后

cd corddova-app 

进入项目目录

复制文件

将vue项目目录下的dist目录下的文件复制到cordova项目中的www目录下。

添加安卓平台

在cordova项目中的cmd继续输入:

cordova platform add android --save

编译安卓项目

输入:

cordova build android --release

不加--release是默认debug版本的,加了才是正式版的。

build成功后的效果为:

此时会输出apk的路径,此时是未签名版的apk,无法安装到手机。

apk签名

生成签名文件,参照:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/84948340

将签名文件keystore文件与未签名的apk放在同一个目录下。

在此目录下打开cmd,输入:

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore release-key.keystore app-release-unsigned.apk cordova-project

其中release-key.keystore  是生成的签名文件;

app-release-unsigned.apk 是要签名的apk;

此时会提示你输入签名口令,此口令就是在生成签名文件时设置的口令。

然后再输入:

zipalign -v 4 app-release-unsigned.apk  cordova-pass.apk

其中cordova-pass.apk是签名后要显示的apk。

2015-10-30 17:14:53 u012794461 阅读数 2174

目录结构

这里实现一个下载文件然后显示一个带进度条的对话框的demo,用来下载一个apk并安装
首先建立一个cordova插件的目录结构:

- Downloader
    - plugin.xml
    - src
        - android
            - Downloader.java

    - www
        - Downloader.js

plugin.xml

<plugin id="com.keytask.updater.cordova" version="0.0.1"
    xmlns="http://apache.org/cordova/ns/plugins/1.0"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <name>Downloader</name>
    <description>更新应用</description>
    <js-module name="Downloader" src="www/Downloader.js">
        <clobbers target="cordova.plugins.Downloader"/>
    </js-module>
    <platform name="android">
        <config-file parent="/*" target="res/xml/config.xml">
            <feature name="Downloader">
                <param name="android-package" value="com.example.downloader.cordova.Downloader"/>
            </feature>
        </config-file>
        <source-file src="src/android/Downloader.java" target-dir="src/com/example/downloader/cordova"/>
    </platform>
</plugin>

Downloader.js

var exec = require('cordova/exec');

exports.downloadWithUrl = function(url,success, error) {
  exec(success, error, "Downloader", "doDownload", [{url:url}]);
  //这里传入一个json,里面是数组,装着要下载的apk地址
};

Downloader.java

public class Downloader extends CordovaPlugin {

    File rootDir = Environment.getExternalStorageDirectory();

    //以下载apk为例
    String fileName="example.apk";

    ProgressDialog mProgressDialog;


    Activity activity;



    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext)
            throws JSONException {
        activity = this.cordova.getActivity();
        if (action.equals("doDownload")) {


            String url = args.getJSONObject(0).getString("url");//在主程序中传进的是一个json,里面有apk的下载地址



        //创建一个进度条对话框
            mProgressDialog = new ProgressDialog(activity);
            mProgressDialog.setMessage("Downloading file...");
            mProgressDialog.setIndeterminate(false);
            mProgressDialog.setMax(100);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mProgressDialog.setCancelable(false);//默认不可取消
            mProgressDialog.show();

        //后台下载apk
            new AsyncTask<String, String, Boolean>(){


                @Override
                protected void onPreExecute() {
                    super.onPreExecute();



                }

                @Override
                protected Boolean doInBackground(String... aurl) {
                    try {
                        //连接地址
                        URL u = new URL(aurl[0]);


                        HttpURLConnection c = (HttpURLConnection) u.openConnection();
                        c.setRequestMethod("GET");
                        c.setDoOutput(true);
                        c.connect();

                        //计算文件长度
                        int lenghtOfFile = c.getContentLength();


                        File destDir = new File(rootDir + "/example/");
                          if (!destDir.exists()) {
                           destDir.mkdirs();
                          }

                        FileOutputStream f = new FileOutputStream(new File(destDir, fileName));

                        InputStream in = c.getInputStream();

                        //下载的代码
                        byte[] buffer = new byte[1024];
                        int len1 = 0;
                        long total = 0;

                        while ((len1 = in.read(buffer)) > 0) {
                            total += len1; //total = total + len1
                            publishProgress("" + (int)((total*100)/lenghtOfFile));
                            f.write(buffer, 0, len1);
                        }
                        f.close();

            //打开这个apk
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setDataAndType(Uri.fromFile(new File(destDir, fileName)), "application/vnd.android.package-archive");
                        activity.startActivity(intent);

                    } catch (Exception e) {
                        e.printStackTrace();
                        return false;
                    }

                    return true;
                }

                protected void onProgressUpdate(String... progress) {
                    mProgressDialog.setProgress(Integer.parseInt(progress[0]));
                }

                @Override
                protected void onPostExecute(Boolean isSuccess) {
                    //dismiss the dialog after the file was downloaded

                    mProgressDialog.dismiss();

                    if (isSuccess){
                        callbackContext.success("成功");
                    }else {
                        callbackContext.error("失败");
                    }
                }

            }.execute(url);



            return true;
        }


        return false;
    }





}

主程序的调用插件

   var testUrl = "http://dl.app.snail.com/snail/panda/20150928/product_officialnew(1.1.10)09-22Ad220.apk";

var downloader = cordova.require('com.example.downloader.cordova.Downloader');
downloader.downloadWithUrl(testUrl, function (success) {
          //下载成功执行
        }, function (error) {
          //下载失败执行
        });

2019-11-01 14:10:16 qq_35125764 阅读数 45

App的更新思路:

  • 如果只更新html5的部分,使用热更新也是无痕更新,好处:如果在ios端还可以绕过审核,不会有任何提示(热更新暂时没有实现,也就不瞎分享了)
  • 如果更新了插件,那就只能更新apk了:
    - 第一种:就是到各个手机的应用市场注册审核,然后有更新了就弹出框提示跳转到应用市场去更新
    - 第二种:自己的一个服务器,检查服务器版本和本地版本之后,下载服务器中最新的apk,完成更新自动安装

目前项目中用的是第二种方式,简单记录一下整个更新的过程。

1, 安装插件:

 cordova plugin add cordova-plugin-app-version 
 cordova plugin add cordova-plugin-file-transfer
 cordova plugin add cordova-plugin-file-opener2

2,获取app的版本号和服务器的版本号:

获取app的versionCode

window.cordova.getAppVersion.getVersionCode(function (versionCode) {
  // Toast(versionCode);
    resolve(versionCode);
});

cordova-plugin-app-version还有其他几个方法:

- (void)getAppName:(CDVInvokedUrlCommand*)command;

- (void)getPackageName:(CDVInvokedUrlCommand*)command;

- (void)getVersionNumber:(CDVInvokedUrlCommand*)command;

- (void)getVersionCode:(CDVInvokedUrlCommand*)command;

使用方法,类似getVersionCode

获取服务器的versionCode:

api.getLastVersion().then(res => {
    const data = (res.data && res.data.data) || {};
      this.versionCode = data.versionCode || 0;
      this.versionName = data.versionName || '';
      this.defaultUrl = data.defaultUrl || '';
      // Toast(`${this.versionCode}, ${this.defaultUrl}`);
      _this.checkUpdate();
  });

对比校验

checkUpdate() {
                this.$bridge.getLastVersionCode().then(data => {
                    if (this.versionCode > data) {
                        this.$dialog.confirm({
                            title: '版本更新',
                            message: `当前最新版本为:${this.versionName},请更新!`
                        }).then(() => {
                            this.$toast('下载应用中,请耐心等待!');
                            //下载并打开apk
                            this.$bridge.downLoadApk(this.defaultUrl).then(result => {
                                //console.debug('success' + result);
                            }).catch(err => {
                                this.$toast('下载失败,请检查网络是否畅通!');
                               // console.debug(err + 'err==========');
                            });
                            // const downLoadDom = this.$refs.downLoad;
                            // downLoadDom.setAttribute('ref', this.defaultUrl);
                            // downLoadDom.click();
                        }).catch(cancel => {
                           // console.debug('取消更新' + cancel);
                        });
                    }
                });
            },

2,下载应用:

downLoadApk(url) {
        return ready((resolve, reject) => { //事件监听deviceready的回调
            if (isApp) { //是否app
                const _this = this;
                const FileTransfer = window.FileTransfer;
                const fileTransfer = new FileTransfer();
                // const uri = encodeURI('https://obs-xa001.obs.cn-north-1.myhuaweicloud.com/xiongan-app/xacx.apk');
                const fileURL = 'cdvfile://localhost/temporary/tuner.apk';//经过测试这个地址没有问题,可以下载和安装
                const targetPath = window.cordova.file.externalDataDirectory + 'xionganchuxing.apk';//这个地址也可以下载和安装
                fileTransfer.download(
                    encodeURI(url), //服务器地址
                    targetPath, //本地存储地址
                    function (entry) { //下载完成回调
                        Toast('应用下载完成!');
                        //console.debug('download complete: ' + JSON.stringify(entry) );
                        _this.openApk(targetPath, resolve, reject);
                        // resolve(entry);
                    },
                    function (error) { //下载失败回调
                       // console.debug('download error: ' + JSON.stringify(error));
                        reject(error);
                    },
                    false,
                    {}
                );
            }
        });
    }

3,打开app

 //打开Apk
    openApk(targetUrl, resolve, reject) {
        if (isApp) {
            //console.debug('开始打开apk!' + targetUrl + 'fileOpen2' + window.cordova.plugins.fileOpener2);
            try {
                window.cordova.plugins.fileOpener2.open(
                    targetUrl,
                    'application/vnd.android.package-archive', //打开apk
                    function onSuccess(data) {
                        console.debug('打开Apk成功' + targetUrl + 'data:' + data);
                        resolve(data);
                    },
                    function onError(error) {
                        reject(error);
                       // console.debug('出错!请在' + targetUrl + '目录下查看, error' + error);
                    }
                );
            } catch (e) {
                reject(e);
                console.debug('openApkError' + e);
            }
        }
    }

Ps:里面的ready, isApp,console.debug都是项目中已经封装的函数,主要还是思路。

APK签名的实现

阅读数 488

没有更多推荐了,返回首页