Ios

JSとOCはiOS(5)で相互に呼び出します--UIWebView + WebViewJavascriptBridge



Js Oc Call Each Other Under Ios Uiwebview Webviewjavascriptbridge



WebViewJavascriptBridge これは、数年後のJSとOCの相互作用のライブラリです。このライブラリを使用している有名なアプリケーションはかなりたくさんあります。現在、このライブラリには7000以上の星があります。私は4年前にそれの最初のバージョンを見に行きました。バージョンV4.1.4より前以前は、ライブラリには1つのクラスと1つのjs txtファイルしかなかったため、古いバージョンWebViewJavascriptBridgeとてもわかりやすいです。また、最新バージョンWebViewJavascriptBridge WKWebViewとも互換性があるため、2つの新しいクラスも追加されています。あなたが最初にそれを見るとき、それはその中の複雑な論理によって怖がるでしょう。実際、それを注意深く読んだ後でも、それはまだ非常に単純です。

WebViewJavascriptBridge使用の説明

WebViewJavascriptBridgeはUIWebViewとWKWebViewでわずかに異なるため、WebViewJavascriptBridgeを説明するために2つの記事に分かれています。この記事では、UIWebView WebViewJavascriptBridgeを使用してJSとOCを呼び出す目的を達成する方法について説明します。WKWebView使用済みWKWebViewJavascriptBridge。次に、WebViewJavascriptBridgeを最初から作成します。



最初の効果チャート:

最初のステップは、プロジェクトをビルドし、WebViewJavascriptBridgeライブラリをプロジェクトに追加することです。

新しいプロジェクトを作成する手順はスキップされます。 WebViewJavascriptBridgeのgithubアドレスは次のとおりです。 WebViewJavascriptBridge バージョンV5.0.5を使用しています。



現在、私のデモのWebViewJavascriptBridgeライブラリは最新のiOSシステムでクラッシュしました。このサードパーティライブラリを使用する場合は、最新バージョンに更新する必要があります。

2番目のステップは、UIWebViewとWebViewJavascriptBridgeの例を作成することです。

2.1UIWebViewの作成

UIWebViewコードを作成します(viewDidLoadでチェックイン):

self.webView = [[UIWebView alloc] initWithFrame:self.view.frame] [self.view addSubview:self.webView] NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@'index.html' withExtension:nil] NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL] // UIWebView scrolls slowly, set to normal speed here self.webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal [self.webView loadRequest:request] Copy code

ここではUIWebViewのプロキシを設定しないでください。これは、WebViewJavascriptBridgeの作成時にUIWebViewプロキシがWebViewJavascriptBridgeに割り当てられているためです。



2.2WebViewJavascriptBridgeの作成

WebViewJavascriptBridgeインスタンスはコントローラーの複数の場所で使用されるため、格納するプロパティまたはインスタンス変数を定義するのが最適です。

_webViewBridge = [WebViewJavascriptBridge bridgeForWebView:self.webView] // {setWebViewDelegate} This method can pass the UIWebView proxy from _webViewBridge. // So if you want to implement the UIWebView proxy method in the controller, add the following code, otherwise you can not write. [_webViewBridge setWebViewDelegate:self] Copy code

次に、{- bridgeForWebView }メソッドを追跡し、実際にどのように実装されているかを確認します。

+ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView { WebViewJavascriptBridge* bridge = [[self alloc] init] [bridge _platformSpecificSetup:webView] return bridge } // The above method calls this method - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { _webView = webView _webView.delegate = self _base = [[WebViewJavascriptBridgeBase alloc] init] _base.delegate = self } Copy code

実際{-bridgeForWebView }内部的には、WebViewJavascriptBridgeオブジェクトを初期化し、そのインスタンス変数_webViewと_baseに値を割り当てるだけです。

3番目のステップは、jsによって呼び出されるネイティブ関数を登録することです。

最初にサンプルコードを取得し、関数を分析します。

#pragma mark - private method - (void)registerNativeFunctions { [self registScanFunction] [self registShareFunction] [self registLocationFunction] [self regitstBGColorFunction] [self registPayFunction] [self registShakeFunction] } - (void)registShareFunction { // All native functions that JS needs to call must be registered with registerHandler first. [_webViewBridge registerHandler:@'shareClick' handler:^(id data, WVJBResponseCallback responseCallback) { // The type of data is related to the parameters passed in JS NSDictionary *tempDic = data // Perform the shared operation here NSString *title = [tempDic objectForKey:@'title'] NSString *content = [tempDic objectForKey:@'content'] NSString *url = [tempDic objectForKey:@'url'] // return the shared results to JS NSString *result = [NSString stringWithFormat:@'Sharing success: %@,%@,%@',title,content,url] responseCallback(result) }] } Copy code

- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handlerこのメソッドには2つのパラメーターがあります。最初のパラメーターhandlerNameはこの関数のエイリアスであり、2番目のパラメーターハンドラーはブロックであり、Nativeによって実装される関数です。 JSが呼び出したいネイティブ実装は、実際にはブロックです。{}内部のコード関数。メンテナンスのために、JSが呼び出すネイティブメソッドをまとめて、単一の関数でメソッドをカプセル化することができます。

4番目のステップは、HMTLに必要なJSコードを完成させることです。

WebViewJavascriptBridgeもURLをインターセプトするネイティブ関数であるため、以前にいくつかのコードがあります JSとOCはiOSでお互いに電話をかけます(1) その中のHTMLJSコードは非常に似ています。

HTMLにはJSメソッドを追加する必要があり、そのメソッドを1回自動的に呼び出す必要があります。方法は次のとおりです。

function setupWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge) } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback) } window.WVJBCallbacks = [callback] var WVJBIframe = document.createElement('iframe') WVJBIframe.style.display = 'none' WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__' document.documentElement.appendChild(WVJBIframe) setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0) } Copy code

上記のメソッドのパラメータは関数です。このメソッドの機能は、主にHTMLが初めてロードされたときに機能することです。目的は、一度ロードすることです。wvjbscheme://__BRIDGE_LOADED__すでに記述されているJSメソッドのHTMLへの挿入をトリガーします。上記の方法を見てください。次のようになります。

function loadURL(url) { var iFrame iFrame = document.createElement('iframe') iFrame.setAttribute('src', url) iFrame.setAttribute('style', 'display:none') iFrame.setAttribute('height', '0px') iFrame.setAttribute('width', '0px') iFrame.setAttribute('frameborder', '0') document.body.appendChild(iFrame) // This iFrame is useless after the request is initiated, so remove it from dom iFrame.parentNode.removeChild(iFrame) iFrame = null } Copy code

setupWebViewJavascriptBridgeメソッドの後に追加されました。JSでこのメソッドを1回呼び出す必要があります:

setupWebViewJavascriptBridge(function(bridge) { bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) { alert('JS method is called:'+data) responseCallback('js executed too') }) }) Copy code

Nativeが呼び出す必要のあるJS関数も、実行する前に登録する必要があります。 Nativeが複数のJS関数を呼び出す必要がある場合、Nativeが呼び出す前に、これらの関数をここに登録する必要があります。次に、JSでのこのメソッドの役割を分析する必要があります。

ここにポイントがあります:

1、最初の呼び出しsetupWebViewJavascriptBridge最初の実行時、window.WebViewJavascriptBridge with window.WVJBCallbacks存在しないため、実行を継続し、パラメーターのコールバック(関数)配列にロードされ、window.WVJBCallbacksに割り当てられます。 jsは、属性の動的な追加と値の割り当てをサポートしています。ここではwindow.WVJBCallbacks = [callback]属性を動的に追加して値を割り当てることです。さらに、jsのグローバル変数はwindow.xxxxを使用して呼び出すことができ、動的に追加された属性も追加できます。window.、直接使用します。

2、WebViewJavascriptBridgeヘルプJSがネイティブURLを呼び出すのに2種類あります。1つはwvjbscheme://__BRIDGE_LOADED__、もう1つはwvjbscheme://__WVJB_QUEUE_MESSAGE__です。前者はsetupWebViewJavascriptBridge 1回だけ実行されます。通常、このURLは、ページがない場合に1回だけ実行する必要があります。 2番目のURLは、すべてのjsがネイティブ関数を呼び出すときに使用されます。

3.カスタムURLをインターセプトする場合、WebViewJavascriptBridge 3つの状況に分けられます。wvjbscheme://__BRIDGE_LOADED__の場合、すでに書き込まれたjsをHMTLに挿入すると、このjsはWebViewJavascriptBridge_JSはいの場合| _ + _になります。 |次にwvjbscheme://__WVJB_QUEUE_MESSAGE__を使用して、jsでcallHandlerを呼び出すために渡されたパラメーターを取得します。次に、from stringByEvaluatingJavaScriptFromString以前に保存されたネイティブメソッドに対応するブロックが、対応するブロックを呼び出します。

5番目のステップ、ネイティブ関数を呼び出す

ネイティブ関数は、以前に挿入されたJSメソッドcallHandlerを使用して呼び出すことができます。サンプルコードは次のとおりです。

WebViewJavascriptBridge

ここでcallHandlerの前function shareClick() { var params = {'title':'Test shared title','content':'Test shared content','url':'http://www.baidu.com'} WebViewJavascriptBridge.callHandler('shareClick',params,function(response) { alert(response) document.getElementById('returnValue').value = response }) } Copy code実際、これはJSのコードに挿入される最後のステップであり、動的に属性を作成し、動的に割り当てられた属性です。次のコードスニペットはWebViewJavascriptBridgeにあります。

WebViewJavascriptBridge_JS

そして、callHandlerは内部で別のjs関数を呼び出しますwindow.WebViewJavascriptBridge = { registerHandler: registerHandler, callHandler: callHandler, disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, _fetchQueue: _fetchQueue, _handleMessageFromObjC: _handleMessageFromObjC } Copy codeおよび_doSend内部では、handlerNameとパラメーターデータ、およびcallbackIdがキーと値のペアにロードされ、配列に保存されます。_doSend、同時にロードsendMessageQueue。使用する場所ですwvjbscheme://__WVJB_QUEUE_MESSAGE__ iOSネイティブへのJS呼び出しの実装が完了しました。

ステップ6、ネイティブ呼び出しjs関数

ネイティブはjsを呼び出します。また、関数を呼び出すには、最初にjsにエイリアスを登録する必要があります。

6.1jsレジスタネイティブ呼び出される関数

サンプルコード:

WebViewJavascriptBridge
6.2ネイティブ呼び出し関数エイリアスmanagerName

サンプルコード:

setupWebViewJavascriptBridge(function(bridge) { bridge.registerHandler('testJSFunction', function(data, responseCallback) { alert('JS method is called:'+data) responseCallback('js executed too') }) // Register other features //bridge.regsiterHandler..... }) Copy code

そして、callHandlerメソッドはjsメソッドへの呼び出しをどのように実装しますか? callHandlerは、js、handlerName、callbackIdに渡されたパラメーターを内部的に結合して辞書に変換し、次に辞書を文字列に変換し、変換された文字列をパラメーターとして渡します。// // If you don't need parameters, don't need a callback, use this // [_webViewBridge callHandler:@'testJSFunction'] // // If you need parameters, don't need a callback, use this // [_webViewBridge callHandler:@'testJSFunction' data:@'a string'] // If you need both parameters and callbacks, use this [_webViewBridge callHandler:@'testJSFunction' data:@'a string' responseCallback:^(id responseData) { NSLog(@'callback after calling JS: %@',responseData) }] Copy code jsに渡されると、jsは渡されますjsonに渡された文字列。次に、handlerNameを介して対応する関数の実行を取得します。コードの重要な部分:

stringByEvaluatingJavaScriptFromString

これは、handlerNameを見つけて関数を実行する関数です。

// Here is the native call to js , which converts the argument to a string and executes the _handleMessageFromObjC method in js. - (void)_dispatchMessage:(WVJBMessage*)message { NSString *messageJSON = [self _serializeMessage:message pretty:NO] [self _log:@'SEND' json:messageJSON] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@'\' withString:@'\\'] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@''' withString:@'\''] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@''' withString:@'\''] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@' ' withString:@'\n'] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@' ' withString:@'\r'] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@'f' withString:@'\f'] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@'u2028' withString:@'\u2028'] messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@'u2029' withString:@'\u2029'] NSString* javascriptCommand = [NSString stringWithFormat:@'WebViewJavascriptBridge._handleMessageFromObjC('%@')', messageJSON] if ([[NSThread currentThread] isMainThread]) { [self _evaluateJavascript:javascriptCommand] } else { dispatch_sync(dispatch_get_main_queue(), ^{ [self _evaluateJavascript:javascriptCommand] }) } } Copy code

ここに移動してWebViewJavascriptBridgeを使用し、jsへのネイティブ呼び出しを実装します。

注意:JSには動的パラメーターの特性があります。 jsを呼び出すことにより、0個のパラメーター、1個のパラメーター、およびN個のパラメーターを渡すことができます。たとえば、jsでtest()メソッドを定義し、渡されるパラメーターがある場合はtest()を呼び出してこのメ​​ソッドを実行し、test(xxx)を呼び出すこともできます。複数のパラメーターがある場合は、test( xxx、xxx)。もちろん、定義するパラメーターがtest(a、b、c)の場合、パラメーターを少なく渡すか、パラメーターを渡さずにtest()を呼び出すこともできます。

総括する

WebViewJavascriptBridgeを使用して、JSとOCの相互作用の利点を実現します。

1.パラメータを取得する方が便利です。パラメータに特別な記号またはURLパラメータがある場合は、適切に解析できます。

いくつかの欠点もあります。

1.インタラクションを行うために、実行する必要のあるjsには、元のjsとのインタラクションステップが少なくとも2回多くあります。

2、より多くの時間を費やし、原理を理解し、WebViewJavascriptBridgeの手順を使用する必要があります。

サンプルプロジェクトアドレス: JS_OC_WebViewJavascriptBridge

楽しんで!