本文細致探討了 Xcode(以 iOS 設備為目標)中的 PhoneGap(也稱為 Apache Cordova)應用程序本機插件。如果您剛開始接觸 PhoneGap 或者需要回顧 PhoneGap 基礎知識,請先閱讀 Xcode for iOS 的 PhoneGap 入門,然後再繼續閱讀本文。
本文交替使用術語 Cordova 和 PhoneGap 指示同一開源應用程序平台,該平台可供您使用 HTML 和 JavaScript 創建本機安裝的移動應用程序。PhoneGap 代碼庫已遷移至 Apache 軟件基金會的開放資源中,名為 Cordova。Adobe 則仍以 PhoneGap 名稱進行分發。有關更多信息,請參閱 Brian Leroux 發布的博客文章“PhoneGap、Cordova、名稱有什麼關系?”正如 Brian 在這篇文章中所說,“目前唯一的區別在於下載包名稱的不同,並且這種情況仍將維持一段時間。
PhoneGap 不僅可讓您利用 Web 技術為本機安裝的移動應用程序構建用戶界面,還能提供基於 JavaScript 的 API 供您與本機設備功能進行交互。默認情況下,PhoneGap 可訪問設備攝像頭、加速計、文件系統、GPS 位置及其他功能間的媒體重放。但是,PhoneGap 並未揭示供您在 JavaScript 應用程序內使用的每一個本機 API。如果您希望 PhoneGap 執行其默認功能集以外的操作,可以使用 PhoneGap 本機插件模型擴展核心 PhoneGap API 的功能。
PhoneGap 本機插件與桌面浏覽器的插件不同;它們為您提供了一種插件自定義代碼以增加 PhoneGap 應用程序框架功能的方式。PhoneGap 本機插件可讓您以本機代碼的形式創建全新的自定義功能,並通過 PhoneGap 的本機-JavaScript 橋將其顯示給 PhoneGap 應用程序。這意味著,您可以顯示所有本機庫或框架,以便在基於 JavaScript 的 PhoneGap 應用程序內部使用。
在您開始編寫 PhoneGap 本機插件之前,了解 PhoneGap 應用程序容器如何向基於 JavaScript 的應用程序顯示本機操作系統功能將會有所幫助。
所有 Cordova API 均包含以下兩個有關部件:一個可以在您的應用程序內部進行訪問的基於 JavaScript 的界面,以及用於以本機代碼執行操作的對應本機類。通常情況下,JavaScript 類和本機類具有相互鏡像的 API,這樣就能輕松地進行跟蹤。JavaScript 類使用 Cordova.exec()
函數調用本機代碼。當它調用 Cordova.exec
時,可將其傳遞至結果處理程序函數和錯誤處理程序函數,同時還會將一組參數傳遞至本機代碼,並將引用傳遞至本機類名稱和本機函數名稱。Cordova
將負責管理 JavaScript 與本機之間的通信,您可以專心構建自己的應用程序。
要了解有關 PhoneGap 本機插件的更多信息,請登錄 Cordova wiki 查看該核心 API 的源代碼。整個 PhoneGap 框架均構建於同一模式之上,您可以在這裡了解這一模式。
要開始構建您的首個 PhoneGap 插件,您需要按照 Xcode for iOS 的 PhoneGap 入門一文中所述的步驟創建一個新 PhoneGap 項目。我將自己的項目命名為 MyFirstPhoneGapNativePlugin。
在您設置完 Hello Xcode 項目後,即可准備為本機插件創建 JavaScript 界面。您需要使用函數(將要鏡像通過本機代碼顯示的邏輯)創建類。在 www 文件夾下,創建一個名為 HelloPlugin.js 的 JavaScript 文件,其中包含如下所示的簡單 JavaScript 類。
var HelloPlugin = { callNativeFunction: function (success, fail, resultType) { return Cordova.exec( success, fail, "com.tricedesigns.HelloPlugin", "nativeFunction",
[resultType]); }};
HelloPlugin 類包含一個名為 callNativeFunction
的函數,它接收了一個成功回調函數、一個錯誤回調函數和一個 resultType
字符串參數。callNativeFunction
函數包含 Cordova.exec
函數,因而將會調用實際本機代碼。此類中沒有其他 JavaScript,但您可以根據自身需要在此處添加
JavaScript 代碼。
調用 Cordova.exec
後,將會看到以下五個參數:
請記住,JavaScript 和本機代碼層之間的代碼執行操作並不同步,因此,在開發 PhoneGap 本機插件時需要使用回調函數和異步編碼實踐。
要創建本機代碼層,請首先創建一個新的本機 Objective-C 類,它擴展核心 Cordova API 的 CDVPlugin 類:
CDVPlugin 類是所有 Cordova 類均必須擴展的父類。CDVPlugin 類通過 PhoneGAP API 封裝本機 JavaScript 通信所需的所有必要邏輯。PhoneGap.exec
函數可讓您調用該新類上的函數。CDVPlugin 類包含一個名為writeJavascript
的核心函數,可讓您調用 PhoneGap 應用程序 Web 視圖內的 JavaScript。本機到 Web JavaScript
這一方向的所有通信均必須使用 writeJavascript
函數完成。
您將會在 PhoneGap 項目內看到一個新的頭文件 (.h) 和一個新的實現文件 (.m)(參見圖 4)。
圖 4. 新的本機類文件。nativeFunction
函數添加定義;例如:
#import @interface HelloPlugin : CDVPlugin- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;@end
此定義包含以下兩個參數:一個是 NSMutableArray
,其中包含從 JavaScript 層和選項字典(地圖)接收到的參數。在本例中,您只需要關注參數數組。頭文件只包含方法簽名;您無需在 .h 文件中包含任何應用程序邏輯。
nativeFunction
函數實例中。您將在下面看到此本機插件類內部使用的 Objective-C 函數示例。
#import "HelloPlugin.h"@implementation HelloPlugin- (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { //get the
callback id NSString *callbackId = [arguments pop]; NSLog(@"Hello, this is a native function called from PhoneGap/Cordova!"); NSString *resultType = [arguments objectAtIndex:0]; CDVPluginResult *result; if ( [resultType isEqualToString:@"success"] ) { result
= [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"Success :)"]; [self writeJavascript:[result toSuccessCallbackString:callbackId]]; } else { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"Error
:("]; [self writeJavascript:[result toErrorCallbackString:callbackId]]; }}@end
在 nativeFunction
方法內部,您首先需要獲取一個 NSString callbackId
引用,核心 PhoneGap API 借此將此函數響應映射到調用此函數的原始 JavaScript。
接下來,此方法使用 NSLog
將消息寫入 Xcode 調試控制台;這只是表明它目前正在執行本機代碼。
寫入到調試控制台後,該函數將會檢查傳遞到該函數的 resultType
,然後創建相應的 CDVPluginResult
實例。resultType
值是一個簡單字符串。如果 resultType
是 success"
,則該函數將創建 success 結果,並使用 [self
writeJavascript]
函數將成功回調函數寫入 JavaScript 層。任何其他 resultType
參數值均將生成 error 結果,並且該函數會將錯誤回調寫入 JavaScript 層。
當您將成功或錯誤回調函數寫回 JavaScript 時,始終使用 CDVPluginResult 實例。但是,您也可以使用writeJavascript
函數將任意 JavaScript 字符串傳遞回 JavaScript 層。這項技術甚至還可用於將數據從本機層實時推送至 JavaScript 層。
鑒於您已經創建插件,因而可以從 PhoneGap 應用程序內部進行調用。
<script>
標記:
<script type="text/javascript" charset="utf-8" src="HelloPlugin.js"></script>
onDeviceReady()
函數後,添加 JavaScript 以調用本機插件及處理插件結果。添加名為callNativePlugin
、nativePluginResultHandler
和 nativePluginErrorHandler
的 JavaScript 函數,如下所示:
function callNativePlugin( returnSuccess ) { HelloPlugin.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess );} function
nativePluginResultHandler (result) { alert("SUCCESS: \r\n"+result );}function nativePluginErrorHandler (error) { alert("ERROR: \r\n"+error );}
callNativePlugin
函數只需調用 JavaScript 的本機插件類接口。當其調用 callNativeFunction
方法時,即會傳遞從本機代碼層接收到的成功和錯誤狀態回調函數。如果本機層成功返回回調函數,將會調用nativePluginResultHandler
函數,而當本機層傳回錯誤回調時,則調用nativePluginErrorHandler
函數。
Hey, it's Cordova!
單擊第一個按鈕將調用 callNativeFunction
方法,同時生成參數 "success"。PhoneGap 將於隨後執行本機代碼並在 JavaScript 層調用成功回調(它將會調用 nativePluginResultHandler
函數)。
當您單擊第二個按鈕時,將會調用 callNativeFunction
方法,同時生成參數 "error"。PhoneGap 將執行本機代碼並在 JavaScript 層調用錯誤回調(它將會調用 nativePluginErrorHandler
函數)。
此時,您幾乎已將所有事物串聯起來並可准備執行操作,但您還必須再完成一個步驟,才能調用 JavaScript 中的本機代碼。
您必須添加一個映射,以便 Cordova 識別您的本機代碼類。還記得在調用 Cordova.exec
時用來識別本機類的字符串引用嗎?您需要將該字符串映射到 Cordova.plist 文件中的實際類實例。Cordova.plist 文件包含當前 Cordova 項目的所有配置信息。
"HelloPlugin"
值的條目(參見圖 5),用貴公司的標識替換 com.tricedesigns
。當調用 Cordova.exec
時,您將利用此字符串引用識別第三個參數中的本機類。
key 是 PhoneGap.exec
映射至本機代碼類所使用的唯一一個字符串引用。value是將要調用的實際本機類名稱。
現在,您可以啟動該應用程序並進行徹底檢查。
要啟動該應用程序,請單擊 Run 按鈕或選擇 Product > Run。
在 iOS Simulator 中(或連接設備上)啟動該應用程序後,您將會看到帶有兩個按鈕的簡單界面(參見圖 6)。單擊任一按鈕調用本機插件的本機代碼,無論調用成功回調還是錯誤回調,都會通過 JavaScript 顯示一條警告消息。
圖 6. iOS 模擬器中運行的應用程序。
當調用本機代碼時,您還能夠在 Xcode 調試控制台窗口中看到輸出內容,反映調用本機插件 NSLog
生成的輸出內容(參見圖 7)。