web-dev-qa-db-ja.com

iOS JavaScriptブリッジ

UIWebViewのHTML5とネイティブiOSフレームワークの両方を一緒に使用するアプリに取り組んでいます。 JavaScriptとObjective-C間の通信を実装できることを知っています。この通信の実装を簡素化するライブラリはありますか? HTML5とjavascript(たとえば、AppMobi、PhoneGap)でネイティブiOSアプリを作成するためのライブラリがいくつかあることは知っていますが、JavaScriptの使用量が多いネイティブiOSアプリの作成に役立つライブラリがあるかどうかはわかりません。する必要がある:

  1. Objective-CからJSメソッドを実行する
  2. JSからObjective-Cメソッドを実行する
  3. Objective-CからのネイティブJSイベント(たとえば、DOM readyイベント)をリッスンします
99
andr111

いくつかのライブラリがありますが、大きなプロジェクトではこれらのライブラリを使用していませんので、試してみてください。

ただし、自分で試してみるのは簡単だと思います。私はそれをする必要があるときに、まさにこれを個人的にやった。また、ニーズに合ったシンプルなライブラリを作成することもできます。

1. Objective-CからJSメソッドを実行する

これは実際には1行のコードです。

NSString *returnvalue = [webView stringByEvaluatingJavaScriptFromString:@"your javascript code string here"];

公式の詳細 IWebView Documentation

2. JSからObjective-Cメソッドを実行する

残念ながら、Mac OSXには同じ2つのwindowScriptObjectプロパティ(およびクラス)が存在しないため、これら2つの間の完全な通信が可能であるため、これは少し複雑です。

ただし、次のようなJavaScriptカスタムメイドURLから簡単に呼び出すことができます。

window.location = yourscheme://callfunction/parameter1/parameter2?parameter3=value

そして、これをObjective-Cからインターセプトします:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
   NSURL *URL = [request URL]; 
   if ([[URL scheme] isEqualToString:@"yourscheme"]) {
       // parse the rest of the URL object and execute functions
   } 
}

これは本来あるべきほどきれいではありません(またはwindowScriptObjectを使用して)が、動作します。

3. Objective-CからのネイティブJSイベント(たとえば、DOM readyイベント)をリッスンします

上記の説明から、それを行うには、JavaScriptコードを作成し、監視するイベントにアタッチし、正しいwindow.location呼び出しを呼び出してインターセプトする必要があることがわかります。

繰り返しますが、本来あるべき状態ではきれいではありませんが、動作します。

149
Folletto

受け入れられた回答でJSからObjective Cを呼び出す推奨方法は推奨されません。問題の1つの例:すぐに2つの連続した呼び出しを行う場合、1つは無視されます(位置をあまり速く変更することはできません)。

次の代替アプローチをお勧めします。

function execute(url) 
{
  var iframe = document.createElement("IFRAME");
  iframe.setAttribute("src", url);
  document.documentElement.appendChild(iframe);
  iframe.parentNode.removeChild(iframe);
  iframe = null;
}

execute関数を繰り返し呼び出します。各呼び出しは独自のiframeで実行されるため、すぐに呼び出される場合は無視しないでください。

this guy へのクレジット。

57
talkol

更新:これはiOS 8で変更されました。私の答えは以前のバージョンに適用されます。

別の方法として、アプリストアから拒否される可能性がある場合は、WebScriptObjectを使用します。

これらのAPIはOSXで公開されていますが、iOSでは公開されていません。

内部クラスへのインターフェースを定義する必要があります。

@interface WebScriptObject: NSObject
@end

@interface WebView
- (WebScriptObject *)windowScriptObject;
@end

@interface UIWebDocumentView: UIView
- (WebView *)webView;
@end

WebScriptObjectとして機能するオブジェクトを定義する必要があります

@interface WebScriptBridge: NSObject
- (void)someEvent: (uint64_t)foo :(NSString *)bar;
- (void)testfoo;
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
+ (WebScriptBridge*)getWebScriptBridge;
@end

static WebScriptBridge *gWebScriptBridge = nil;

@implementation WebScriptBridge
- (void)someEvent: (uint64_t)foo :(NSString *)bar
{
    NSLog(bar);
}

-(void)testfoo {
    NSLog(@"testfoo!");
}

+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
{
    return NO;
}

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
{
    return NO;
}

+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    // Naming rules can be found at: https://developer.Apple.com/library/mac/documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/Reference/Reference.html
    if (sel == @selector(testfoo)) return @"testfoo";
    if (sel == @selector(someEvent::)) return @"someEvent";

    return nil;
}
+ (WebScriptBridge*)getWebScriptBridge {
    if (gWebScriptBridge == nil)
        gWebScriptBridge = [WebScriptBridge new];

    return gWebScriptBridge;
}
@end

インスタンスをUIWebViewに設定します

if ([uiWebView.subviews count] > 0) {
    UIView *scrollView = uiWebView.subviews[0];

    for (UIView *childView in scrollView.subviews) {
        if ([childView isKindOfClass:[UIWebDocumentView class]]) {
            UIWebDocumentView *documentView = (UIWebDocumentView *)childView;
            WebScriptObject *wso = documentView.webView.windowScriptObject;

            [wso setValue:[WebScriptBridge getWebScriptBridge] forKey:@"yourBridge"];
        }
    }
}

これで、javascriptの内部で次を呼び出すことができます。

yourBridge.someEvent(100, "hello");
yourBridge.testfoo();
12
Joseph Lennox

iOS8では、UIWebViewの代わりにWKWebViewを見ることができます 。これには次のクラスがあります。WKScriptMessageHandler:Webページで実行されているJavaScriptからメッセージを受信するためのメソッドを提供します。

5
Alex Stone

これはiOS7、チェックアウトで可能です http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/

3
CocoaChris

KirinJSプロジェクトをご覧ください。 Kirin JS これにより、実行するプラットフォームに適したアプリケーションロジックとネイティブUIにJavascriptを使用できます。

0
rochal

IOS 8でWKWebViewを使用している場合、ネイティブインターフェイスをjavascriptに自動的に公開できる XWebView を見てください。

0
soflare

WebViewJavascriptBridgeのようなライブラリを作成しましたが、JQueryに似ており、セットアップが簡単で使いやすいです。 jQueryに依存していません(その功績はありますが、これを書く前にWebViewJavascriptBridgeが存在することを知っていたので、飛び込む前に少し抑えたかもしれません)。どう考えているか教えてください! jockeyjs

0
Tim Coulter

あなたの最善の策は、Appcelerators Titanium製品です。彼らはすでにObj-C javascriptブリッジを構築しています V8エンジン Webkitで使用されるJavascriptCoreエンジン。また、オープンソースなので、ダウンロードして、Obj-Cを好きなように変更することができます。

0
hova