2017-02-26 7 views
1

私はHTMLにCSSファイルを挿入した後で、私のwebviewを表示しようとしています。 私はonPageCommitVisible関数に入れようとしましたが、上の23個のapisとddのみで動作します。誰かが、CSSがロードされた後に初めてwebviewを表示するにはどうすればよいでしょうか?今度は "ジャンプ"し、新しいCSSが置き換えられる前に、元のCSSが最初の1秒間表示されます。あなたが関数内で見ることができるようAndroid:CSS注入が完了したことを知るにはどうすればいいですか?

private void injectCSS(WebView webView) { 
      try { 
       webView.loadUrl("javascript:(function() {" + 
         "var css = document.createElement(\"style\");\n" + 
         "css.type = \"text/css\";\n" + 
         "css.innerHTML = \"" + readFileAsString() + "\";\n" + 
         "document.body.appendChild(css);" + 
         "})()"); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 

この機能は、HTMLにCSSのコードを挿入:

@Override 
     public void onPageFinished(WebView view, String url) { 
      Utils.logDebug(this, "Page finished"); 
      if (android.os.Build.VERSION.SDK_INT < 23) { 
       injectCSS(view); 
      } 
      super.onPageFinished(view, url); 
      showWebView(true); 
      onPageChange(); 
     } 

は、これは私のInjestCSS機能です。

+0

あなた 'injectCSS'がやって何? – j2ko

+0

@ j2koただ質問を更新しました。 –

答えて

2

これを処理できる場所はほとんどありません。

  • あなたはevaluateJavaScript代わりのloadUrl(APIレベル19)を使用して、WebViewのが見える設定しますれているコールバックを渡すことができます。
  • あなたはaddJavaScriptInterfaceを使用して独自のJavaScriptインターフェースを登録し、あなたがWebChromeClientを設定し、特定のメッセージを使用してスクリプトの昇給の警告で、その後onJsAlertをオーバーライドすることができます
  • スクリプトの最後にそれを呼び出すことができます。
  • UPDATE:さらに、これは 'css'リクエストの1つをインターセプトし、ロードされたファイルに必要なコンテンツを追加することで実現できます。これにより、onPageFinishedの直前にスタイルを挿入することができます。このthisスレッドを確認してください。

私は例を以下にまとめているすべてのアプローチ:

package com.j2ko.webviewapp; 

    import android.support.v7.app.AppCompatActivity; 
    import android.os.Bundle; 
    import android.util.Base64; 
    import android.util.Log; 
    import android.view.View; 
    import android.webkit.JavascriptInterface; 
    import android.webkit.JsResult; 
    import android.webkit.ValueCallback; 
    import android.webkit.WebChromeClient; 
    import android.webkit.WebView; 
    import android.webkit.WebViewClient; 

    import java.io.InputStream; 
    import java.io.StringReader; 
    import java.io.StringWriter; 

    public class MainActivity extends AppCompatActivity { 
     private static final String MAIN_FUNC_FMT = "(function() { %s })()"; 
     private static final String FUNC_BODY_FMT = 
       "var parent = document.loadedgetElementsByTagName('head').item(0);" + 
         "var css = document.createElement('style');" + 
         "css.type = 'text/css';" + 
         "css.innerHTML = %s;" + 
         "parent.appendChild(css);"; 

     private static final String BASE64_DECODE_FMT = "window.atob('%s')"; 

     WebView mWebView; 

     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.activity_main); 

      mWebView = (WebView) findViewById(R.id.webview); 
      mWebView.getSettings().setJavaScriptEnabled(true); 
      mWebView.setWebViewClient(new WebViewClient() { 
       @Override 
       public void onPageFinished(WebView view, String url) { 
        super.onPageFinished(view, url); 
        //Change it to whatever 
        injectWithEvaluateAndInterface(view); 
       } 

       @Override 
       public void onLoadResource(WebView view, String url) { 
        super.onLoadResource(view, url); 
       } 
      }); 
      mWebView.setVisibility(View.INVISIBLE); 
      mWebView.loadUrl("http://wiki.org"); 
     } 


     private static class CSSInjectBuilder { 
      private final String mOrigin; 
      private String mAtEnd = null; 
      private boolean mUseBase64 = false; 

      public CSSInjectBuilder(String css) { 
       mOrigin = css; 
      } 

      public CSSInjectBuilder withBase64() { 
       mUseBase64 = true; 
       return this; 
      } 

      public CSSInjectBuilder withExpressionAtEnd(String expression){ 
       mAtEnd = expression; 
       return this; 
      } 

      String build() { 
       String func_body = FUNC_BODY_FMT; 

       if (mAtEnd != null) { 
        func_body += mAtEnd; 
       } 

       final String css; 
       if (mUseBase64) { 
        byte[] buffer = mOrigin.getBytes(); 
        css = String.format(BASE64_DECODE_FMT, Base64.encodeToString(buffer, Base64.NO_WRAP)); 
       } else { 
        css = "'" + mOrigin + "'"; 
       } 

       func_body = String.format(func_body, css); 

       return String.format(MAIN_FUNC_FMT, func_body); 
      } 
     } 

     byte[] loadAsset() { 
      try { 
       InputStream inputStream = getAssets().open("style.css"); 
       byte[] buffer = new byte[inputStream.available()]; 
       inputStream.read(buffer); 
       inputStream.close(); 
       return buffer; 
      } catch (Exception e) { 
      } 

      return null; 
     } 

     String loadCSS() { 
      return new String(loadAsset()); 
     } 

     void injectWithEvaluate(final WebView view) { 
      view.evaluateJavascript(new CSSInjectBuilder(loadCSS()).withBase64().build(), new ValueCallback<String>() { 
       @Override 
       public void onReceiveValue(String value) { 
        view.setVisibility(View.VISIBLE); 
       } 
      }); 
     } 

     void injectWithEvaluateAndInterface(WebView view) { 
      view.addJavascriptInterface(new WebViewInterface(), "WebViewBackEnd"); 
      final String injector = new CSSInjectBuilder(loadCSS()) 
        .withBase64() 
        .withExpressionAtEnd("window.WebViewBackEnd.CSSInjectionComplete();") 
        .build(); 

      view.evaluateJavascript(injector, null); 
     } 

     void injectWithLoadUrlSimple(WebView view) { 
      view.loadUrl("javascript:" + loadCSS()); 
      view.setVisibility(View.VISIBLE); 
     } 

     void injectWithLoadUrlAndCheckAlert(final WebView view) { 
      view.setWebChromeClient(new WebChromeClient() { 
       @Override 
       public boolean onJsAlert(WebView view, String url, String message, JsResult result) { 
        if (message.equals("CSSInjectionComplete")) { 
         view.setVisibility(View.VISIBLE); 
         return true; 
        } 
        return super.onJsAlert(view, url, message, result); 
       } 
      }); 

      //alert could hang aplying scripts so put it on timeout 
      final String injector = new CSSInjectBuilder(loadCSS()) 
        .withBase64() 
        .withExpressionAtEnd("setTimeout(function(){alert('CSSInjectionComplete');}, 1);") 
        .build(); 

      view.loadUrl("javascript:" + injector); 
     } 

     private class WebViewInterface { 

      @JavascriptInterface 
      public void CSSInjectionComplete(){ 

       mWebView.post(new Runnable() { 
        @Override 
        public void run() { 
         mWebView.setVisibility(View.VISIBLE); 
        } 
       }); 
      } 
     } 

    } 
+0

すべてのアプローチを実装する必要がありますか、それとも1つだけ実装する必要がありますか? – Brudus

+0

私は説明の目的のためだけにすべてを掲示しました - どれがどちらに合うかを選択してください – j2ko

+0

今のところ私は1つだけ試しましたが、WebViewInterfaceではまだ目に見えるwebviewとインジェクションの間に遅延があります。 – Brudus

関連する問題