話題の記事

[iOS 7] JavaScriptCore Framework を使った Objective-C と JavaScript の連携ができるようになった

2013.09.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

iOS 7 / Mac OS X 10.9 から Objective-C から JavaScript の相互連携ができるようになりました。どんな感じで連携ができるのでしょうか。

サンプルコード

Objective-C から JavaScript の式

[C] // コンテキストを作成 JSContext *context = [[JSContext alloc] init]; // 計算 JSValue *result = [context evaluateScript:@"1 + 2;"]; // 結果 NSLog(@"1 + 2 = %d", [result toInt32]); [/C]

JSContextクラスからJavaScriptを実行する場所としてのインスタンスを作成し、- (JSValue *)evaluateScript:(NSString *)script;メソッドで式を評価させるのが基本パターンの模様。- (int32_t)toInt32;メソッドでObjective−Cの世界の型に変換しています。他にも- (NSDate *)toDate;など各種取り揃えられています。

Objective-C から JavaScript のファンクション

[C] // コンテキストを作成 JSContext *context = [[JSContext alloc] init]; // JavaScriptを評価 [context evaluateScript:@"function multiply(a, b){return a*b;}"]; // multiply ファンクションをObjCのオブジェクト化 JSValue *multiply = context[@"multiply"]; // multiply用に引数を定義 NSArray *args = @[[NSNumber numberWithInt:2],[NSNumber numberWithInt:3]]; // multiply ファンクションを引数付きで呼び出し(引数無しの場合は callWithArguments の引数を nil に) JSValue *result = [multiply callWithArguments:args]; // 結果 NSLog(@"2 * 3 = %d", [result toInt32]); [/C]

ファンクションを呼び出す時は一旦JavaScriptを評価した後、対象のJavaScriptファンクションをJSValueのインスタンスとします。そのインスタンスに対して- (JSValue *)callWithArguments:(NSArray *)arguments;でファンクションを呼び出します。

JavaScript から Objective-C のブロック構文

[C] // コンテキストを作成 JSContext *context = [[JSContext alloc] init]; // Block 構文 を定義して コンテキストに設定 context[@"multiply"] = ^(int a,int b) { return a * b; }; NSString * jsCode = @"multiply(2,4);"; // multiply ファンクションを呼び出し JSValue * result = [context evaluateScript:jsCode]; // 結果 NSLog(@"2 * 4 = %d", [result toInt32]); [/C]

逆に JavaScript から Objective−C のコードを呼び出すパターンです。JavaScript を実行するためのコンテキストを作るのは今までと一緒。ブロック構文を定義して JavaScript の世界の multiplyオブジェクト に設定しています。ここで JavaScript と Objective−C の世界での謎の融合がされているのでしょうか。そして multiply を JavaScript のように呼び出すと実は Objective−C のブロック構文が呼び出される、という仕組みのようです。

まとめ

2つの世界が簡単に行き来できるようになっています。使い道としては同じサービスでWeb版とネイティブアプリ版がある場合ロジックを共通化させたいとか、表示ロジックを JavaScript にしてダウンロードさせてA/Bテストするとか、ですかね。思いつくマイナス要素としてデバッグや、エラー処理、混在する言語でカオスる等考えられます。
何かもっと面白い使い方があるかもしれない、という可能性を感じる(けど思いつかない)、そんな機能でした。

参考

https://developer.apple.com/library/mac/documentation/Carbon/Reference/WebKit_JavaScriptCore_Ref/_index.html

http://hayageek.com/execute-javascript-in-ios/