android 解决系统级应用 WebView 加载崩溃的问题

想必大家在开发系统应用的过程中用到 WebView 的地方可能会遇到这样的加载崩溃问题

less 复制代码
Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes

at android.webkit.WebViewFactory.getProvider([WebViewFactory.java:235](http://webviewfactory.java:235/))

at android.webkit.WebView.getFactory([WebView.java:2681](http://webview.java:2681/))

at android.webkit.WebView.ensureProviderCreated([WebView.java:2676](http://webview.java:2676/))

at android.webkit.WebView.setOverScrollMode([WebView.java:2741](http://webview.java:2741/))

at android.view.View.<init>([View.java:4821](http://view.java:4821/))

at android.view.View.<init>([View.java:4962](http://view.java:4962/))

at android.view.ViewGroup.<init>([ViewGroup.java:660](http://viewgroup.java:660/))

at android.widget.AbsoluteLayout.<init>([AbsoluteLayout.java:55](http://absolutelayout.java:55/))

at android.webkit.WebView.<init>([WebView.java:659](http://webview.java:659/))

at android.webkit.WebView.<init>([WebView.java:604](http://webview.java:604/))

at android.webkit.WebView.<init>([WebView.java:587](http://webview.java:587/))

at android.webkit.WebView.<init>([WebView.java:574](http://webview.java:574/))

这是因为首次使用时,系统会进行检查,如果 UID 是 root 进程或者系统进程,直接抛出异常。sProviderInstance 是 WebViewFactoryProvider 的对象,主要提供创建 WebView 内核的机制。WebView在 Android 4.4 之前使用的是 Webkit 内核,在 Android 4.4 以后切换到了 Chromium 内核。Google 使用了工厂方法模式,优雅地切换 WebView 内核的实现方式。我们注意到只有 sProviderInstance 为空的时候系统才去检查进程,然后创建 sProviderInstance对象。所以这给了我们一个启发 ---- 能不能一开始就主动创建 sProviderInstance 对象,把她塞到 WebViewFactory 类里面,从而欺骗 API 绕过系统检查呢?

下面就要用到 Hook 的思想了,首先要找到一个合适的点,静态变量、单例是最佳选择,刚刚好 sProviderInstance 是静态的。那就开始拿它开刀,看看系统是怎么创建 sProviderInstance 的,我们自己也模仿它这么做。其实系统也是通过反射来做的

java 复制代码
import android.annotation.SuppressLint;
import android.os.Build;

import com.atoto.utils.log.AtotoLogger;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 描述:
 * 创建者: IT 乐手
 * 日期: 2025/4/25
 */

public class WebViewCompat {

    private final static String TAG = "WebViewCompat";

    @SuppressLint("SoonBlockedPrivateApi")
    public static void hookWebView() {

        int sdkInt = Build.VERSION.SDK_INT;
        try {
            Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
            Field field = factoryClass.getDeclaredField("sProviderInstance");
            field.setAccessible(true);
            Object sProviderInstance = field.get(null);

            if (sProviderInstance != null) {
                AtotoLogger.i(TAG, "sProviderInstance isn't null");
                return;
            }

            Method getProviderClassMethod;

            if (sdkInt > 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
            } else if (sdkInt == 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
            } else {
                AtotoLogger.i(TAG, "Don't need to Hook WebView");
                return;
            }
            getProviderClassMethod.setAccessible(true);
            Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
            Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
            Constructor delegateConstructor = delegateClass.getDeclaredConstructor();
            delegateConstructor.setAccessible(true);


            Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
            chromiumMethodName.setAccessible(true);
            String chromiumMethodNameStr = (String) chromiumMethodName.get(null);
            AtotoLogger.i(TAG, "chromiumMethodNameStr: " + chromiumMethodNameStr);
            if (chromiumMethodNameStr == null) {
                chromiumMethodNameStr = "create";
            }
            Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
            if (staticFactory != null) {
                sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
            }

            if (sProviderInstance != null) {
                field.set("sProviderInstance", sProviderInstance);
                AtotoLogger.i(TAG, "Hook success!");
            } else {
                AtotoLogger.i(TAG, "Hook failed!");
            }
        } catch (Throwable e) {
            AtotoLogger.printException(TAG, e);
        }
    }
}

在实例化使用 WebView 前调用即可

java 复制代码
hookWebView();
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.webview);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl("http://www.baidu.com");
相关推荐
消失的旧时光-194326 分钟前
Android 系统层扫盲 09:AMS、ATMS、WMS、PMS 到底分别管什么?
android·wms·pms·ams·aosp·atms
Godikov42 分钟前
Android 系统级设备应用踩坑实录:sharedUserId 签名、SDK 授权失败 -4、开机自启与 U 盘 OTA 升级
android
IT毕设实战小研4 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
企业数字化笔记5 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端
龙之叶5 小时前
Android出海系列-GMS认证介绍
android
潮族大Z5 小时前
Android性能优化:启动、内存、卡顿的一站式排查手册
android
事圆则缓7 小时前
从suspend字节码到 Retrofit 协程桥:挂起函数识别与恢复
android·retrofit
杉氧8 小时前
RN 性能调优指南:重渲染(Re-renders)控制与长列表(FlatList)优化
android·前端·react native
Coffeeee8 小时前
claude-video 一个让你的Agent拥有看视频能力的Skill
android·人工智能·aigc
菜鸟~noob23310 小时前
【电子战】第07篇:多普勒测向【含matlab代码】
android·开发语言·matlab