Android WebView 动态修改Html 样式

2022-07-09  本文已影响0人  SoldierWIN

前言

在Android的应用里用WebView 加载一个网页可以说是很常见的需求了,但是会有些情况前端页面不满足UI样式并且前端资源不足的情况,这个时候就需要我们自己动手在客户端这边来修改页面样式,废话不多说,开始。

1、WebViewClient

这个是修改样式的关键类:

mWebView.setWebViewClient(new WebViewClient() {
...
//这里重写需要的方法
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    //在当前的webview中跳转到新的url,重定向
   return true;
}
@Override
public void onPageFinished(WebView view, String url) {
    Log.d(TAG, "onPageFinished url = " + url);
    if (url.contains("passport.xiami.com/qrcode-login")) {
        view.loadUrl("javascript:(function() {" +
                "var parent = document.getElementsByTagName('head').item(0);" +
                "var style = document.createElement('style');" +
                "style.type = 'text/css';" +
                "style.innerHTML = window.atob('" + qrcss + "');" +
                "parent.appendChild(style)" +
                "})()");
    } else
        if (url.contains("oauth.xiami.com/authorize")) {
        view.loadUrl("javascript:(function() {" +
                "var parent = document.getElementsByTagName('head').item(0);" +
                "var style = document.createElement('style');" +
                "style.type = 'text/css';" +
                "style.innerHTML = window.atob('" + authcss + "');" +
                "parent.appendChild(style);" +
                "})()");
    } else {
    super.onPageFinished(view, url);
    }

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
    Log.d(TAG, "shouldInterceptRequest url=" + request.getUrl());
    if (request.getUrl().toString().contains("https://passport.xiami.com/qrcode-login")) {
        //通过URL主动请求整个html回来,然后注入CSS和JS
        String page = mCssUtils.getUrlData(request.getUrl().toString(),"css/qr_code.css", "js/disableclick.js");
        return new WebResourceResponse("text/html", "utf-8", new ByteArrayInputStream(page.getBytes()));
    }
    else if(request.getUrl().toString().contains("oauth.xiami.com/authorize")){
        //通过URL主动请求整个html回来,然后注入CSS和JS
        String page = mCssUtils.getUrlData(request, cookies,"css/auth.css", null);
        return new WebResourceResponse("text/html", "utf-8", new ByteArrayInputStream(page.getBytes()));
    }
    //因为授权界面的修改复杂一些,针对特定的资源一个个修改
    //左方向箭头
    else if (request.getUrl().toString().contains("https://gtms02.alicdn.com/tps/i2")) {
        try {
            return new WebResourceResponse("image/png", "UTF-8", getAssets().open("img/left.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //右方向箭头
    else if (request.getUrl().toString().contains("https://gtms02.alicdn.com/tps/i3")) {
        try {
            return new WebResourceResponse("image/png", "UTF-8", getAssets().open("img/right.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }//加载CSS的时候,附加我们自己的css上去
    else if (request.getUrl().toString().contains("https://oauth.xiami.com/assets/css/oauth-us.css")) {
        String css = mCssUtils.appendCss(request.getUrl().toString(), "css/auth.css");
        return new WebResourceResponse("text/css", "UTF-8", new ByteArrayInputStream(css.getBytes()));
    }
    return super.shouldInterceptRequest(view, request);
}



}

onPageFinished 里边执行js方法这种方式可以在网页加载完成之后做一些操作,比如插入样式,但是会导致页面刷新闪烁;

另外一种方式,就是拦截请求,在网页加载之前在上面修改或者加入我们需要的样式内容; 这种方式也是比较推荐的;

1、方法一是通过请求的url,主动去访问,请求整个html回来,注入css和js,注意因为这个时候此方法还没有返回,所以界面不会刷新,也就解决了闪烁的问题,当我们返回注入过css和js的WebResourceResponse对象时,界面才会加载。
2、方法二是针对要请求的资源类型,如image、css、js等,拦截后给系统返回我们自定义的css和js,达到注入修改的目的
注入的过程中,注意css注入在head最后位置,js注入在body最后位置,其实就是要让自己的css和js最后执行,防止被后面的代码覆盖。我在项目中注入的html中就在</body>的结束前还有一段js代码,一开始没注意,我注入的js一直未起效。

二、工具类

下面是工具类相关的代码:Cssutil

import android.text.TextUtils;
import android.webkit.WebResourceRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

public class CssUtil {

    private static String mDefaultEncoding = "UTF-8";

    /**
     * 描述:根据给定的网址,获取返回的html注入css和js
     * @param
     * @return
     * @throw
     */
    public static String getUrlData(WebResourceRequest request, String cookies, String cssPath, String jsPath) {
        String page = getHtml(request, cookies);
        String css = "";
        if (!TextUtils.isEmpty(cssPath)) {
            css = buildCss(cssPath);
        }
        String js = "";
        if (!TextUtils.isEmpty(jsPath)) {
            js = buildJS(jsPath);
        }
        page = inject(page, css, js);
        return page;
    }




    //描述:请求指定的url并返回html页字符串
    private static String getHtml(WebResourceRequest request, String cookies) {
        StringBuilder total = new StringBuilder();
        try {
            URL url = new URL(request.getUrl().toString());
            Map<String, String> headers = request.getRequestHeaders();
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //设置请求的header
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }
            //扫码请求登录网页cookies一定要设置,不然后台判断登录状态会出错
            if (cookies != null && !cookies.isEmpty()) {
                connection.setRequestProperty("Cookie", cookies);
            }
            connection.setRequestMethod(request.getMethod());
            connection.connect();
            InputStream is = connection.getInputStream();
            String encoding = connection.getContentEncoding();
            if (encoding == null) {
                encoding = mDefaultEncoding;
            }
            BufferedReader r = new BufferedReader(new InputStreamReader(is, encoding));
            String line;
            while ((line = r.readLine()) != null) {
                total.append(line);
            }
            is.close();
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return total.toString();
    }



    /**
     * 描述:根据指定路径读取css文件
     *
     * @param
     * @return
     * @throw
     */
    private static String buildCss(String css) {
        StringBuilder contents = new StringBuilder();

        InputStreamReader reader;
        try {
            reader = new InputStreamReader(ContextUtil.getContext().getAssets().open(css), mDefaultEncoding);
            BufferedReader br = new BufferedReader(reader);

            String line;
            while ((line = br.readLine()) != null) {
                contents.append(line);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "<style type=\"text/css\">" + contents.toString().trim().replace("\n", "") + "</style>";
    }


    /**
     * 描述:根据给定路径读取js文件
     *
     * @param
     * @return
     * @throw
     */
    private static String buildJS(String jsPath) {
        StringBuilder contents = new StringBuilder();

        InputStreamReader reader;
        try {
            reader = new InputStreamReader(ContextUtil.getContext().getAssets().open(jsPath), mDefaultEncoding);
            BufferedReader br = new BufferedReader(reader);

            String line;
            while ((line = br.readLine()) != null) {
                contents.append(line);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "<script type=\"text/javascript\">" + contents.toString().trim().replace("\n", "") + "</script>";
    }



    /**
     * 描述:给定的HTML中插入css和js代码
     *
     * @param
     * @return
     * @throw
     */
    private static String inject(String page, String css, String js) {
        int headEnd = page.indexOf("</head>");
        String res;
        if (headEnd > 0) {
            res = page.substring(0, headEnd) + css + page.substring(headEnd, page.length());
        } else {
            res = "<head>" + css + "</head>" + page;
        }

        int bodyEnd = res.indexOf("</body>");
        if (bodyEnd > 0) {
            res = res.substring(0, bodyEnd) + js + res.substring(bodyEnd, res.length());
        }
        return res;
    }


}

Css 样式,这里要根据自己的网页实际内容写样式,例如:

.p1 {
    text-align:center;
    color:#1E293D;
    font-size: 60px;
}

.p2 ,.p3 ,.p4, .s6 {
    color:#1E293D;
    font-size: 40px;
}

body {background-color:#00000000;}

Css样式不怎么熟的可以看下这 菜鸟教程,还是比较简单的,可以根据id 、class 或者标签修改;
如果想插入js脚本也是类似的操作,这里就不写例子了;

本文是摘自一位老哥的笔记,也是为了自己记录一下,感兴趣老哥的无私奉献。

上一篇 下一篇

猜你喜欢

热点阅读