ios WKWebViewとJSのインタラクティブ実戦テクニック

16786 ワード

最近、同社はヒマワリの遠隔制御とピーナッツ殻動的ドメイン名解析サービスクライアントに対してHTML 5とインタラクティブなAppを行う必要があり、開発サイクルが短く、いつでもコンテンツを更新できるという利点がある.そこで、AppとWebのインタラクションの方法を整理しました.
一、WKWebView
Xcode 8がリリースされた後、コンパイラはiOS 7をサポートしなくなったため、私たちのappも最低サポートiOS 8.0に変更しました.webと対話する必要がある以上、iOS 8.0を使用してから発売された新しいコントロールWKWebViewを選択します.
WKWebViewは、UIWebViewに比べて多くのメリットがあります.
  • より多くのHTML 5の機能をサポート
  • 最大60 fpsスクロールリフレッシュ周波数と内蔵ジェスチャー
  • Safariに準拠するJavaScriptエンジン
  • パフォーマンス、安定性の面でメモリ消費量を大幅に向上させ、より少ないプロトコル方法と機能をより細かくする
  • は、ロードの進行状況などを取得することができる.

  • 二、WKWebViewの使い方の紹介
    注意:本文は主にWKWebViewとJSの相互作用を説明し、ここではWKWebViewの基礎的な使い方を簡単に紹介するだけで、その他の具体的な使い方の詳細は公式ドキュメントを参照してください.
    WebKitの導入が必要
    #import "">

    インスタンス化
    /*! @abstract Returns a web view initialized with a specified frame and
     configuration.
     @param frame The frame for the new web view.
     @param configuration The configuration for the new web view.
     @result An initialized web view, or nil if the object could not be
     initialized.
     @discussion This is a designated initializer. You can use
     @link -initWithFrame: @/link to initialize an instance with the default
     configuration. The initializer copies the specified configuration, so
     mutating the configuration after invoking the initializer has no effect
     on the web view.
     */
    - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

    HTMLページのロード
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
    WKWebView *webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
    [webView loadRequest:request];
    [self.view addSubview:webView];

    ここではloadだけでUIWebViewと同じように使用できますが、一般的な2つのエージェントについて簡単に説明します.
    三、WKWebViewエージェント
    WKWebViewには2つのエージェントがあります.
    
    /*! @abstract The web view's navigation delegate. */
    @property (nullable, nonatomic, weak) id  navigationDelegate;
    
    /*! @abstract The web view's user interface delegate. */
    @property (nullable, nonatomic, weak) id  UIDelegate;

    WKNavigationDelegateプロトコル
    WKNavigationDelegate主な処理ページジャンプ関連イベント
    //          
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
    
    //             
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
    
    //         
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    
    //           
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    
    //       
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    
    //             (    )
    - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
    
    //    
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
    
    //              
    - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    
    // webView           (         )
    - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
    
    // webView web          。(iOS 9.0  )
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));

    WKUIdelegateプロトコル
    WKUIdelegateは主に警告ボックス、ダイアログボックスなどのページ上のイベントを処理します.
    一般的な方法:
    //       
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
    
    //       
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
    
    //      
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;

    四、WKWebViewとJSのインタラクション
    インタラクション方式
    iOS 8.0以前にUIWebViewを使用していた場合、OCでJSコードを呼び出すしかありませんでしたが、JSはOCコードを直接呼び出すことができず、特別なリクエストを約定し、UIWebViewのプロトコルメソッドでリクエストをブロックすることでJSによるOCの呼び出しを実現する必要があります.
    ただし,WKWebViewを使用すると便利であり,約束したScriptMessage(スクリプト情報に直訳し,本稿ではJSイベントと暫定する)の傍受を直接追加することで,JS呼び出しOCを実現できる.すべての操作はWKUSerContentControllerで処理されます
    WKUSerContentControlの入手方法
    WKUserContentControllerは、WKWebViewのプロパティであり、WKWebViewは、WKWebViewのプロパティ(つまり、WKWebViewがインスタンス化されたときに渡されるconfiguration)である
    WKUserContentController *conntentController = self.webView.configuration.userContentController;

    WKUSerContentControllerについて詳しく説明します.
    五、WKUSerContentControl&JS呼び出しOC
    /*! A WKUserContentController object provides a way for JavaScript to post
     messages to a web view.
     The user content controller associated with a web view is specified by its
     web view configuration.
     */
    WK_EXTERN API_AVAILABLE(macosx(10.10), ios(8.0))
    @interface WKUserContentController : NSObject 
    WKUserContentController   JavaScript Web view       

    関連メソッドの紹介
    //  ScriptMessage(JS  )    
    - (void)addScriptMessageHandler:(id )scriptMessageHandler name:(NSString *)name;
    
    //    ScriptMessage(JS  )  
    - (void)removeScriptMessageHandlerForName:(NSString *)name;

    JSコールOC
    ScriptMessage(JSイベント)の追加削除
    まずJSコードにあらかじめ約束したScriptMessage(JSイベント)への呼び出しを加える.
    window.webkit.messageHandlers..postMessage(       )

    同時にOC側はこのJSイベントの傍受に参加する必要がある
    たとえば、@closeWindowというメッセージを渡します.
    window.webkit.messageHandlers.closeWindow.postMessage()

    OC側に@"closeWindow"というJSの傍受を追加
    [conntentController addScriptMessageHandler:self name:@"closeWindow"];

    ここでは、@"closeWindow"のリスニングを追加します.ただし、このJSイベントをキャプチャする際にどのように処理する必要があるかは、対応するプロトコルメソッドで実装する必要があり、scriptMessageHandlerがプロトコルWKScriptMessageHandlerを実装する必要がある場合は後述する.
    @closeWindowというJSイベントのリスニングを削除
    [conntentController removeScriptMessageHandlerForName:@"closeWindow"];

    WKScriptMessageHandlerプロトコル
    //      ScriptMessageJS- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

    たとえば、@closeWindowという名前のイベントを処理します.
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
    {
        //message.name   ScriptMessage    
        if ([message.name isEqualToString:@"closeWindow"]) {
            //    do something
            //message.body    ScriptMessage        
        }
    }

    六、OC呼び出しJS
    UIWebViewと同様にWKWebViewはJSメソッドを直接呼び出すことができる
    WKWebViewメソッド
    - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

    同様にJS側のメソッド名と対応する操作のkey値を事前に知る必要がある.例えば、Webのある処理完了を通知するJS関数名はfunctionであり、所定の操作名をactionとして実行する必要がある場合、呼び出しは以下のようになる.
    [self.webView evaluateJavaScript:@"function('action')" completionHandler:nil];

    七、同期タイトル
    WKWebViewが存在するUIViewController(ビューコントローラ)は、UINAvigationControllerナビゲーションコントローラが存在する場合があります.この場合、ジャンプしたページに応じてタイトルを変更する必要がある場合があります.この場合、KVO WKWebViewのtitleだけでよいので、最新のtitleをUIViewControllerのtitleに付与すればよいのです.
    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary""> *)change context:(nullable void *)context
    {
        if([keyPath isEqualToString:@"title"]){
            self.navigationItem.title = self.webView.title;
        }
    }</nskeyvaluechangekey,>></nscoding>></wknavigationdelegate>>

    作者:張文宇、ヒマワリの遠隔制御ソフトウェア/落花生の殻/タンポポルータiOS高級ソフトウェアエンジニア