iOS 插件開發指南

本節提供如何在 iOS 平台上實作原生插件程式碼的詳細資訊。

在閱讀本節之前,請參閱插件開發指南,以了解插件的結構及其常見的 JavaScript 介面。本節將繼續示範範例 echo 插件,該插件會從 Cordova 的 webview 與原生平台之間進行通訊。

iOS 插件會實作成一個繼承自 CDVPlugin 類別的 Objective-C 類別。為了讓 JavaScript 的 exec 方法的 service 參數對應到一個 Objective-C 類別,每個插件類別都必須在指定的應用程式目錄的 config.xml 檔案中註冊為 <feature> 標籤。

插件類別對應

插件的 JavaScript 部分會使用 cordova.exec 方法,如下所示

exec(<successFunction>, <failFunction>, <service>, <action>, [<args>]);

這會將請求從 UIWebView 傳送到 iOS 原生端,有效地呼叫 service 類別的 action 方法,並將引數傳遞到 args 陣列中。

使用 plugin.xml 檔案自動注入此標記,在您的 Cordova-iOS 應用程式專案的 config.xml 檔案中,將插件指定為 <feature> 標籤,如插件開發指南中所述

<feature name="LocalStorage">
    <param name="ios-package" value="CDVLocalStorage" />
</feature>

功能的 name 屬性應與您指定為 JavaScript exec 呼叫的 service 參數的內容相符。value 屬性應與插件的 Objective-C 類別的名稱相符。<param> 元素的 name 應始終為 ios-package。如果您未遵循這些準則,插件可能會編譯,但 Cordova 仍然可能無法存取它。

插件初始化與生命週期

在每個 UIWebView 的生命週期中,都會建立一個插件物件的實例。除非在 config.xml 中將具有 onload name 屬性的 <param> 設定為 "true",否則直到 JavaScript 第一次呼叫參考它們時,才會實例化插件。例如,

<feature name="Echo">
    <param name="ios-package" value="Echo" />
    <param name="onload" value="true" />
</feature>

插件應使用 pluginInitialize 方法進行啟動邏輯。

具有長時間執行請求或背景活動(例如媒體播放、監聽器或維護內部狀態)的插件應實作 onReset 方法,以取消這些長時間執行的請求或在這些活動後進行清理。當 UIWebView 導覽至新頁面或重新整理時,會執行此方法,這會重新載入 JavaScript。

撰寫 iOS Cordova 插件

JavaScript 呼叫會向原生端觸發插件請求,而對應的 iOS Objective-C 插件會在 config.xml 檔案中正確對應,但是最終的 iOS Objective-C 插件類別看起來如何?使用 JavaScript 的 exec 函式派送到插件的任何內容,都會傳遞到對應的插件類別的 action 方法中。插件方法具有此簽章

- (void)myMethod:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult = nil;
    NSString* myarg = [command.arguments objectAtIndex:0];

    if (myarg != nil) {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    } else {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was null"];
    }
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

如需更多詳細資訊,請參閱CDVInvokedUrlCommand.hCDVPluginResult.hCDVCommandDelegate.h

iOS CDVPluginResult 訊息類型

您可以使用 CDVPluginResult 將各種結果類型傳回 JavaScript 回呼,並使用遵循此模式的類別方法

+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAs...

您可以建立 StringIntDoubleBoolArrayDictionaryArrayBufferMultipart 類型。您也可以省略任何引數來傳送狀態、傳回錯誤,甚至選擇不傳送任何插件結果,在這種情況下,也不會觸發任何回呼。

請注意以下複雜的傳回值

  • messageAsArrayBuffer 預期 NSData*,並在 JavaScript 回呼中轉換為 ArrayBuffer。同樣地,JavaScript 傳送到插件的任何 ArrayBuffer 都會轉換為 NSData*

  • messageAsMultipart 預期 NSArray* 包含任何其他支援的類型,並將整個陣列作為 arguments 傳送到您的 JavaScript 回呼。這樣,所有引數都會視需要序列化或還原序列化,因此將 NSData* 作為 multipart 傳回是安全的,但不作為 Array/Dictionary 傳回。

Echo iOS 插件範例

若要比對應用程式插件中描述的 JavaScript 介面 echo 功能,請使用 plugin.xmlfeature 規格注入到本機平台的 config.xml 檔案中

<platform name="ios">
    <config-file target="config.xml" parent="/*">
        <feature name="Echo">
            <param name="ios-package" value="Echo" />
        </feature>
    </config-file>
</platform>

然後,我們會將下列 Echo.hEcho.m 檔案新增至 Cordova-iOS 應用程式目錄中的 Plugins 資料夾

/********* Echo.h Cordova Plugin Header *******/

#import <Cordova/CDVPlugin.h>

@interface Echo : CDVPlugin

- (void)echo:(CDVInvokedUrlCommand*)command;

@end

/********* Echo.m Cordova Plugin Implementation *******/

#import "Echo.h"
#import <Cordova/CDVPlugin.h>

@implementation Echo

- (void)echo:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult = nil;
    NSString* echo = [command.arguments objectAtIndex:0];

    if (echo != nil && [echo length] > 0) {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo];
    } else {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
    }

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

@end

檔案頂端的必要匯入會從 CDVPlugin 擴充類別。在本例中,插件僅支援單一 echo 動作。它會藉由呼叫 objectAtIndex 方法,取得 arguments 陣列的第一個參數來取得 echo 字串,這對應於 JavaScript exec() 函式傳遞的引數。

它會檢查參數以確保它不是 nil 或空字串,如果是,則傳回具有 ERROR 狀態的 PluginResult。如果參數通過檢查,則會傳回具有 OK 狀態的 PluginResult,並傳入原始的 echo 字串。最後,它會將結果傳送到 self.commandDelegate,這會在 JavaScript 端執行 exec 方法的成功或失敗回呼。如果呼叫成功回呼,則會傳入 echo 參數。

iOS 整合

CDVPlugin 類別具有您的插件可以覆寫的其他方法。例如,您可以擷取 暫停繼續、應用程式終止和 handleOpenURL 事件。請參閱 CDVPlugin.hCDVPlugin.m 類別以取得指引。

WKURLSchemeTask 鉤子

WKURLSchemeTask 是 Cordova 的主要 WKWebView 用於從您的應用程式套件載入檔案的介面。您可以藉由在插件中實作 - (BOOL) overrideSchemeTask: (id <WKURLSchemeTask>)urlSchemeTask 方法,為 webview 建立自己的自訂配置或自訂載入程式碼。

執行緒

插件方法通常會在與主介面相同的執行緒中執行。如果您的插件需要大量的處理或需要封鎖呼叫,您應該使用背景執行緒。例如

- (void)myPluginMethod:(CDVInvokedUrlCommand*)command
{
    // Check command.arguments here.
    [self.commandDelegate runInBackground:^{
        NSString* payload = nil;
        // Some blocking logic...
        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
        // The sendPluginResult method is thread-safe.
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }];
}

偵錯 iOS 插件

若要在 Objective-C 端偵錯,您需要 Xcode 的內建偵錯工具。對於 JavaScript,您可以將 Safari 連接到 iOS 模擬器/裝置中執行的應用程式。

常見陷阱

  • 別忘了將插件的對應新增至 config.xml。如果您忘記,則會在 Xcode 主控台中記錄錯誤。

  • 別忘了在允許清單中新增您連線的任何主機,如網域允許清單指南中所述。如果您忘記,則會在 Xcode 主控台中記錄錯誤。