iOSプラグイン開発ガイド

このセクションでは、iOSプラットフォームでネイティブプラグインコードを実装する方法の詳細について説明します。

これを読む前に、プラグインの構造とその共通のJavaScriptインターフェースの概要については、プラグイン開発ガイドを参照してください。このセクションでは、Cordovaウェブビューとネイティブプラットフォーム間で通信するサンプルのechoプラグインをさらに説明します。

iOSプラグインは、CDVPluginクラスを拡張するObjective-Cクラスとして実装されます。JavaScriptのexecメソッドのserviceパラメーターをObjective-Cクラスにマップするには、各プラグインクラスを名前付きアプリケーションディレクトリのconfig.xmlファイルで<feature>タグとして登録する必要があります。

プラグインクラスのマッピング

プラグインのJavaScript部分は、次のようにcordova.execメソッドを使用します。

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

これは、UIWebViewからiOSネイティブ側へのリクエストをマーシャリングし、args配列に渡された引数を使用して、serviceクラスのactionメソッドを効果的に呼び出します。

プラグイン開発ガイドで説明されているように、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のライフタイムに対して、プラグインオブジェクトのインスタンスが1つ作成されます。config.xmlonloadname属性が"true"に設定されている場合を除き、プラグインはJavaScriptからの呼び出しによって初めて参照されるまでインスタンス化されません。例:

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

プラグインは、起動ロジックにpluginInitializeメソッドを使用する必要があります。

メディア再生、リスナー、内部状態を維持するなど、長時間実行されるリクエストやバックグラウンドアクティビティを持つプラグインは、それらの長時間実行されるリクエストをキャンセルしたり、それらのアクティビティの後片付けを行うために、onResetメソッドを実装する必要があります。このメソッドは、JavaScriptを再読み込みするUIWebViewが新しいページに移動したり、更新したりするときに実行されます。

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.h、およびCDVCommandDelegate.hを参照してください。

iOS CDVPluginResultメッセージタイプ

このパターンに従うクラスメソッドを使用して、さまざまな結果タイプをJavaScriptコールバックに戻すためにCDVPluginResultを使用できます。

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

StringIntDoubleBoolArrayDictionaryArrayBuffer、およびMultipartタイプを作成できます。ステータスを送信したり、エラーを返したり、プラグインの結果を送信しないように選択することもできます。その場合、どちらのコールバックも実行されません。

複雑な戻り値については、次の点に注意してください。

  • messageAsArrayBufferNSData*を期待し、JavaScriptコールバックでArrayBufferに変換します。同様に、JavaScriptがプラグインに送信するArrayBufferNSData*に変換されます。

  • messageAsMultipartは、他のサポートされているタイプのいずれかを含むNSArray*を期待し、配列全体をJavaScriptコールバックへのargumentsとして送信します。このようにして、すべての引数は必要に応じてシリアル化またはデシリアル化されるため、Array/Dictionaryとしてではなく、NSData*をマルチパートとして返すことができます。

Echo iOSプラグインの例

アプリケーションプラグインで説明されているJavaScriptインターフェースのecho機能と一致させるには、plugin.xmlを使用して、ローカルプラットフォームのconfig.xmlファイルにfeature仕様を挿入します。

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

次に、Cordova-iOSアプリケーションディレクトリのPluginsフォルダに次のEcho.hファイルとEcho.mファイルを追加します。

/********* 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配列の最初のパラメーターを取得することで、エコー文字列を取得します。これは、JavaScriptのexec()関数によって渡された引数に対応します。

パラメーターがnilまたは空文字列ではないことを確認し、その場合、ERRORステータスを持つPluginResultを返します。パラメーターがチェックを通過した場合、元のecho文字列を渡して、OKステータスのPluginResultを返します。最後に、結果をself.commandDelegateに送信します。これにより、JavaScript側のexecメソッドの成功または失敗のコールバックが実行されます。成功コールバックが呼び出されると、echoパラメーターが渡されます。

iOS統合

CDVPluginクラスには、プラグインでオーバーライドできる他のメソッドがあります。たとえば、pauseresume、アプリの終了、およびhandleOpenURLイベントをキャプチャできます。CDVPlugin.hCDVPlugin.mクラスを参照してください。

WKURLSchemeTaskフック

WKURLSchemeTaskは、CordovaのメインWKWebViewがアプリバンドルからファイルを読み込むために使用するインターフェースです。プラグインで- (BOOL) overrideSchemeTask: (id <WKURLSchemeTask>)urlSchemeTaskメソッドを実装することで、独自の カスタムスキームまたはウェブビューのカスタム読み込みコードを作成できます。

スレッド

プラグインメソッドは通常、メインインターフェースと同じスレッドで実行されます。プラグインに大量の処理が必要な場合、またはブロッキングコールが必要な場合は、バックグラウンドスレッドを使用する必要があります。例:

- (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コンソールにエラーが記録されます。