在 《Cordova webapp實戰開發:(4)Android環境搭建》中我們搭建好了開發環境,也給大家布置了調用插件的預習作業,做得如何了呢?今天我們來學一下如何自己從頭建立一個Andorid下的cordova插件。
本次練習你能學到的
- 學習如何實現Android下自動更新功能
- 學習Android下插件類的編寫
- 學習Android下插件的配置
- 學習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); }); });