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脚本也是类似的操作,这里就不写例子了;
本文是摘自一位老哥的笔记,也是为了自己记录一下,感兴趣老哥的无私奉献。