Developing a Plugin on iOS

プラグインは CDVPlugin クラスを継承した Objective-C のクラスです。

各プラグインクラスは Cordova.plist ファイルの Plugins キーを使用し登録されている必要があります。

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

プラグインの JavaScript 部分は常に cordova.exec メソッドを以下のように使います:

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

これは UIWebView から iOS ネイティブ側へのリクエストを整理し、おおよそ要約すると service クラスで action メソッドを、 args 配列で渡された引数と一緒に呼び出すということになります。

実行に時間がかかったり、バックグラウンドで動く (例: media の再生) もの、リスナーや内部状態を持つプラグインは onReset() メソッドが実装され、これらの動作を停止またはリセットすべきです。このメソッドは UIWebView が新しいページに遷移、もしくはリフレッシュした時、つまり JavaScript がリロードされた時に実行されます。

このプラグインは、 Cordova-iOS アプリケーションのプロジェクトフォルダーの中の Cordova.plist ファイルの Plugins キー (辞書) に追加される必要があります。

<key>service_name</key>
<string>PluginClassName</string>

service_name のキーは JavaScript の exec の中で使用しているものと一致している必要があり、値はプラグインの Objective-C クラスの名前になります。これがないと、プラグインはコンパイルされますが、 Cordova からアクセスできない状態となります。

iOS Cordova Plugin の作成

私たちはプラグインリクエストをネイティブ側に送る JavaScript を作成しました。また、正しく Cordova.plist ファイルでマッピングされた iOS Objective-C プラグインもあります。では、最終的に 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];
}
  1. CDVInvokedUrlCommand.h
  2. CDVPluginResult.h

プラグインシグネチャ

Cordova 2.1.0 からサポートされた 新しいシグネチャ は次のとおりです:

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

古い (非推奨) シグネチャはつぎのとおりです:

    - (void)myMethod:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

基本的に、オプション辞書は新しいシグネチャでは削除されており、 callbackId は引数配列の 0 番目の要素ではなく、別のプロパティーとなっています。

iOS プラグインの Echo プラグイン

Cordova.plist ファイルの Plugins キー (辞書) に以下を追加します:

<key>Echo</key>
<string>Echo</string>

次のファイル (Echo.hEcho.m) を Cordova-iOS アプリケーションフォルダーの中の プラグインフォルダーに追加します:

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

#import <Cordova/CDV.h>

@interface Echo : CDVPlugin

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

@end

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

#import "Echo.h"
#import <Cordova/CDV.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

コードを見ていきましょう。一番上には、必要なすべての Cordova に関する import 文が並んでいます。クラスは CDVPlugin を継承しています - これはとても重要です。

このプラグインは 1 つのアクション echo のみをサポートしています。最初に、 objectAtIndex メソッドを args に使って引数配列 0 番目の要素である echo 用文字列を取得します。次に、 objectAtIndex メソッドを使って、引数配列の1番目の要素である echo 用文字列を取得します。ここで、少しパラメーターに対してチェックを行います: nil チェックや文字列の長さが0でないかどうかなどです。

もしそうであった場合は、ステータスが ERRORPluginResult を返します。もしこれらのチェックをパスしたら、ステータスが OKPluginResult を返し、パラメーターとして受け取った echo 文字列を渡します。

最後に、 self.commandDelegate に結果を返します。これは、 JavaScript 側で成功またはエラーコールバック関数を実行するような JavaScript を実行します。もし成功コールバックが呼ばれた場合は、 echo パラメーターをパラメーターとして渡します。

スレッド

たとえ UIWebView が dedicated thread 上で実行されるとしても、プラグインメソッドは UI スレッドで実行されます。もしプラグインが尋常じゃない数のプロセスが必要、または処理をブロックする必要がある場合は、バックグラウンドスレッドを使用するべきです。使用例は次のとおりです:

- (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];
    }];
}

一歩進んだプラグインの機能

他にも、オーバーライド出来るメソッドについては以下を参照してください:

  1. CDVPlugin.h
  2. CDVPlugin.m

例えば、 pausa, resume, app terminate, handleOpenURL events といったような機能を実装できます。

プラグインのデバッグ

Objective-C 側でデバッグするには、 Xcode のビルトインのデバッガーを使用します。 JavaScript 側では、 iOS 5.0 では Apache Cordova Project の Weinre または サードパーティ製の iWebInspector を使用できます。

iOS 6 では、 Safari 6.0 を使用して簡単に iOS 6 シミュレーター上で動いているアプリをデバッグできます。

よくある落とし穴

  • Cordova.plist にプラグインマッピングを追加することを忘れないでください - もし忘れている場合は、 Xcode のコンソールログにエラーが表示されます
  • 接続するすべてのホストを ホワイトリスト に追加することを忘れないで下さい - もし忘れている場合は、 Xcode のコンソールログにエラーが表示されます

非推奨のプラグインシグネチャに関する注意点

古い (非推奨) シグネチャはつぎのとおりです:

    - (void) myMethod:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

Objective-C プラグインメソッドの options パラメーターは非推奨であり、使われるべきではありません。レガシー的な理由で、 args 配列の最後の JavaScript オブジェクト要素は、 Objective-C 側メソッドの options 辞書に渡されます。どんな JavaScript オブジェクトでも args 配列の最後の要素として渡されるべきであり、もし配列の途中の要素に JavaScript オブジェクトがあると、それ以降の Objective-C 側の配列のインデックスがでたらめになることに十分注意してください。 options 辞書はただ1つの JavaScript オブジェクトのみをサポートしており、また配列の一番最後の要素のみネイティブメソッドに渡されます。このようにエラーを起こしやすいので、 options は非推奨となっています。