摘要:任何初始化任務應該在文件中的事件的事件處理函數中。這個配置文件有幾個地方很關鍵,一開始沒有認真看,將插件導進工程跑的時候各種問題,十分頭痛,不得不重新認真看看文檔。
前言
來新公司的第一個任務,研究hybrid App中間層實現原理,做中間層插件開發。這個任務挺有意思,也很有挑戰性,之前在DCloud雖然做過5+ App開發,但是中間層的東西確實涉及不多。本系列文章屬于系列開篇cordova學習筆記,本文主要是從零開始搭建一個cordova工程,并了解cordova開發的基本內容。
創建第一個AppApache Cordova是一個開源的移動開發框架。允許你用標準的web技術-HTML5,CSS3和JavaScript做跨平臺開發。 應用在每個平臺的具體執行被封裝了起來,并依靠符合標準的API綁定去訪問每個設備的功能,比如說:傳感器、數據、網絡狀態等。
Cordova官網:http://cordova.apache.org/
Cordova中文網:http://cordova.axuer.com/
Cordova中文站:http://www.cordova.org.cn/
npm install -g cordova
安裝完成可以通過cordova -v查看版本號,本文是在V6.5.0下構建。
2.新建項目cordova create[ID [NAME [CONFIG]]] [options]
Create a Cordova project:
PATH —— 項目路徑
ID —— app 包名 - used in
NAME —— app 名稱
CONFIG —— 配置文件地址 json string whose key/values will be included in [PATH]/.cordova/config.json
Options:
--template=
--copy-from|src=
--link-to=
Example:
cordova create hello-cordova io.zhaomenghuan HelloCordova
這將會為你的cordova應用創造必須的目錄。默認情況下,cordova create命令生成基于web的應用程序的骨骼,項目的主頁是 www/index.html 文件。
3.添加平臺所有后續命令都需要在項目目錄或者項目目錄的任何子目錄運行:
cd hello-cordova
給你的App添加目標平臺。我們將會添加ios和android平臺,并確保他們保存在了config.xml中:
cordova platform add ios --save cordova platform add android --save
運行add或者remove平臺的命令將會影響項目platforms的內容,在這個目錄中每個指定平臺都有一個子目錄。
注意:在你使用CLI創建應用的時候, 不要 修改/platforms/目錄中的任何文件。當準備構建應用或者重新安裝插件時這個目錄通常會被重寫。
檢查你當前平臺設置狀況:
cordova platform is Installed platforms: android 6.1.2 Available platforms: amazon-fireos ~3.6.3 (deprecated) blackberry10 ~3.8.0 browser ~4.1.0 firefoxos ~3.6.3 webos ~3.7.0 windows ~4.4.0 wp8 ~3.8.2 (deprecated)
安裝構建先決條件:
要構建和運行App,你需要安裝每個你需要平臺的SDK。另外,當你使用瀏覽器開發你可以添加 browser平臺,它不需要任何平臺SDK。
檢測你是否滿足構建平臺的要求:
cordova requirements Requirements check results for android: Java JDK: installed 1.8.0 Android SDK: installed true Android target: installed android-7,android-8,android-9,android-10,android-11,android-12,android-13,android-14,android-15,android-16,android-17,android-18,android-19,android-20,android-21,android-22,android-23,android-24,android-25 Gradle: installed
初次使用我們可能會遇到下面的報錯:
Error: Failed to find "ANDROID_HOME" environment variable. Try setting setting it manually. Failed to find "android" command in your "PATH". Try update your "PATH" to include path to valid SDK directory.
這是因為我們沒有配置環境變量:
設置JAVA_HOME環境變量,指定為JDK安裝路徑
設置ANDROID_HOME環境變量,指定為Android SDK安裝路徑
添加Android SDK的tools和platform-tools目錄到你的PATH
對于android平臺下的環境配置在這里不再贅述,具體可以參考:
Android平臺的要求
iOS平臺的要求
Windows平臺的要求
4.構建App默認情況下,?cordova create生產基于web應用程序的骨架,項目開始頁面位于www/index.html
?文件。任何初始化任務應該在www/js/index.js文件中的deviceready事件的事件處理函數中。
運行下面命令為所有添加的平臺構建:
cordova build
你可以在每次構建中選擇限制平臺范圍 - 這個例子中是android:
cordova build android
注意:首次使用時,命令行提示 Downloading https://services.gradle.org/distributions/gradle-2.14.1-all.zip,是在下載對應的gradle并自動解壓安裝,根據網絡狀況,可能耗時極長,且容易報錯。
使用Cordova編譯Android平臺程序提示:Could not reserve enough space for 2097152KB object heap。
Error occurred during initialization of VM Could not reserve enough space for 2097152KB object heap
大體的意思是系統內存不夠用,創建VM失敗。試了網上好幾種方法都不行,最后這個方法可以了:
開始->控制面板->系統->高級設置->環境變量->系統變量
新建變量:
變量名: _JAVA_OPTIONS
變量值: -Xmx512M
我們有多種方式運行我們的App,在不同場景下使用不同的方式有助于我們快速開發和測試我們的應用。
在命令行運行下面的命令,會重新構建App并可以在特定平臺的模擬器上查看:
cordova emulate android
你可以將你的手機插入電腦,在手機上直接測試App:
cordova run android
在進行打包操作前,我們可以通過創建一個本地服務預覽app UI,使用指定的端口或缺省值為8000運行本地Web服務器www/assets。訪問項目:http://HOST_IP:PORT/PLATFORM/www。
cordova serve [port]
參考文檔:
設置Android模擬器
Cordova run 命令參考文檔
Cordova emulate 命令參考文檔
6.安裝插件cordova的強大之處在于我們可以通過安裝插件,拓展我們web工程的能力,比如調用系統底層API來調用設備上的底層功能,如攝像頭、相冊。通過cordova plugin命令實現插件管理。
可以在這里搜索需要的插件:Cordova Plugins 。
cordova {plugin | plugins} [ add[..] {--searchpath= | --noregistry | --link | --save | --browserify | --force} | {remove | rm} { | } --save | {list | ls} | search [ ] | save | ]
添加插件:
cordova plugin add[...]
移除插件:
cordova plugin remove [...]7.平臺為中心的工作流開發App
上面我們是在跨平臺(CLI)的工作流進行,原則上如果我們不需要自己寫原生層自定義組件,我們完全可以只在CLI上完成我們的工作,當然如果需要進一步深入了解cordova native與js的通信聯系,我們需要切換到平臺為中心的工作流,即將我們的cordova工程導入到原生工程。例如:我們可以使用android studio導入我們新建的cordova工程。
官方推薦的插件遵循相同的目錄結構,根目錄下是plugin.xml配置文件,src目錄下放平臺原生代碼,www下放js接口代碼,基本配置方法和代碼結構由一定規律,我們使用plugman可以生成一個插件模板,改改就可以寫一個自定義插件。
1.安裝 plugman ,使用 plugman 創建插件模板npm install -g plugman
比如這里我們創建一個nativeUI的插件:
plugman create --name NativeUI --plugin_id cordova-plugin-nativeui --plugin_version 0.0.1
參數介紹:
pluginName: 插件名字:NativeUI
pluginID: 插件id : cordova-plugin-nativeui
oversion: 版本 : 0.0.1
directory:一個絕對或相對路徑的目錄,該目錄將創建插件項目
variable NAME=VALUE: 額外的描述,如作者信息和相關描述
進入插件目錄
cd NativeUI
給 plugin.xml 增加Android平臺
plugman platform add --platform_name android
生成的插件文件結構為:
NativeUI: ├── src └── android └── NativeUI.java ├── www └── NativeUI.js └── plugin.xml2.修改配置文件
plugin.xml文件字段含義:
元素 | 描述 |
---|---|
plugin | 定義命名空間,ID和插件版本。應該用定義在http://apache.org/cordova/ns/...命名空間。plugin的ID在輸入cordova plugins命令時在插件列表中顯示。 |
name | 定義插件的名字。 |
description | 定義插件的描述信息。 |
author | 定義插件作者的名字。 |
keywords | 定義與插件相關的關鍵字。Cordova研發組建立了公開、可搜索的插件倉庫,添加的關鍵字能在你把插件提交到倉庫后幫助被發現。 |
license | 定義插件的許可。 |
engines | 用來定義插件支持的Cordova版本。再添加engine元素定義每個支持的Cordova版本。 |
js-module | 指js文件名,而這個文件會自動以
cordova.js在創建Android工程的時候,是從cordova的lib目錄下Copy到platformsandroidassetswwwcordova.js的。同時備份到platformsandroidplatform_wwwcordova.js。下一篇文章我會試著讀一下cordova.js的源碼,這里對cordova.js暫不做深入探究。 這里我們主要關心幾個地方,我們的原生代碼在src目錄下,assets/www目錄下是我們的web 程序。www目錄下的plugins文件夾就是我們的插件js部分,cordova_plugins.js是根據plugins文件夾的內容生成的。 cordova_plugins.js的整體結構: cordova.define("cordova/plugin_list", function(require, exports, module) { module.exports = [ { "id": "cordova-plugin-nativeui.NativeUI", "file": "plugins/cordova-plugin-nativeui/www/NativeUI.js", "pluginId": "cordova-plugin-nativeui", "clobbers": [ "agree.nativeUI" ] }, ... ]; module.exports.metadata = // TOP OF METADATA { "cordova-plugin-nativeui": "0.0.1", ... }; // BOTTOM OF METADATA });Android插件開發指南 Android插件基于Cordova-Android,它是基于具有Javscript-to-native橋接的Android WebView構建的。 Android插件的本機部分至少包含一個擴展CordovaPlugin類的Java類,并重寫其一個執行方法。 插件類映射插件的JavaScript接口使用cordova.exec方法,如下所示: cordova.exec( function(winParam) {}: 成功回調 function(error) {}: 錯誤回調 service: 原生層服務名稱 action: js層調用方法名 [args]: js層傳遞到原生層的數據 這將WebView的請求傳遞給Android本機端,有效地在服務類上調用action方法,并在args數組中傳遞其他參數。無論您將插件分發為Java文件還是作為自己的jar文件,必須在Cordova-Android應用程序的res / xml / config.xml文件中指定該插件。 有關如何使用plugin.xml文件注入此要素的詳細信息,請參閱應用程序插件: 插件初始化及其生命周期 一個插件對象的一個實例是為每個WebView的生命創建的。 插件不會被實例化,直到它們被JavaScript的調用首次引用為止,除非在config.xml中將具有onload name屬性的設置為“true”。 插件使用 initialize 初始化啟動: @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); // your init code here } 插件還可以訪問Android生命周期事件,并可以通過擴展所提供的方法(onResume,onDestroy等)來處理它們。 具有長時間運行請求的插件,媒體播放,偵聽器或內部狀態等背景活動應實現onReset()方法。 當WebView導航到新頁面或刷新時,它會執行,這會重新加載JavaScript。 編寫Android Java插件一個JavaScript調用觸發對本機端的插件請求,并且相應的Java插件在config.xml文件中正確映射,但最終的Android Java Plugin類是什么樣的? 使用JavaScript的exec函數發送到插件的任何東西都被傳遞到插件類的execute方法中。 插件的JavaScript不會在WebView界面的主線程中運行; 而是在WebCore線程上運行,執行方法也是如此。 如果需要與用戶界面進行交互,應該使用Activity的runOnUiThread方法。 如果不需要在UI線程上運行,但不希望阻止WebCore線程,則應使用cordova.getThreadPool()獲得的Cordova ExecutorService執行代碼。 ... @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { if (action.equals("toast")) { this.toast(args.getString(0)); return true; } return false; } /** * Builds and shows a native Android toast with given Strings * * @param message The message the toast should display */ private void toast(final String message) { final CordovaInterface cordova = this.cordova; if (message != null && message.length() > 0) { final int duration = Toast.LENGTH_SHORT; Runnable runnable = new Runnable() { public void run() { Toast toast = Toast.makeText(cordova.getActivity().getApplicationContext(), message, duration); toast.show(); } }; cordova.getActivity().runOnUiThread(runnable); } } ... js部分的代碼: var exec = require("cordova/exec"); module.exports = { toast: function(message) { exec(null, null, "NativeUI", "toast", [message]); } } callbackContext.success可以將原生層字符串作為參數傳遞給JavaScript層的成功回調,callbackContext.error可以將給JavaScript層的錯誤回調函數傳遞參數。 添加依賴庫如果你的Android插件有額外的依賴關系,那么它們必須以兩種方式之一列在plugin.xml中: 首選的方法是使用 第二個選項是使用 Android具有Intent系統,允許進程相互通信。插件可以訪問CordovaInterface對象,可以訪問運行應用程序的Android Activity。 這是啟動新的Android Intent所需的上下文。 CordovaInterface允許插件為結果啟動Activity,并為Intent返回應用程序時設置回調插件。 從Cordova 2.0開始,插件無法再直接訪問上下文,并且舊的ctx成員已被棄用。 所有的ctx方法都存在于Context中,所以getContext()和getActivity()都可以返回所需的對象。
Android 6.0 "Marshmallow" 引入了新的權限模型,用戶可以根據需要啟用和禁用權限。這意味著應用程序必須將這些權限更改處理為將來,這是Cordova-Android 5.0.0發行版的重點。 就插件而言,可以通過調用權限方法來請求權限,該簽名如下: cordova.requestPermission(CordovaPlugin plugin, int requestCode, String permission); 為了減少冗長度,將此值分配給本地靜態變量是標準做法: public static final String READ = Manifest.permission.READ_CONTACTS; 定義requestCode的標準做法如下: public static final int SEARCH_REQ_CODE = 0; 然后,在exec方法中,應該檢查權限: if(cordova.hasPermission(READ)) { search(executeArgs); } else { getReadPermission(SEARCH_REQ_CODE); } 在這種情況下,我們只需調用requestPermission: protected void getReadPermission(int requestCode) { cordova.requestPermission(this, requestCode, READ); } 這將調用該活動并引起提示出現要求該權限。 一旦用戶擁有權限,結果必須使用onRequestPermissionResult方法處理,每個插件應該覆蓋該方法。 一個例子可以在下面找到: public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { for(int r:grantResults) { if(r == PackageManager.PERMISSION_DENIED) { this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, PERMISSION_DENIED_ERROR)); return; } } switch(requestCode) { case SEARCH_REQ_CODE: search(executeArgs); break; case SAVE_REQ_CODE: save(executeArgs); break; case REMOVE_REQ_CODE: remove(executeArgs); break; } } 上面的switch語句將從提示符返回,并且根據傳入的requestCode,它將調用該方法。 應該注意的是,如果執行不正確地處理權限提示可能會堆疊,并且應該避免這種情況。 除了要求獲得單一權限的權限之外,還可以通過定義權限數組來請求整個組的權限,如同Geolocation插件所做的那樣: String [] permissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION }; 然后當請求權限時,需要完成的所有操作如下: cordova.requestPermissions(this, 0, permissions); 這將請求數組中指定的權限。 提供公開訪問的權限陣列是一個好主意,因為可以使用插件作為依賴關系使用,盡管這不是必需的。 啟動其他活動如果你的插件啟動將Cordova活動推送到后臺的活動,則需要特別考慮。 如果設備運行內存不足,Android操作系統將在后臺銷毀活動。在這種情況下,CordovaPlugin實例也將被銷毀。 如果您的插件正在等待其啟動的活動的結果,則當Cordova活動返回到前臺并獲得結果時,將創建一個新的插件實例。 但是,插件的狀態不會自動保存或恢復,插件的CallbackContext將丟失。 CordovaPlugin可以實現兩種方法來處理這種情況: /** * Called when the Activity is being destroyed (e.g. if a plugin calls out to an * external Activity and the OS kills the CordovaActivity in the background). * The plugin should save its state in this method only if it is awaiting the * result of an external Activity and needs to preserve some information so as * to handle that result; onRestoreStateForActivityResult() will only be called * if the plugin is the recipient of an Activity result * * @return Bundle containing the state of the plugin or null if state does not * need to be saved */ public Bundle onSaveInstanceState() {} /** * Called when a plugin is the recipient of an Activity result after the * CordovaActivity has been destroyed. The Bundle will be the same as the one * the plugin returned in onSaveInstanceState() * * @param state Bundle containing the state of the plugin * @param callbackContext Replacement Context to return the plugin result to */ public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {}總結 cordova 是否能夠發揮出它出彩的一面還是源于我們對原生的熟練程度,只有對原生足夠熟練,對cordova的運行機制足夠熟悉才能做出一個相對比較令人滿意的App,后面的文章我會嘗試閱讀cordova的源碼,深入解析cordova的實現原理和插件機制,也會教大家封裝一些常用的自定義組件。本文內容基本取材于官方文檔,只是借助谷歌翻譯以及自己在探索過程中的一些問題,做了一些增刪,如果有任何問題,希望各位不吝指教。 寫文章不容易,也許寫這些代碼就幾分鐘的事,寫一篇大家好接受的文章或許需要幾天的醞釀,然后加上幾天的碼字,累并快樂著。如果文章對您有幫助請我喝杯咖啡吧! 轉載需標注本文原始地址:https://zhaomenghuan.github.io/ 文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。 轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82692.html 相關文章
發表評論0條評論buildupchao男|高級講師TA的文章閱讀更多
閱讀需要支付1元查看
|