Android WebView注入CSS+JS的项目解决方案

【Android】webview javascript 注入方法 Android中向webview注入js代码可以通过webview.loadUrl("javascript:xxx")来实现,然后就会执行javascript后面的代码。 但是当需要注入一整个js文件的时候,貌似就有点麻烦了。不过理清以下思路,方法其实也很简单,如下:我们通过在webview的onPageFinished方法中执行js代码注入: 第一种: 当webview加载完之... 阅读详情

在某个项目中,由于用到第三方的接口,登录和授权的界面也由第三方提供,而我们是在车机产品上使用,分辨率为800X480。第三方并没有针对这个分辨率的布局,并且不为我们进行修改,就算是高德去推也没有推动。因此,只能使用偏门的方法,之所以说偏门,是因为注入css和js的方式是有风险的,假如web端改了页面,可能我们的app就得跟着升级了。好了,下面开始正题

  1. 首先,要在WebView注入JS,我们需要开启JS的支持:
    mWebView = (WebView) findViewById(R.id.wb_login);
    //访问的html中支持js
    mWebView.getSettings().setJavaScriptEnabled(true);
    //设置背景色
    mWebView.setBackgroundColor(0);
    //设置透明度
    mWebView.getBackground().setAlpha(0);
    mWebView.setWebViewClient(new WebViewClient() {
  2. 重写WebViewClient中的关键方法
    shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
    Give the host application a chance to take over the control when a new url is about to be loaded in the current WebView.
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        //在当前的webview中跳转到新的url
    
        //获取cookies
        CookieManager cm = CookieManager.getInstance();
        cookies = cm.getCookie(url);
        Log.d(TAG, "shouldOverrideUrlLoading url=" + url);
        Log.d(TAG, "shouldOverrideUrlLoading cookies ... " + cookies);
        if (url.contains("code=")) {
            mAutoMapCode = utils.getURLValue(url, "code");
            loginLayout.setVisibility(View.GONE);
            registerLayout.setVisibility(View.VISIBLE);
        }
    
        view.loadUrl(url);
        return true;
    }

我在demo中重写shouldOverrideUrlLoading这个函数主要是为了在Web进行重定向时,显示和隐藏一些Android界面的按钮,如果没有特殊的需求,不需要重写这个函数

onPageFinished(WebView view, String url)
Notify the host application that a page has finished loading.
@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);
    }
}

我们可以在onPageFinished回调函数中,通过js脚本的方式动态注入css,上面就是示例代码。但是不建议在onPageFinished函数中完成脚本的注入,因为执行到onPageFinished的时候页面已经加载完成了,这样的修改会导致界面有一个闪烁的变化的过程,我们有更好的方式来完成css和js的注入或者替换,下面会说到。

shouldInterceptRequest(WebView view, WebResourceRequest request)
Notify the host application of a resource request and allow the application to return the data.

重头戏来了,shouldInterceptRequest是在非UI线程中运行的,那么我们可以在这里做网络访问等耗时的操作。其次,网络的响应数据是在这里返回的,因此在这里进行处理就可以解决在onPageFinished中的闪烁问题。

@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);
}

在这里,我列举了两种方法,对返回的html进行css和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一直未起效。

原始的二维码界面:

经过css和js注入后的界面如下:

原始的授权界面:

注入css和js后的界面:

代码中我自定义了一个cssutil工具类,里面完成了关键代码如下:

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


/**
 * 描述:请求指定的url并返回html页字符串
 * 作者:LeoHo
 *
 * @param
 * @return
 * @throw
 */
private 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文件
 * 作者:LeoHo
 *
 * @param
 * @return
 * @throw
 */
private String buildCss(String css) {
    StringBuilder contents = new StringBuilder();

    InputStreamReader reader;
    try {
        reader = new InputStreamReader(mContext.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文件
 * 作者:LeoHo
 *
 * @param
 * @return
 * @throw
 */
private String buildJS(String jsPath) {
    StringBuilder contents = new StringBuilder();

    InputStreamReader reader;
    try {
        reader = new InputStreamReader(mContext.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代码
 * 作者:LeoHo
 *
 * @param
 * @return
 * @throw
 */
private 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;
}

深入探讨Android中WebView的JS交互技术 WebView是Android平台上的一个重要组件,允许应用程序显示网页内容。它不仅适用于显示网页,也是实现混合应用、嵌入式Web视图等场景的核心技术。开发者可以通过WebView加载本地的HTML文件或远程的Web资源,甚至可以与JavaScript交互,实现更丰富的用户体验。是Android WebView组件提供的一种方法,它允许你执行一段JavaScript代码,并可获得执行结果。与不同的是,能够异步执行JavaScript代码并处理返回值,这使得它在执行交互式脚本时更为高效。 阅读详情

相关推荐

Android WebView与PDF加载实战项目详解

参数推荐值说明data经过UTF-8编码的HTML字符串建议预处理转义特殊字符mimeType必须匹配实际内容类型encoding"UTF-8"或"base64"优先选用Base64提升兼容性⚠️ 特别提醒:自Android 7.0(API 24)起,loadData()已被标记为潜在安全隐患,因其可能绕过同源策略。生产环境中建议优先使用。

weixin_29781865的博客 1225

WebView注入JavaScript代码

应用需要统计网页打开情况,部分三方网页在网页跳转时无法在onPageFinished中监测到。使用代码注入在网页url发生变化时调用原生代码,传入新的url。

Noodles_ck的博客 1702

Android webview注入JS代码 修改网页内容操作

主要介绍了Android webview注入JS代码 修改网页内容操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

DoKit:一机多控WebView无侵入注入JS|滴滴开源

将滴滴技术设为“星标⭐️”第一时间收到文章更新导读自2018年正式对外开源以来,DoKit经历了五年的打磨,已经发展成一个相对完整的生态,支持六大平台(Android、iOS、Web、小程序、Flutter和PC),是滴滴开源委员会的精品孵化项目。在外部被众多头部企业广泛使用并获得了良好的口碑。在滴滴内部,DoKit已经在所有业务线和App中落地使用,基本覆盖所有日常开发和测试场景,提升了研发和质...

DiDi_Tech的博客 2877

傻瓜式下载、安装CentOS7操作步骤

CentOS7.9下载和安装操作步骤

weixin_45608163的博客 1万+

研发工作量科学量化评估模型:从多维系数到等级落地指南

摘要:本文提出了一套基于多维系数的科学量化评估模型,用于精准评估软件开发工作量。该模型从需求复杂度、技术难度、质量要求和依赖风险四个核心维度进行量化评估,通过系数乘积计算综合工作量。文章详细说明了各维度的系数区间划分标准,并演示了从基础工作量估算到综合系数计算的具体步骤。该模型通过结构化评估过程,将主观经验转化为客观量化指标,帮助团队提高工作量评估的准确性,增强项目交付的可预测性。其价值在于使评估过程透明化、结构化和可追溯,从而减少项目延期风险,优化资源规划。

友莘居士的博客 1684

android JS动态框架,Android WebView 动态注入 CSS 和 JavaScript

如何在 Android WebView 重动态加载页面和注入 CSS 和 JavaScript ?我们在开发过程中可能有这样的需求, 用一个 WebView 去加载网页的时候, 原来的网页里面的样式用安卓的WebView控件打开, 想改变原网页的样式为另外的一种样式, 这时候就可以采用这样的方法:主要使用了 Android WebView 这个类里面的一个函数:loadDataWithBaseUR...

weixin_30692969的博客 599

CCF201803-2 碰撞的小球 python

一些话:已经不知道是第几次做这道题了(大概第三次吧),真的常做常新,每次都有新的细节想法。虽然方法简单粗暴,但好在方便理解,对于我这种菜鸟选手而言。 但在做的过程中,最开始还忽略了输入的小球初始位置有可能是无序的,输出的时候要保持相对位置。CCF真的考验细节,希望上考场时能够认真仔细一点。就酱… #碰撞的小球 #当小球坐标为0或L时,会朝相反方向移动 #当两个小球坐标相等时,会分别转向相反的方向 #计算t秒之后小球的位置 n,L,t = map(int,input().split()) location .

tanya_dre的博客 351

通过css注入实现的android webview的夜间模式

一开始,产品跟我确认是否能够实现uc的夜间模式,我回答,当然可以,uc可以,我们也可以。 但是后来发现不是酱紫的,找了很多方法都不能做到uc那样,最后找到一些方法就是webview调用js、 当然,这个方案也不能做到像uc那样完美,但相对来说,勉勉强强,应该比调节亮度的应该要好些 原理就是在webview的加载结束,调用css代码,改变html页面的背景色、文字颜色、边框颜色等。

shuishuixiaoping的专栏 3665

QTableView为例:Qt模型视图委托(MVD)(Model-View-Delegate)

QT中的MVD(模型-视图-委托)模式是一种类似于MVC的设计模式,将数据、界面和交互逻辑分离。模型负责数据管理,视图负责显示界面,而委托则嵌入在视图中处理数据的显示和编辑。QT提供了多种视图组件(如QListView、QTreeView、QTableView)和模型类(如QStandardItemModel、QAbstractItemModel),支持数据的多样化呈现。委托(Delegate)通过定制显示和编辑行为增强了视图的灵活性。该模式适用于各类数据结构展示(列表、表格、树形),能够高效处理数据与界面

菜一头包的博客 1989

【OpenCV】复杂场景下的高精度圆检测实战(附完整代码)

本文针对OpenCV霍夫圆检测在复杂场景下易失效的问题,提出了一套基于轮廓分析的高精度圆检测实战方案。通过图像预处理、轮廓发现及多轮几何筛选(面积、周长、椭圆拟合、多边形逼近),有效排除噪声和类圆干扰物,显著提升复杂场景下的检测鲁棒性,并附完整可调参的Python代码实现。

weixin_29095587的博客 201

Android Webview(js与native互调)

Webview 前端相关知识: 同源策略: 当域名和端口名相同则称为同源 XMLHttpRequest 对象 可以在页面加载后与服务器进行收发包 可以只更新局部界面 跨域: 浏览器的同源策略导致了跨域 在浏览器中 不同来源的网站是不能相互访问 避免被随意修改内容 HTML 标签语言 用于设计网页的样式、内容 HTML5 新的第五代HTML规范 有<video 标签等 若网站使用了HTML5 ...

5ingwings(SiHao)的博客 6928

ROS四旋翼无人机快速上手指南(3):工作环境文件框架与各功能包整体讲解

这一章节主要讲解无人机平台的控制文件架构和各个功能包组成和用法。

The Road of Engineer 2406

Android Webview js或css 替换 注入

webview使用起来非常方便,但是由于过大的js或css使加载时间太长,体验不好,拦截js本地注入就是一个很好的解决办法。 wv_webview.getSettings().setJavaScriptEnabled(true); wv_webview.setWebViewClient(new WebViewClient(){ @Override public boolean

zhangxunxyy的博客 4093

osg点云加载与渲染

osg点云加载与渲染

cangqiongxiaoye的博客 821

扣子Coze工作流教程:采集公众号爆文,一键仿写自动发布

通过本教程,你学会了如何利用扣子(Coze)平台构建一个完整的公众号文章自动处理工作流。这个系统不仅能够大幅提升内容产出效率,还能通过AI二创保持内容新鲜度和原创性。最佳实践建议:初次使用时,建议先保存为草稿而不是直接发布,以便人工审核;从简单的工作流开始,逐步增加复杂度;定期检查工作流运行日志,优化节点配置。自动化内容创作是新媒体运营的未来趋势,掌握这项技能将使你在数字内容领域占据显著优势。

互联网架构师笔记 1238

WebView之修改页面JS、CSS

1、背景 混合开发在移动端已经火了很多年了,说起混合开发,就不得不提起Android的WebView,用WebView来加载html页面及进行交互也早已不再是什么新鲜事了,现在几乎每个App都或多或少采用了这种混合开发的方式,毕竟开发效率高,可适用于快速变更迭代的需求,同时在多端方面(Android,iOS,微信公众号,网站等)也极具优势。 2、场景及需求 场景1:WebView加载的是自己公司开发的html页面,但因种种原因,你不想去与前端工程师沟通修改一些CSS或JS文件时,我们如何通过原生的办法

5683

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

android webview js css,Android Webview通過Javascript注入CSS

而網頁不在本地。這是我試過的最新代碼。當我嘗試運行一切保持不變,我測試到CSS,它做我想做的。private void carregaCSS() {String extraStyles;extraStyles= "javascript: myfunction(){";extraStyles += " document.querySelectorAll('div.live-search-contai...

weixin_39687881的博客 184

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

如何用Robotium进行WebView测试:JavaScript注入与元素定位终极指南

Robotium是Android平台上功能强大的UI自动化测试框架,专门针对原生和混合应用提供完整的测试支持。在混合应用中,WebView测试常常是开发者的痛点,而Robotium通过JavaScript注入技术完美解决了这一难题。本文将详细介绍如何使用Robotium进行WebView测试,包括JavaScript注入和元素定位的核心方法。 ## 🎯 WebView测试的挑战与Robotiu

gitblog_00251的博客 358

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android WebView实战避坑指南:从白屏、412错误到JS交互全链路解析

WebView是Android中承载H5内容的核心组件,其本质是基于Chromium内核的轻量级浏览器引擎,具备HTML渲染、JavaScript执行与原生通信能力。由于Android系统版本迭代频繁,WebView在API行为、安全策略和线程模型上存在显著差异——例如`evaluateJavascript()`替代`loadUrl('javascript:')`、`@JavascriptInterface`强制注解、`file://`协议在Android 7.0+被默认拦截等。这些变化直接导致白屏、412

weixin_34318326的博客 785

Android WebView 深色模式适配方案总结

在 Android WebView 中适配深色模式(Dark Mode)是一个常见的需求,尤其是当加载的网页没有原生支持。通过 JavaScript 动态插入 CSS,强制修改网页的背景、文字颜色等样式。在 Android WebView 中实现深色模式,主要有。如果是第三方网页,JS 注入 CSS 是最稳妥的方案。,并分析它们的优缺点,帮助开发者选择最佳实现方式。,可让 WebView 自动适配深色模式。拦截 HTML/CSS,动态替换样式。如果你的网页可控,建议直接使用。

tangweiguo03051987的博客 1288

Android WebView 页面性能监控实现

在上一篇 Android WebView 开发使用笔记 中记录了WebView的一些使用方法以及注意事项,在这一篇,我将对WebView中页面资源加载以及JS错误的监控实现进行详细的介绍。 使用方法 首先贴一下代码 https://github.com/jwcqc/WebViewMonitor 核心其实就是 https://github.com/jwcqc/WebViewMonitor/

jwcqc的博客 6770

Android WebView 开发详解(一)

详细介绍Android WebView开发,介绍WebView开发各个注意事项及其解决方法。

typename 记录点滴 13万+

Android WebView常见问题及解决方案汇总

Android WebView常见问题及使用注意事项汇总 就目前而言,如何应对版本的频繁更新呢,又如何灵活多变地展示我们的界面呢,这又涉及到了web app与native app之间孰优孰劣的争论. 于是乎,一种混合型的app诞生了,灵活多变的部分,如淘宝商城首页的活动页面,一集凡客诚品中我们都可以见到web 页面与native页面的混合,既利用了web app的灵活易更新,也借助了native app本身的效率. 当然,就会用到webview这样的一个控件,这里,我把自己使用过程中遇到的一些问题整理下来:

Whatever is worth doing is worth doing well. 22万+

PakePlus-Android:原生WebView容器化架构与极简打包技术解析

PakePlus-Android是一款基于原生Android WebView容器技术的网页应用打包框架,通过创新的架构设计实现了将任意网页、HTML项目或前端应用(Vue/React等)快速转换为轻量级移动应用的解决方案。该框架面向需要将Web技术栈快速部署为移动应用的开发者,提供了完整的权限管理、JavaScript注入和跨平台适配能力。 ## 架构设计与技术选型分析 ### 原生WebVi

gitblog_00195的博客 845
上一篇: 在Android Service中弹出系统全屏对话框
leogray
博客等级 码龄20年 317粉丝 52原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值