onPageFinished でJavaScript 連携に普遍性を。。

WebViewJavaScript 連携はセキュリティに問題が残るとしても、やはり魅力的な使い方がある。
ページが読み込めなかった時、、

f:id:posturan:20160313193422p:plain


WebViewClient onReceivedError が呼ばれるのでそこでエラー処理を書けばよいのだが、、
onPageFinished で判定したい場合に、JavaScript 連携を使ってしまう。
画面に出さない、裏で WebView を使った処理する時などに使えそうである。

注意しなければならないのは、上の「ページが見つかりませんでした」のエラーの場合、
onPageFinished は、2回呼ばれることだ。

onPageFinished で JavaScript による判定の結果実行されるインターフェースを以下のように用意する。

public interface PageFinishedListener{
   public void onSuccess(String url);
   public void onFailed(String url);
}


WebView の addJavascriptInterface でセットするインスタンスのクラス定義は以下のようにする。
getRname() が、addJavascriptInterface 実行のキー名を返すようになっている。

import android.webkit.WebView;
/**
 * WebPageJsRelay
 */

public class WebPageJsRelay{
   private int count;
   private PageFinishedListener handle;
   private String url;
   private boolean isPages;

   public WebPageJsRelay(PageFinishedListener handle){
      count = 0;
      this.handle = handle;
   }
   public final String getRname(){
      return "jsrelay";
   }

   public final void triggerPageStarted(){
      count = 0;
      isPages = false;
   }
   public final void  triggerPagefinished(WebView _view, String _url){
      this.url = _url;
      isPages = !isPages;
      if (isPages){
         _view.loadUrl("javascript:var g=document.getElementsByTagName('img');for(var i=0;i<g.length;i++){ jsrelay.imaged(g[i].src); }jsrelay.parse();");
      }
   }
   public final void imaged(String src){
      if ("file:///android_asset/webkit/android-weberror.png".equals(src)){
         count++;
      }

   }
   public final void parse(){

     if ( count > 0){
         count = 0;
         handle.onFailed(url);
      }else{
         handle.onSuccess(url);
      }
   }
}

使用サンプルは、

WebView mWebView;
WebPageJsRelay mPageRelay;
  :
  :
mPageRelay = new WebPageJsRelay(new PageFinishedListener(){
   @Override
   public void onSuccess(String url){
      // TODO ページが正常に読み込めた時の処理
   }
   @Override
   public void onFailed(String url){
      // TODO ページが読み込めなかった時の処理
   }
});
mWebView.addJavascriptInterface(mPageRelay, mPageRelay.getRname());


mWebView.setWebViewClient(new WebViewClient(){
   @Override
   public void onPageStarted(WebView view, String url, Bitmap favicon){
      mPageRelay.triggerPageStarted();
   }
   @Override
   public void onPageFinished(WebView view, String url){
      mPageRelay.triggerPagefinished(view, url);
   }
   @Override
   public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
      // エラー受信時の処理
   }
   private Message mdontResend;
   @Override
   public void onFormResubmission(WebView view,Message dontResend,Message resend){
      if (mdontResend != null){
         mdontResend.sendToTarget();
         return;
      }
      mdontResend = dontResend;
      if (resend != null){
         resend.sendToTarget();
         mdontResend = null;
      }
   }
   @Override
   public void onReceivedHttpAuthRequest(WebView view,final HttpAuthHandler handler,String host,String realm){
      handler.cancel();
   }
});