iOSはJavaScripptCoreエンジンフレームを導入する


JavaScripptCoreエンジン
    WebKitはレンダリングエンジンであり、簡単にページのレイアウト、描画及びレイヤの合成を担当していることは知っていますが、WebKitプロジェクトにはレンダリング関連のロジックだけでなく、デフォルトのjavascriptエンジン-JavaScripptCoreも集積されています.現在SafariのJSCに基づいて構築されています.JSCの実行理念は従来のエンジン論理に合致しており、2つの部分を含んでいる. JIT.解釈器は、ある種のタイプのファイル解釈に対して実行され、JSCでは、そのターゲットファイルはコードで構築されたシンタックスツリーによって生成されたバイトコードファイルであり、javaのバイトコードに類似しているが、JSCではバイトコードの実行は、スタックに基づくものではなく、レジスタに基づく仮想マシンであることが分かりやすい.利点は、ARMアーキテクチャプロセッサにおいて、3アドレスコマンドを使用して、より多くの回数を減らすことができるスタックやスタックなどのコマンドの割り当てや時間を消費するメモリIOです.JITはjava仮想マシンに多くの応用があり、より多くのホットスポットを実行する方法を現地の方法にコンパイルし、より効率的に実行しています.JSCのJITは同じです.    iOS 7では、JSCフレームワークを導入することができ、このようにして、js層コードの実行をoc層で操作することができます.また、JSCは多くのCレベルのインターフェースを露出しています.私たちも下の階でカスタムjs実行環境を構築し、操作はjsコードを実行し、制御可能な実行はより拡張性が強いです.
hybridアプリケーション構築
    このようなパワフルなエンジンがある以上、私達はhybridpアプリを構築する時、JSCを使って、cordvaのwebView JavascriptBridgeフレームの代わりに簡易なインターフェース露出を完成します.今後は、oc層でUIコンポーネントをモジュール化し、JSExport暴露インターフェースを通じて、js層が対応するモジュールの初期化方法を調整します.  oc端初期化は、js実行コンテキストJSContextオブジェクトを簡単に実行し、[[JSContext alloc] init]でよいが、hybrid appでは、このようにJSContextを初期化することによって、キャリアページのUICWebVIewとは同じjs環境ではないので、UICWebView対応するJSContextを取得する必要がある.しかし、apple公式は関連の方法を提供していませんが、こちらでは一部の人が難しいです.KVC方式でUICWebView対応のJSContextを取得することができます.方式は以下の通りです.対応するJSContextを取得すると、私たちができることがたくさんあります.
//      JSContext
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

//   JSContext       
[context setExceptionHandler:^(JSContext *context, JSValue *value) {
    NSLog(@"oc catches the exception: %@", value);
}];

//          UIController   
ShowjoyFad *sf=[ShowjoyFad new];

//      JSContext , js               , window.showjoyFad
context[@"showjoyFad"]=sf;
context[@"ViewController"] = self;

//   js      
JSValue * abc = context[@"abc"];
//   
JSValue * ret = [abc callWithArguments:@[@"helloworld"]];
NSLog(@"ret: %@",[ret toString]);
    簡単な例によって、JSC通信の簡潔さが明らかになります.androidのWebView通信と同様に、native端末は直接インターフェースをjsコンテキストに注入できます.jsはいつのタイミングで関数を呼び出しますか?しかし、ここでは比較的難しい問題に関連しています.JSContextの取得はUICWebViewのその段階ですか?    まずUICWebViewのwebView DidStartLoad段階でJSContextを作成して、oc端を暴露する方法があります.一級ページをロードする時、jsは正常にocを呼び出す方法がありますが、二級ページにジャンプしても、ocを実行する方法がありません.webView DidStartLoadの段階では、jsファイルはロードされていませんので、js層で定義されている関数は、oc端では実行できません.    第二に、webVIew DidFinishLoad段階でJSContextを作成して、oc方法を透過します.js段階はwebVIew DidFinish Load段階の前ですので、一級ページjsはocメソッドを呼び出すことができません.しかし、二級ページは同じです.しかし、jsコードはiOSのUIスレッドで実行されます.jsにsetTimeoutを設定することにより、タスクを実行キューの端に置くことができます.まず、oc層のwebVIew DidFinish Load方法を実行し、タスクが完了したらjs中の非同期コードを実行します.逆に、oc層がjs関数を呼び出しても問題はありません.なぜなら、webVIew DidFinishLoad段階でjsコードが実行されました.    このため、簡単な枠組みを実現することによって、js層とoc層の相互作用ができ、より良い互換性のために、webVIew DidFinishLoad段階でJSContextを作成するしかない.一方、js層では、2つの方法が監視され、ocを実行する方法がある.
          1, oc  webVIewDidFinishLoad  ,  oc    ,  JSContext  UIWebView stringByEvluateJavascriptString      ```webViewDidFinishLoad```  ,js        
          2,     setTimeout js           
    上記の方法によって、簡単なJSCBridgeを構築しましたが、欠点もはっきりしています.oc端インターフェース暴露のタイミングには硬性が要求されています.そして、jsがoc端を実行するコードは一貫して非同期です.
なぜ第一案を放棄しましたか?
UICWebViewのJSContext取得
    前編では、UICWebVIewのJSConetextを簡単なkvcで取得しましたが、実際には、appleは開発者にUICWebViewにアクセスする方法を提供していません.KVCを通じて目標に達することができますが、APPがこのhack方法を採用すると、APP Storeの審査を通過できない可能性が大きいです.これはオンラインベースのビジネスAPPにとっては耐えられません.ですから、UICWebViewのJSContextを取得するための別の方法を探さなければなりません.安全で使いやすいので、目を逸らす必要があります.
解決
WebFrame LoadDelegate
    OS Xでは、WebFrame LoadDelegateはWebKitとNSWebViewとの通信を担当しています.NSWebViewの内部は依然としてWebKitレンダリングエンジンを使用しています.レンダリング中の一連のイベントを解決するには、WebFrame LoadDelegateオブジェクトを使用しなければなりません.        1、ロードプロセス:
                         ,      ,    ,     。webkit          WebFrameLoadDelegate 。

              webView:didStartProvisionalLoadForFrame:    ,        url
              webView:didReceiveTitle:forFrame:       
              webView:didFinishLoadForFrame:      
        2、エラーの処理:
                 ,        。          WebFrameLoadDelegate 。                     

             webView:didFailProvisionalLoadWithError:forFrame:              ,          URL            
             webView:didFailLoadWithError:forFrame:              
    でもiOSの中では?私は試したことがありますが、WebFrame LoadDelegateという対象はありません.iOSのWebKitフレームはUnibViewほど多くのインターフェースを提供していないようですが、WebKitのソースを通して、彼はNick Hodappです.
Nickの発見
    iOSでは、WebFrame LoadDelegateが暴露されていないにもかかわらず、具体的な実現においては、WebKitのimplementがこのプロトコルを実現するいくつかの方法があるかどうかを判断し、実現すれば実行され、webitのWebFrame Loader Cient.mmファイルでは、
if (implementations->didCreateJavaScriptContextForFrameFunc) {
    CallFrameLoadDelegate(implementations->didCreateJavaScriptContextForFrameFunc, webView, @selector(webView:didCreateJavaScriptContext:forFrame:),
        script.javaScriptContext(), m_webFrame.get());
}
現在のオブジェクトが[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]方法を実装しているかどうかを判断します.ある場合は実行します.この方法は3つのパラメータを伝達します.最初はwebkitと通信するWebViewです.このWebViewはUICWebVIewではなく、Nick層がテストをしました.得られたWebViewはUID Viewではないと推測されます.二つ目は私たちが獲得したいJSContextです.三つ目のパラメータはwebkitフレームの中のWebFrameオブジェクトであり、私たちの期待とは無関係です.
    この関数をwebkitに実行させるためには、オブジェクトにこの方法を実現させなければなりません.全てのOCオブジェクトはNSObjectオブジェクトから継承されているので、この方法はNSObjectオブジェクトで実現でき、このセグメントコードはwebkitフレームで実行できることを保証することができる.
    その次に、私達はJSContextを取得しましたが、JSContextとUICWebVIewの対応関係は分かりません.私達のView Controllerの中に複数のUICWebViewがあるかもしれません.どうやって取得したJSContextをUICWebviewに対応するかも難しい問題です.ここでは、すべてのUICWebViewオブジェクトを取得し、各オブジェクトの中でjsコードを実行し、jsコンテキストで変数をマーキングし、取得したJSContextでUICWebVIewオブジェクト中のオブジェクトと同じかどうかを判断する簡単な方法があります.このように、私達はUICWebViewのwebView DidStartLoadとwebView DidFinishLoadの間でJSContextを取得して、ocとjsの双方向通信を行うことができます.
完全である
    前節の説明を通して、Nickの考えが大体分かりましたので、このような通信機構はプロトコルとカテゴリを通して完成できます.もちろん、ocを使って運行する時も大丈夫です.最終のocエンドインターフェースのコードはwebView:didCreateJavaScriptContext:forFrame:において、jsファイルはロードが完了すれば、ocのインターフェース方法を実行することができます.クロック端がjsにアクセスするインターフェースはwebVIew DidFinishLoadで実行でき、webView:didCreateJavaScriptContext:forFrame:の問題を完璧に解決します.    js端では、全体に露出された だけが、oc端をアクセスできるので、js端の柔軟性が制限される.私はjsの端で「賦」を通じてインターフェースの暴露(window.say=function(){alert}を完成しました.)、ocの端でアクセスできなくて、普通の関数声明を通じてのみ問題を解決できます.これはJSContextのメモリポインタ参照と関係があります.この問題を解決するために、グローバル関数を作成してjsのインターフェースの対象を暴露します.取得したオブジェクトを通じて特定のインターフェース方法にアクセスする.
 if(isiOS4JSC){
    //          window.jscObj    
    var ev = eval;
    $.JSBridge._JSMethod = method;

    //        
    // jsc                 ,                 
    ev('function toObjectCExec() {' +
      'window.jscObj = window.jscObj ? window.jscObj : {};'+
      'window.jscObj["' + methodName + '"] = function (message) {' +
      '  var ret = $.JSBridge._JSMethod(message);' +
      '  return JSON.stringify(ret);' +
      '};' +
      'return jscObj;' +
    '}');

  }
このように、js端のインターフェースが露出しやすくなります.
終わりに
    現在のiOS hybridAPPの主流通信方式は依然としてcoravaのjavascript WebviewBridgeに適応していると信じていますが、jscがiOS 7に導入されるにつれて、ここで紹介したjscを使って、ocとjsの通信がより流行するようになります.しかし、私達はwebkitのソースコードでhackの方式を作ってもいけないわけではないです.UICWebViewは相変わらずwebkitを使ってレンダリングしさえすれば、この方式はずっと有効です.私たちは未来に憧れる理由があります.iOSとandroidの下でより便利な統合Jsエンジンで提案した双方向通信を完成します.