Cordova webapp实战开发:(5)如何写一个Andorid下自动更新的插件?

news2024/11/29 6:25:39

在 《Cordova webapp实战开发:(4)Android环境搭建》中我们搭建好了开发环境,也给大家布置了调用插件的预习作业,做得如何了呢?今天我们来学一下如何自己从头建立一个Andorid下的cordova插件。

本次练习你能学到的

  1. 学习如何实现Android下自动更新功能
  2. 学习Android下插件类的编写
  3. 学习Android下插件的配置
  4. 学习Android下插件的调用

主要内容

  • 打开APP后检查版本更新,如果有更新则弹出更新对话框

  • APP中【检查更新】显示当前版本号,并可以点击进行版本检查更新

如何实现自动更新功能

你可以自己写代码,也可以网上找代码抄一下,我之前的 敏捷个人APP 就是从网上下的一个代码片段放进我的项目中的。不过今天和大家说的不是如何编写自动更新代码,因为我们今天要做的是如何更快的用别人写好的东西来加速自己产品开发的进度和质量。

自动更新这个东西也不涉及到什么技术难度,一般第三方要是提供了也不会出什么质量问题,能够拿来就用岂不是很好呢?网上找了一下,发现 友盟提供自动更新

很好,那就直接用这个吧,Andorid和iOS都可以用。

如何集成到我们的产品中,看他们自己写的文档:自动更新android文档 ,我就不多说了,如果遇到问题,可以在咱们群里问问大家。

插件类的编写

原生Andorid中如果调用,就看上面说的他们自己写的文档。如果我们现在要在APP中【设置】中增加自动检查和显示当前版本,则需要我们开始学习如何编写cordova插件了。

这里我们会编写一个插件,两个方法,一个方法用来检测更新,另一个方法用来获得当前APP的版本号。

闲话不说了,直接来代码。

public class GCAppPlugin extends CordovaPlugin {
 
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if ("version".equals(action)) {
            version(callbackContext);
            return true;
        }
        else if ("checkUpdate".equals(action)) {
            final Context mContext = this.cordova.getActivity();
            UmengUpdateAgent.setUpdateAutoPopup(false);
            UmengUpdateAgent.setUpdateListener(new UmengUpdateListener() {
                @Override
                public void onUpdateReturned(int updateStatus, UpdateResponse updateInfo) {
                      switch (updateStatus) {
                        case UpdateStatus.Yes: // has update
                            UmengUpdateAgent.showUpdateDialog(mContext, updateInfo);
                            break;
                        case UpdateStatus.No: // has no update
                            Toast.makeText(mContext, "现在使用的已是最新版本了", Toast.LENGTH_SHORT).show();
                            break;
                        case UpdateStatus.NoneWifi: // none wifi
                            Toast.makeText(mContext, "没有wifi连接, 只在wifi下更新", Toast.LENGTH_SHORT).show();
                            break;
                        case UpdateStatus.Timeout: // time out
                            Toast.makeText(mContext, "超时", Toast.LENGTH_SHORT).show();
                            break;
                        }
                }
            });
            UmengUpdateAgent.forceUpdate(mContext);
            return true;
        }
}
 
private synchronized void version(CallbackContext callbackContext) {
  PackageInfo packInfo;
  try {
    packInfo = this.cordova.getActivity().getPackageManager().getPackageInfo(this.cordova.getActivity().getPackageName(),0);
    String version = packInfo.versionName +"("+packInfo.versionCode+")";
    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, version));
  } catch (NameNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

 

Javascript如何得到插件调用后的返回结果?主要通过类似 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, version)); 代码返回PluginResult,失败和成功都可以触发Javascript执行对应的自定义函数

插件的配置

插件写完了,很多人遇到的下一个问题就是怎么配置才能在Javascript中调用呢?我们今天也不解析源码,为什么呢?因为我没看:)不过,我一定要给大家说清楚如何配置,否则就永远调用不了插件。

打开res/xml/config.xml文件,添加feature,必须匹配类名,因为源码中是通过这些去配对的。上面我们写了更新插件,现在就是要配置一下这个插件类到功能名称,我在配置文件中加入了下文粗体部分内容

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.glodon.gcapp" version="2.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>掌中广材</name>
    <description> 随时随地查找全国最完整最及时的信息价   </description>
    <author email="22626496@qq.com" href="http://www.中国信息价.cn">  周金根    </author>
    <content src="html/scj/scj.html" />
    <access origin="*" />
    <access origin="tel:*" launch-external="yes"/>
    <access origin="geo:*" launch-external="yes"/>
    <access origin="mailto:*" launch-external="yes"/>
    <access origin="sms:*" launch-external="yes"/>
    <access origin="market:*" launch-external="yes"/>
 
    <preference name="SplashScreen" value="screen" />
    <preference name="SplashScreenDelay" value="30000" />
    <preference name="SplashMaintainAspectRatio" value="false" />
    <preference name="LoadingDialog" value="正在加载中..." />
 
    <feature name="Device">
        <param name="android-package" value="org.apache.cordova.device.Device" />
    </feature>
     <feature name="NetworkStatus">
        <param name="android-package" value="org.apache.cordova.networkinformation.NetworkManager" />
    </feature>
    <feature name="SplashScreen">
        <param name="android-package" value="org.apache.cordova.splashscreen.SplashScreen" />
    </feature>
    <feature name="Camera">
        <param name="android-package" value="org.apache.cordova.camera.CameraLauncher" />
    </feature>
    <feature name="BarcodeScanner">
        <param name="android-package" value="com.phonegap.plugins.barcodescanner.BarcodeScanner" />
    </feature>
    <feature name="Gcapp">
        <param name="android-package" value="com.gldjc.guangcaiclient.GCAppPlugin" />
    </feature>
</widget>

代码贴完了,我还是要再多说一下,

com.gldjc.guangcaiclient.GCAppPlugin  是插件类的全面
  • Gcapp是 feature 名称,下面大家就知道在哪里会用到了

以上文件就是告诉cordova,我们新增了一个Gcapp功能,这个功能会调用我们的原生插件Java对象,接下来就是Javascript如何能调用到这个类了,最重要的就是这个Gcapp功能名称。

我们接着就要写Javascript代码来调用这个功能了,如何写呢?继续往下看,我在assets/www/plugins/下新增目录并建立了文件gcapp.js,完整路径是 assets/www/plugins/com.gldjc.guangcaiclient/www/gcapp.js,代码如下:

cordova.define('com.gldjc.guangcaiclient.gcapp', function(require, exports, module) {
        var exec = require("cordova/exec");
        function Gcapp() {};
 
        Gcapp.prototype.version = function (getversion) {
            exec(getversion, null, 'Gcapp', 'version', []);
        };   
 
      Gcapp.prototype.checkUpdate = function () {
            exec(null, null, 'Gcapp', 'checkUpdate', []);
        };   
 
        var gcapp = new Gcapp();
        module.exports = gcapp;
});

exec是cordova.js中内部的函数,当插件返回 PluginResult.Status.OK 时会执行exec的成功回调函数,如果插件返回的是错误,则会执行exec的错误回调函数。这里我们解释一下

 exec(null, null, 'Gcapp', 'checkUpdate', []);

其中Gcapp就是我们在上一步骤加的feature名称,大小写匹配着写,通过这个名称,cordova才能找到调用那个java插件类,然后通过checkUpdate知道调用这个插件类的哪个方法,后面[]中则是参数。因为我这个插件不需要参数,所以为空。

Javascript插件类也配对成功了,那如何调用呢?你可以直接在html中包括这个js,不过我们一般会再配置一个js,那就是assets/www/cordova_plugins.js,这样就不用对每个插件类都去写一遍了,cordova会遍历你的配置去加载它们。

cordova.define('cordova/plugin_list', function(require, exports, module) {
module.exports = [
    {
        "file": "plugins/org.apache.cordova.device/www/device.js",
        "id": "org.apache.cordova.device.device",
        "clobbers": [
            "device"
        ]
    },
    {
        "file": "plugins/org.apache.cordova.networkinformation/www/network.js",
        "id": "org.apache.cordova.networkinformation.network",
        "clobbers": [
            "navigator.connection",
            "navigator.network.connection"
        ]
    },
     {
        "file": "plugins/org.apache.cordova.networkinformation/www/Connection.js",
        "id": "org.apache.cordova.networkinformation.Connection",
        "clobbers": [
            "Connection"
        ]
    },
     {
        "file": "plugins/org.apache.cordova.splashscreen/www/splashscreen.js",
        "id": "org.apache.cordova.splashscreen",
        "clobbers": [
            "navigator.splashscreen"
        ]
    },
        {
        "file" : "plugins/org.apache.cordova.camera/www/CameraConstants.js",
        "id" : "org.apache.cordova.camera.Camera",
        "clobbers" : [ "Camera" ]
    },
    {
        "file" : "plugins/org.apache.cordova.camera/www/CameraPopoverOptions.js",
        "id" : "org.apache.cordova.camera.CameraPopoverOptions",
        "clobbers" : [ "CameraPopoverOptions" ]
    },
    {
        "file" : "plugins/org.apache.cordova.camera/www/Camera.js",
        "id" : "org.apache.cordova.camera.camera",
        "clobbers" : [ "navigator.camera" ]
    },
    {
        "file" : "plugins/org.apache.cordova.camera/www/CameraPopoverHandle.js",
        "id" : "org.apache.cordova.camera.CameraPopoverHandle",
        "clobbers" : [ "CameraPopoverHandle" ]
    },
    {
        "file" : "plugins/com.phonegap.plugins.barcodescanner/www/barcodescanner.js",
        "id" : "com.phonegap.plugins.barcodescanner.barcodescanner",
        "clobbers" : [ "barcodescanner" ]
    },
    {
        "file": "plugins/com.gldjc.guangcaiclient/www/gcapp.js",
        "id": "com.gldjc.guangcaiclient.gcapp",
        "clobbers": [
            "gcapp"
        ]
    }
];
module.exports.metadata =
// TOP OF METADATA
{
    "org.apache.cordova.device": "0.2.13"
}
// BOTTOM OF METADATA
});

file表示我们去哪里找脚本插件定义js,id是之前我们在gcapp.js中开头cordova.define中写的标识,cordova通过这个标志去找到我们的Javascript插件定义,而clobbers则是我们在前端通过什么对象名来调用这个插件。这里我写的是gcapp,则后面调用则只需要写成gcapp.checkUpdate 即可

插件的调用

万事俱备,只欠东风,你们可以开始看到结果了,如果从头到这里一步成功,那应该还是蛮兴奋的事情吧。

具体前端页面如何设计我就不说了,我的页面效果就如本文最前面的图片,在js中我是这些调用version的,至于checkUpdate就是一样了,在按钮的click事件中调用 gcapp.checkUpdate(); 即可

$(document).on("PG_pageinit", function(event) {
    gcapp.version(function(version){
            $("#version").html(version);
    });
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/524015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大腹太卷】一篇文章带你了解校招的神秘面纱

校招求职复盘 写在前面方向确定前置工作就业信息获取简历制作简历投递 笔面试工作测评笔试面试八股文自我介绍项目相关HR面试反问环节 Offer选择写在后面 写在前面 2023届应届生&#xff0c;去年的时候参加了校招&#xff0c;一路走来&#xff0c;感慨良多&#xff0c;特此记录…

蚊香液、蚊香片、蚊香盘的优缺点

夏天来了&#xff0c;蚊子也出来活动了&#xff0c;又到了消灭蚊子的季节。     蚊子是凭借人所呼出的二氧化碳和带气味的气体&#xff0c;来定位人的位置&#xff0c;进而叮咬人的皮肤。     蚊子吸人血&#xff0c;主要是利用血液里的胆固醇、B族维生素&#xff0c;促进蚊…

OSPF综合实验(第一部分)

目录 要求 确定广播域的个数 分配网段 配置路由器IP地址-优先公网配通 配置MGRE部分 拓扑结构&#xff1a; 要求 1、R4为ISP&#xff0c;其上只能配置IP地址&#xff0c;R4与其他所有直连设备间使用公有IP 2、R3~R5/6/7为MGRE环境&#xff0c;R3为中心站点 3、整个OSPF环境I…

《编程思维与实践》1072.下一位妙数

《编程思维与实践》1072.下一位妙数 题目 思路 思路与最小不重复数基本一致,从最高位开始找到第一个出现9的位置,让其加1,后面全变为0即可. 只需要再加一个判定条件:不能被9整除. 由数学知识,一个数不能被9整除当且仅当各位数之和不能被9整除. 这里给出简单的证明: 不妨以三位…

Linux-初学者系列7_shell编程

在进行服务器集群管理时&#xff0c;需要编写shell程序来进行服务器管理。 shell是一个命令行解释器&#xff0c;他会为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序&#xff0c;用户用shell启动、挂起、停止和编写一些程序。 Linux-初学者系列7_shell编程…

简单记录一下spi的四种mode

0 前言 最近在学习SPI&#xff0c;刚开始接触四种mode的时候&#xff0c;还有点懵&#xff0c;也是搜了好几个博客&#xff0c;才算搞懂&#xff0c;特此记录下&#xff0c;防止下次又要翻好几篇博客才找到答案 >_< 1 四种mode的组成单元 这四种mode是由时钟极性和时钟…

Leetcode刷题之反转链表Ⅱ

业精于勤而荒于嬉&#xff0c;行成于思而毁于随。 ——韩愈目录 前言&#xff1a; &#x1f341;一.反转链表Ⅱ &#x1f352;1.left和right中间链表反转&#xff0c;再把反转链表和剩下的链接起来 &#x1f5fc;2.left和right中间链表头插 题目描述…

「实验记录」MIT 6.824 Raft Lab2A Leader Election

#Lab2A - Leader Election I. SourceII. My CodeIII. MotivationIV. SolutionS1 - 角色转换S2 - 发起 RequestVote 拉票请求S3 - 收到 RequestVote 的不同反应S4 - 发送 AppendEntries 心跳包S5 - 收到 AppendEntries 的不同反应S6 - defs.go约定俗成和GetState() V. Result I.…

The service already exists!

文章目录 项目场景&#xff1a;原因分析&#xff1a;解决方案&#xff1a; 项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 在给一位同学安装MySQL时报了这个错&#xff0c;我知道是她之前安装过但是没删干净的原因 但是我把Everything和注册表都查…

五、RGB实验(正点原子达芬奇Pro代码>>ZYNQ 7020代码移植)

RGB实验(正点原子达芬奇Pro代码&#xff1e;&#xff1e;ZYNQ 7020代码移植) 文章目录 RGB实验(正点原子达芬奇Pro代码&#xff1e;&#xff1e;ZYNQ 7020代码移植)前言一、本文目标二、移植步骤1.建立文件2.建立v文件1.lcd_rgb_colorbar2.lcd_driver3.rd_id4.clk_div5.lcd_dis…

单调队列算法模板及应用

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/algorithms-notes 】或者公众号【AIShareLab】回复 算法笔记 也可获取。 文章目录 队列算法模板例题&#xff1a;滑动窗口code 队列算法模板 // hh 表示队头&#xff0c;tt表示队尾 int q[N], hh 0…

使用Advanced Installer软件将winform程序打包成exe安装文件

在使用vs编写c#代码时&#xff0c;一般都是在debug文件中双击exe文件就可以执行&#xff0c;但是有时候需要将这个exe文件发给别人使用&#xff0c;在自己的电脑上exe文件可以执行&#xff0c;但是在别人的电脑上有时候打开后会报错&#xff0c;提示缺少.neta运行环境&#xff…

AUTUSAR通信篇 - CAN网络通信(一)

第一篇从全局角度出发&#xff0c;简单介绍了AUTOSAR的结构&#xff0c;从本篇开始我们一起详细了解一下AUTOSAR软件架构下内部的组成部分。下面&#xff0c;我们首先介绍第一个模块-通信。在AUTOSAR BSW中通信由三个部分组成&#xff0c;分别是&#xff1a;通信驱动、通信抽象…

【计算机视觉 | Pytorch】timm 包的具体介绍和图像分类案例(含源代码)

一、具体介绍 timm 是一个 PyTorch 原生实现的计算机视觉模型库。它提供了预训练模型和各种网络组件&#xff0c;可以用于各种计算机视觉任务&#xff0c;例如图像分类、物体检测、语义分割等等。 timm 的特点如下&#xff1a; PyTorch 原生实现&#xff1a;timm 的实现方式…

Java之线程池

目录 一.上节复习 1.阻塞队列 二.线程池 1.什么是线程池 2.为什么要使用线程池 3.JDK中的线程池 三.工厂模式 1.工厂模式的目的 四.使用线程池 1.submit()方法 2.模拟两个阶段任务的执行 五.自定义一个线程池 六.JDK提供线程池的详解 1.如何自定义一个线程池? 2.创…

【计网】第三章 数据链路层(3)信道划分介质访问控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 3.5-1 信道划分介质访问控制&#xff08;播报信道中应用&#xff09;一、传输数据使用的两种链路二、介质访问控制 三、信道划分 介质访问控制&#xff08;静态划分…

协程切换原理与实践 -- 从ucontext api到x86_64汇编

目录 1.协程切换原理理解 2.ucontext实现协程切换 2.1 实现流程 2.2 根据ucontext流程看协程实现 2.3 回答开头提出的问题 3.x86_64汇编实现协程切换 3.1libco x86_64汇编代码分析 3.2.保存程序返回代码地址流程 3.3.恢复程序地址以及上下文 4.实现简单协程框架 1.协程…

《编程思维与实践》1071.猜猜猜

《编程思维与实践》1071.猜猜猜 题目 思路 对于首字符而言,如果后一位字符与之相同,则首位选法只有1种,不同则2种; 对于最后一位字符而言,如果前一位字符与之相同,则末位选法只有1种,不同则2种; 对于中间的字符而言,有以下几种可能: 1.中间字符与前后字符均不同且前后字符不同…

企业挑选人力资源管理系统,需要从哪些角度考察?

企业在挑选人力资源管理系统时&#xff0c;除了要考虑到企业自身的主要需求外&#xff0c;还应该从哪些角度考察人力资源管理系统呢&#xff1f;一起来看看吧~ 一. 数据是否共通 企业在人力资源管理系统时通常有多个功能模块的需求。除了要看系统是否具备这些功能模块&#xff…

一分钟图情论文:《数据与信息之间逻辑关系的探讨——兼及DIKW概念链模式》

一分钟图情论文&#xff1a;《数据与信息之间逻辑关系的探讨——兼及DIKW概念链模式》 1989年&#xff0c;Ackoff R L在论文&#xff1a;《From data to wisdom》中正式提出DIKW概念链模型&#xff0c;在该模型提出后的20年间&#xff0c;在计算机学科、信息管理学科、图书情报…