一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

PhoneGap 在 Android 上的插件開發(fā)方法介紹

 JS資料庫 2014-08-08

簡介: 移動應用開發(fā)已經(jīng)成為軟件開發(fā)的一個重要方向,但是移動開發(fā)面臨的一個重要問題就是跨平臺的問題。 PhoneGap 作為一個多平臺的軟件開發(fā)框架,提供了一次編寫多個平臺的運行。目前已經(jīng)支持多達 6 個移動平臺。對應平臺的插件開發(fā)則可以為 PhoneGap 擴展 API 的本地接口,提供更加復雜的特性。了解 PhoneGap 框架的原理以便為 PhoneGap 提供本地的插件接口成為 PhoneGap 應用開發(fā)的重要方面。本文將以一個簡單的實例介紹 PhoneGap 在 Android 上的插件開發(fā)方法。閱讀本文需要基本的 Android 開發(fā)經(jīng)驗和 PhoneGap 開發(fā)經(jīng)驗。

PhoneGap 簡介

PhoneGap 是利用 HTML 來開發(fā)移動應用的一個開放源代碼的框架,利用它就可以僅僅使用 HTML 和 Javascript 實現(xiàn)一次編寫,多個移動平臺運行的應用。目前已經(jīng)可以支持 Android、iOS、BlackBerry 等 6 個平臺。在完成這篇短文的過程中,PhoneGap 正式發(fā)布了 1.0.0 版本。因而短文中的版本使用的是 1.0.0rc2 版本的代碼。

PhoneGap 在 Android 平臺上的實現(xiàn)的框架是利用了在本地代碼和瀏覽器間建立中間層來實現(xiàn)對 Java 代碼的隔離。利用瀏覽器的接口和網(wǎng)絡 socket 接口實現(xiàn)數(shù)據(jù)的通訊。因此在對 PhoneGap 框架的理解上,需要從 Java 端和瀏覽器端兩部分來分別學習。

關于 Android 開發(fā)環(huán)境和 PhoneGap 開發(fā)環(huán)境的搭建,請參考參考資料中的開發(fā)者網(wǎng)站實施。

Java 端介紹

Java 端作為后臺調(diào)用 Android 本地 SDK 的接口,主要實現(xiàn)了如下的功能:

  1. 建立通訊機制,提供接口給瀏覽器端,方便 JavaScript 進行調(diào)用。
  2. 數(shù)據(jù)隊列的維護,以保證瀏覽器端的調(diào)用后產(chǎn)生的數(shù)據(jù)可以回送。
  3. 插件體系的建立,提供整個框架的可擴展性。

而這三部分的功能對應到代碼中則是如下的幾個重要的 Java 類:

  1. DroidGap、CallbackServer
  2. CallbackServer
  3. Plugin、PluginManager

因此我們需要依次來了解這幾個重要的 Java 類的具體實現(xiàn),這樣才可以對 PhoneGap 在 Android 上的體系有一個很好的了解。

DroidGap 的實現(xiàn)

當我們完成一個基本的 PhoneGap 的示例后,我們就會發(fā)現(xiàn),在使用 PhoneGap 進行開發(fā)的手機應用中,第一步就是將繼承關系 extends Activity 修改為 extends DroidGap。因此,DroidGap 是整個應用開始的地點,首先需要了解 DroidGap 的內(nèi)容。

在源碼中可以看到 DroidGap 繼承自 PhonegapActivity,而 PhonegapActivity 是一個抽象類,繼承自 Activity,但是具體的實現(xiàn)都是集中在 DroidGap 類中。

因此,我們繼續(xù)回到 DroidGap 類中,當我們知道 DroidGap 類也是一個 Acitvity 后,就會明白,DroidGap 在 onCreate 方法中實現(xiàn)了整個類最初的一些操作,代碼的實現(xiàn)則集中在 onCreate() 和 init() 這兩個方法中,具體的流程如下:

  1. 設置 WebView

設置 WebView 的代碼都集中在 init() 方法中,其中一個值得注意的工作是設置 WebChromClient。代碼中提供了一個繼承自 WebChromClient 的類,重寫了其中的 onJsAlert,onJsConfirm,onJsPrompt 等方法。而在 onJsPrompt() 方法中,實現(xiàn)了 PhoneGap 中 Java 端和瀏覽器端通訊的關鍵一步。因此,值得我們專門的關注其代碼,具體的功能實現(xiàn)代碼如下,我們已經(jīng)過濾了一些錯誤處理、安全驗證等等可能會妨礙我們對重要 的功能實現(xiàn)理解的代碼:


代碼清單 1. WebView 代碼
				
 if (reqOk && defaultValue != null && defaultValue.length() > 3 
 && defaultValue.substring(0, 4).equals("gap:")) { 
   JSONArray array; 
   try { 
 array = new JSONArray(defaultValue.substring(4)); 
 String service = array.getString(0); 
 String action = array.getString(1); 
 String callbackId = array.getString(2); 
 boolean async = array.getBoolean(3); 
 String r = pluginManager.exec(service, action, callbackId, message, async); 
 result.confirm(r); 
 } catch (JSONException e) { 
 e.printStackTrace(); 
 } 
 } 
 // Polling for JavaScript messages 
 else if ...... 

在此,我們就可以明白,實現(xiàn) JavaScript 與 Java 端通訊的原理是 JavaScript 利用 prompt 來傳遞調(diào)用信息的數(shù)據(jù),在 onJsPrompt 中,重寫的方法截獲了這些數(shù)據(jù),在完成了對數(shù)據(jù)格式等等分析后,按照要求進行具體的調(diào)用。而具體的調(diào)用利用是的 PluginManager 類,這將在隨后說明。

  1. 綁定 js

在完成 WebView 的設置后,再將 PhoneGap 和 js 綁定,實現(xiàn) js 與 PhoneGap 的通訊。在這一步中主要的內(nèi)容就是實例化了 CallbackServer 和 PluginManager 兩個類。因此,更多的內(nèi)容會在隨后對這兩個類的介紹中再說明。

  1. 載入 URL

LoadUrl 方法也是實現(xiàn)一個 PhoneGap 示例后很熟悉的方法,在 loadUrl 中,完成基本的字符串處理后,主要利用 runOnUiThread 開始處理,其中第一步檢測是否需要提供載入的顯示,之后使用 WebView 的 loadUrl 載入內(nèi)容,并且設置超時時間。

至此,Java 端的準備工作也就完成,實現(xiàn)了 UI 的載入。可以看到,在 DroidGap 類中最重要的一個部分就是截獲 JavaScript 的 prompt 數(shù)據(jù)。這是實現(xiàn)瀏覽器端和 Java 端通訊的基礎。

Plugin 的實現(xiàn)

Plugin 是一個抽象類,實現(xiàn)了 IPlugin 接口,PhoneGap 中利用 Android SDK 實現(xiàn)邏輯代碼的途徑就是通過繼承 Plugin 來實現(xiàn)。應此 Plugin 本身非常簡單,最主要的部分是提供一個 execute 方法,如下:

 public abstract PluginResult execute(String action, JSONArray args, String callbackId); 

Plugin 的實現(xiàn)中的重要邏輯在其中來實現(xiàn),它返回的是一個 PluginResult 對象,這個對象主要負責傳遞數(shù)據(jù)信息,包括的成員主要如下:

	 private final int status; 

用于返回狀態(tài),status 與一個 enum 類型相關,用于標注插件的執(zhí)行結果如何。

	 private final String message; 

用于返回數(shù)據(jù)信息。

PluginManager 的實現(xiàn)

PluginManager 事實上是 DroidGap 類和具體的繼承自 Plugin 的插件的聯(lián)系紐帶,由它來尋找和載入插件,并且調(diào)用。

首先,PluginManager 在構造函數(shù)中,調(diào)用了 loadPlugins 方法,該方法負責解析 xml 配置文件,對應每個 plugin,調(diào)用一次 addService 用于注冊插件,具體的注冊地點,是通過維護一個 HashMap<String, String> 來實現(xiàn),分別保存 serviceType, className。在成員中,有另外一個 HashMap<String, IPlugin> 用于實現(xiàn) className 和 IPlugin 類的綁定。這樣就實現(xiàn)了 serviceType 和 IPlugin 的對應。

在 PluginManager 中,執(zhí)行插件的方法 exec 是主要功能,我們將會詳細說明一下這個方法的過程:

  1. 利用查詢之前提到的 HashMap<String, String> 將 service 和 className 對應起來,這樣我們就獲得了提供功能的插件類的位置。
  2. 通過 getClassByName 來獲得插件類。
  3. 完成類型檢測,確定對應的類是一個插件類。
  4. 執(zhí)行 addPlugin 方法,其中則將第 2 步中獲得插件類的 className 和具體的 Plugin 接口的實現(xiàn)綁定,具體的實現(xiàn)就是上文中提到的 HashMap<Strig,IPlugin>。
  5. 判斷 Plugin 是否需要異步執(zhí)行,再根據(jù)情況,選擇直接執(zhí)行或者是建立新的線程來執(zhí)行。
  6. 完成執(zhí)行后,得到的數(shù)據(jù)會根據(jù)情況交給 CallbackServer 來處理,PluginManager 會調(diào)用 DroidGap 中的 sendJavaScript 來將數(shù)據(jù)交給 CallbackServer,事實上,DroidGap 中的 sendJavaScript 不過是對 CallbackServer 中的 sendJavaScript 包裝,實際調(diào)用的是 CallbackServer 中的 sendJavaScript 方法,這涉及到了 CallbackServer 類,隨后就會說明。

執(zhí)行結果的轉(zhuǎn)換則是利用 PluginResult 中的一些 to***String 方法。這些方法返回了一個 String 類型,其中包括了具體的 JSON 對象和 callbackId,具體的形式則是一個 js 代碼,用于前端的調(diào)用。

CallbackServer 的實現(xiàn)

CallbackServer 實現(xiàn)了 Runnable 接口,具體的功能就是維護一個數(shù)據(jù)的隊列,并且建立一個服務器,用于 XHR 的數(shù)據(jù)傳遞,對數(shù)據(jù)的隊列的維護利用的是 LinkedList<String>。

由于實現(xiàn)的是 Runnable 接口,在 CallbackServer 中,最主要的方法就是 run() 方法,run() 方法的具體內(nèi)容簡介如下:

  1. 首先利用 ServerSocket 監(jiān)聽端口,具體端口則自由分配。
  2. 在 accept 后則是對 HTTP 協(xié)議的解析,和對應的返回 status code。
  3. 在驗證正確后,利用 getJavascript 方法得到維護的 LinkedList<String>() 中的保存的 js 代碼,如果為空則返回 null。
  4. 這些具體的 string 類型的 js 代碼則利用 socket 作為 response 返回給前端。

之后就是對隊列維護的方法,這時理解之前的 sendJavaScript 則很簡單,該方法與 getJavaScript 相反,一個是從 LinkedList 中取出 js 代碼,一個則是加入。

綜上,CallbackServer 實現(xiàn)的是兩個功能,一個是 XHR 的 SocketServer,一個是對隊列的維護。而完成 CallbackServer 類的說明后,Java 端的主要功能也都說明完畢。隨后會說明瀏覽器端的說明,在完成瀏覽器端說明后,我們就會明白整個 PhoneGap 框架運行的原理。

瀏覽器端介紹

瀏覽器端的 JavaScript 代碼較多,但是實現(xiàn)其中核心功能的代碼都在 PhoneGap 類中,其他的都是 PhoneGap 框架中自帶的一些 Plugin 的 JavaScript 代碼。

在瀏覽器端,其中一個最重要的函數(shù)就是 PhoneGap.exec 函數(shù),因為大部分的函數(shù)調(diào)用,最終都會在這里實現(xiàn)與本地 Java 端的數(shù)據(jù)通訊,轉(zhuǎn)而去調(diào)用 Java 端的 Plugin 來實現(xiàn)具體的執(zhí)行。主要的內(nèi)容如下,我們已經(jīng)去除一些非功能的錯誤處理代碼段,集中于具體的功能實現(xiàn):


代碼清單 2. PhonGap.exec 代碼
				
 var callbackId = service + PhoneGap.callbackId++; 
 if (success || fail) { 
    PhoneGap.callbacks[callbackId] = {success:success, fail:fail}; 
 } 
 var r = prompt(PhoneGap.stringify(args), "gap:"+ 
 PhoneGap.stringify([service, action, callbackId, true])); 
 // If a result was returned 
 if (r.length > 0) { 
    eval("var v="+r+";"); 
    // If status is OK, then return value back to caller 
    if (v.status === PhoneGap.callbackStatus.OK) { 
       ...... 
    }else if ...... 
 } 

在以上標紅加粗的代碼段上,我們可以看到,調(diào)用的是 prompt 方法 , 我們在之前特別提到了,PhoneGap 在 DroidGap 類中,繼承了一個 WebChromeClient, 其中重寫了方法 onJsPrompt,這樣在 Java 端,就截獲了瀏覽器端的調(diào)用?,F(xiàn)在可以回到之前的 Java 端的說明,查看之前列出的 onJsPrompt 代碼,聯(lián)系之前的 Java 端的介紹,就會覺得豁然開朗了,剩下了流程也就順理成章了。通過 r 的返回值,就可以輕松的返回數(shù)據(jù)給瀏覽器端了。

這時我們會有一個好奇,那就是 CallbackServer 的 SocketServer 的作用在哪里,因為至此我們已經(jīng)看到了整個數(shù)據(jù)在瀏覽器端和 Java 端的通訊,那么這樣的一個 SocketServer 又是提供的什么數(shù)據(jù)通訊呢?

顯然,在 PluginManager 中的 exec中,我們會返回執(zhí)行獲得的數(shù)據(jù),但是,在使用異步調(diào)用的時 候,立即返回的則是一個空字符串,也即沒有數(shù)據(jù)返回,之后插件會在一個新的線程中執(zhí)行,等到異步的插件執(zhí)行的結果返回數(shù)據(jù)后,會放入到隊列中,等待 XHR 的獲得。而 XHR 的調(diào)用是在 JavaScript 代碼初始化中開始調(diào)用的,其中由于 JsCallBack 函數(shù)有使用輪詢保證自己循環(huán)執(zhí)行。這樣就可以不斷的獲得異步數(shù)據(jù)。

Hello 插件的實現(xiàn)

掌握了上文中對 PhoneGap 框架的分析,我們就可以通過自己實現(xiàn)相關的插件來完成自己希望實現(xiàn)的功能,這樣就可以不斷豐富自己應用的功能。我們假設開發(fā)者已經(jīng)熟悉了 PhoneGap 和 Android 的基本開發(fā)知識,Android 和 PhoneGap 開發(fā)環(huán)境搭建已經(jīng)完成。

在具體的 Plugin 實現(xiàn)中,要分兩個部分來實現(xiàn),Java 代碼和 JavaScript 代碼,就此流程,我們來通過一個簡單的例子來看一下如何具體的完成 Plugin 的實現(xiàn)。

在 Java 端,我們要繼承一個 Plugin 類,實現(xiàn)其中的 execute 方法,在這里,我們省略具體的功能邏輯。

在 JavaScript 端,我們要利用現(xiàn)有 PhoneGap.exec 來調(diào)用具體的 Java 端,而且需要注意的是要在 PhoneGap 中注冊這一個插件,PhoneGap.addConstructor就在 JavaScript 端調(diào)用 Java 端代碼,完成添加,當然直接修改 XML 文件來實現(xiàn)也可以。

首先,完成 Java 端的代碼實現(xiàn)。

我們實現(xiàn)一個簡單的字符串回射程序,來模擬具體的邏輯,代碼如下:


清單 3. 插件實例 Java 端代碼
				
 @Override 
 public PluginResult execute(String action, JSONArray args, String callbackId) { 
 PluginResult.Status status = PluginResult.Status.OK; 
 PluginResult r=null; 
 if (action.equals("sayHello")){ 
 r = new PluginResult(status,"Hello"); 
 }else if (action.equals("saySth")){ 
 r = new PluginResult(status,args); 
 } 
 return r; 
 } 

實現(xiàn)的功能如下:

  1. 如果 action 的參數(shù)是 sayHello,則返回字符串“Hello”。
  2. 如果是 saySth,則返回 args 中的內(nèi)容。

之后,完成 JavaScript 代碼

請注意 JavaScipt 代碼是需要 HTML 代碼包含后才能使用的:


清單 4. 插件實例 JavaScript 端代碼
				
     var Hello=function(){ 
     } 
     Hello.prototype.saySth = function(msg, callback, fail) { 
 return PhoneGap.exec(function(args) { 
     callback(args); 
 }, function(args) { 
 if(typeof fail == 'function') { 
     fail(args); 
 } 
 }, 'Hello', 'saySth', [msg]); 
     } 
     Hello.prototype.sayHello = function(callback, fail) { 
 return PhoneGap.exec(function(args) { 
  callback(args); 
 }, function(args) { 
 if(typeof fail == 'function') { 
 fail(args); 
 } 
 }, 'Hello', 'sayHello',['sayHello']); 
     } 
     PhoneGap.addConstructor(function() { 
    PhoneGap.addPlugin('hello', new Hello()); 
    //PluginManager.addService("Hello","qj.Hello"); 
     }) 

在這里我們需要有一個特別的說明:

在上述 JavaScript 代碼中,我們注釋了 addConstructor 函數(shù)中的一行,因為我們在開發(fā)過程中發(fā)現(xiàn)這條代碼的執(zhí)行在 Javascript 端沒有被實現(xiàn)。

因此這段代碼具體的執(zhí)行則需要我們在 Java 端實現(xiàn)代碼,那么為了實現(xiàn)這段 JavaScript 代碼所做的補償性的 Java 代碼要在自己實現(xiàn)的 Java 端的 onCreate 函數(shù)中實現(xiàn),內(nèi)容是很簡單的一句(當然,也可以通過修改 xml 文件來實現(xiàn)這一功能,上文提到過,PluginManager 類會掃描 xml 文件來依次以對應 xml 文件中的插件名作為參數(shù)執(zhí)行這一調(diào)用):

 this.pluginManager.addService("Hello", "qj.Hello"); 

注意第二個參數(shù)是實現(xiàn)的插件的代碼的位置,Hello 插件的位置是“src.qj.Hello.java”,對應的位置信息就是去除 .java 后綴名后的位置信息,整個項目的組織結構如圖。


圖 1. 項目組織結構圖示例
圖 1. 項目組織結構圖示例

至此,Hello 插件已經(jīng)實現(xiàn),如果需要調(diào)用,則 JavaScript 代碼如下:


清單 5. 插件調(diào)用代碼
				
 window.plugins.hello.sayHello(function(arg){alert(arg);}, 
 function(arg){alert(arg);}); 
 window.plugins.hello.saySth("Bingo",function(arg){alert(arg);}, 
 function(arg){alert(arg);}); 

我們簡單的將返回的數(shù)據(jù)通過 alert() 展示出來,插件的執(zhí)行結果如下:

點擊 SayHello,


圖 2. 點擊 SayHello 示例
圖 2. 點擊 SayHello 示例

點擊 SayBingo


圖 3. 點擊 SayBingo 示例
圖 3. 點擊 SayBingo 示例

結束語

至此插件的開發(fā)已經(jīng)完成,其中很大的篇幅都是通過對 PhoneGap 的框架的說明,讓我們可以對插件的運行過程有一個更加底層的認識,我想這是比實現(xiàn)一個簡單的插件更加重要的東西。如果讀者需要了解更多的信息,請瀏覽參考資料中的開發(fā)者網(wǎng)站,獲得更加實時的信息。

文章出處:IBM developerWorks

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    蜜桃传媒视频麻豆第一区| 少妇人妻中出中文字幕| 中文字幕av诱惑一区二区| 久久精品国产一区久久久| 国产一区二区三区av在线| 欧美精品一区二区水蜜桃| 美女被草的视频在线观看| 日韩成人动画在线观看| 亚洲二区欧美一区二区| 欧美在线观看视频免费不卡| 中文字幕一区二区三区大片| 欧美人妻免费一区二区三区| 国产精品尹人香蕉综合网 | 在线免费看国产精品黄片| 国产中文字幕久久黄色片| 在线免费观看黄色美女| 日本不卡一区视频欧美| 欧美一级日韩中文字幕| 国产一区麻豆水好多高潮| 国产亚洲中文日韩欧美综合网| 国产精品午夜视频免费观看| 久久人人爽人人爽大片av| 一区二区三区18禁看| 国产一区二区三区口爆在线| 国产精品亚洲一区二区| 亚洲国产av在线视频| 99久久精品免费精品国产| 日本人妻丰满熟妇久久| 国产伦精品一区二区三区高清版| 一级片二级片欧美日韩| 久久热中文字幕在线视频| 亚洲国产另类久久精品| 日韩色婷婷综合在线观看| 日本精品啪啪一区二区三区| 青青久久亚洲婷婷中文网| 国产日韩欧美一区二区| 91午夜少妇极品福利| 日本亚洲欧美男人的天堂| 亚洲欧美中文字幕精品| 国产精品尹人香蕉综合网| 国产av精品高清一区二区三区|