0

I've seen several questions on this but all of the solutions didn't work for me. For a client we have to develop an app that actually does nothing except of showing a WebView and a native DrawerLayout. However, we only have their mobile webpage (with a menu, etc.). So we have to hide some elements. It is very important that the existing stylesheets stay the same, just some other CSS rules are added.

What I've tried so far:

@Override
public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        if (!mErrorOccured && !noConnectionAvailable) {
            injectCSS();
        }

        mainActivity.hideLoadingScreen();
}

With this Injection:

// Inject CSS method: read style.css/readmode.css from assets folder
// Append stylesheet to document head
private void injectCSS() {
    try {
        Activity activity = (Activity) mContext;
        SharedPreferences sharPref = activity.getSharedPreferences(Constants.PREFERENCE_NAME, Context.MODE_PRIVATE);
        Boolean isReadMode = sharPref.getBoolean(Constants.READMODE_KEY, false);

        InputStream inputStream;

        if (isReadMode) {
            inputStream = activity.getAssets().open("readmode.css");
        } else {
            inputStream = activity.getAssets().open("style.css");
        }

        byte[] buffer = new byte[inputStream.available()];
        inputStream.read(buffer);
        inputStream.close();
        String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
        webView.loadUrl("javascript:(function() {" +
                    "var parent = document.getElementsByTagName('head').item(0);" +
                    "var style = document.createElement('style');" +
                    "style.type = 'text/css';" +
                    // Tell the browser to BASE64-decode the string into your script !!!
                    "style.innerHTML = window.atob('" + encoded + "');" +
                    "parent.appendChild(style);" +
                    "Android.injectCSS('Works!');})()");
        } catch (Exception e) {
            e.printStackTrace();
        }
}

I've also tried to add a JavaScript Interface that uses the Android.injectCSS('Works!'); of the JavaScript above combined with:

@JavascriptInterface
public void injectCSS(String toast) {
    Toast.makeText(mContext, toast, Toast.LENGTH_LONG).show();

    mMainActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mMainFragment.unhideWebView();
        }
    });
}

And:

public void unhideWebView() {
    webView.setVisibility(View.VISIBLE);
}

However, there is always a delay before the elements of the web page are hidden. I've also tried to use Jsoup. First this threw an NetworkOnMainThreadException. After I've tried to use it with an AsyncTask, it was not possible to change the WebView on onPostExecute() because this handling must be on the main thread. Even using a runOnUiThrad() did not help calling loadData() on the WebView with the new loaded data.

Is there any way to inject CSS/JS before the WebView shows up?

Brudus
  • 749
  • 1
  • 8
  • 22
  • Take a look at my answer here : http://stackoverflow.com/questions/42471990/android-how-can-i-know-css-injection-is-complete?noredirect=1#comment72084584_42471990 – j2ko Feb 27 '17 at 21:08
  • In addition to that you can intercept loading of one of the css files like described in this thread: http://stackoverflow.com/questions/8273991/webview-shouldinterceptrequest-example. But instead of replacing it's data - simply append it with your additional css rules – j2ko Feb 27 '17 at 21:11

0 Answers0