iOS JavaScriptブリッジ


101

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

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

1
javascript window.webkit.messageHandlers。{NAME} .postMessage(message)からWKWebView:呼び出しを使用し、それを[WKUserContentController addScriptMessageHandler:name:]で処理して、JSからObjective-Cを呼び出すことができます
kostyl

回答:


150

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

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

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

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

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

公式のUIWebViewドキュメントの詳細。

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

残念ながら、Mac OSXには同じ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対応イベント)をリッスンします

上記の説明から、そうしたい場合は、JavaScriptコードを作成し、それを監視するイベントに添付して、正しいwindow.locationコールをインターセプトする必要があることがわかります。

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


12
ヒント:スキームにアンダースコアなどを入れないでください。
FABB

4
そして、あなたがすることになっているときに値を返します:)
Pizzaiola Gorgonzola

2
別のヒント:ちらつきを防ぐためにURLをiFrameにロードします
iCaramba

@Folletoこんにちは、「しかし、私はこれらを大きなプロジェクトで使用しなかった」と言いました、なぜでしょうか?これらのライブラリでいくつかの問題を見つけましたか??? 前もって感謝します。
JERC、2015年

1
問題ない。私は単にそれらを使用しなかったので、大規模なプロジェクトでの使用についてコメントすることはできません。それを明確にしたかったのです。:)
Folletto、

57

受け入れられた回答でJSから目的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で実行されるため、すばやく呼び出されても無視されません。

この男のクレジット。


1
また、JavaScriptでiOSが取得できるキューを使用して、.srcからのメッセージの変更が速すぎないようにすることもできます。上記でリンクされている実装github.com/marcuswestin/WebViewJavascriptBridgeは、キューアプローチを使用しています。
kevintcoughlin 14年

12

更新:これは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();

アプリがアプリストアで拒否されました。私が受け取った問題は、「アプリがAppNameの非パブリッククラスを含むか、またはそこから継承する:UIWebDocumentView」
chandru

5

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


もちろん、メソッドはcontinuoulsyを実行していません。これは、appleが提供するフレームワークのバグです
Josh Kethepalli

WKWebViewCookieを適切に処理しないなど、多くの問題があります。ここに来た人はすべての問題を解決できると思っている人への警告です-採用する前に少しググってください。
CupawnTae 2016年

3

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


3
実際には、JavaScriptCoreはUIWebViewsと相互作用しません。これは優れたツールですが、さまざまな種類の問題に対応できます。;)
Folletto、2014年

1
はい、そうです:JSContext * context = [_webView valueForKeyPath:@ "documentView.webView.mainFrame.javaScriptContext"]; しかし、JavaScriptCoreは現時点ではバグが多く、実際に使用することはできません。
マルハル2014

0

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


@hova、これはObj-C V8ブリッジではありません。V8はAndroidでのみ利用されます。
ロス

0

:KirinJSプロジェクトを見ていキリンJSそれは上で動作するアプリケーション・ロジックおよびプラットフォームへの適切なネイティブUIのためにJavascriptを使用することができます。


誰かがまだキリンに貢献していますか?過去数か月、何のアクティビティも見当たりません...
サム

0

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


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.