wushaominkk 发表于 2019-7-18 11:25

解决Android8.0系统应用打开webView报错

由于webView存在安全漏洞,谷歌从5.1开始全面禁止系统应用使用webview,使用会导致应用崩溃错误提示:Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
异常信息可以看出 是在 WebViewFactory.java 的getProvider 方法 抛出的。源码路径为
frameworks/base/core/java/android/webkit/WebViewFactory.java
static WebViewFactoryProvider getProvider() {
      synchronized (sProviderLock) {
            // For now the main purpose of this function (and the factory abstraction) is to keep
            // us honest and minimize usage of WebView internals when binding the proxy.
            if (sProviderInstance != null) return sProviderInstance; //如果sProviderInstance不为空直接返回
            
          //1,判断,如果是系统id ,则抛出异常。
            final int uid = android.os.Process.myUid();
            if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
                throw new UnsupportedOperationException(
                        "For security reasons, WebView is not allowed in privileged processes");
            }

            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
            try {
                //2
                Class<WebViewFactoryProvider> providerClass = getProviderClass();

                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
                try {
                  //3 给 sProviderInstance 赋值
                  sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
                            .newInstance(new WebViewDelegate());
                  if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                  return sProviderInstance;
                } catch (Exception e) {
                  Log.e(LOGTAG, "error instantiating provider", e);
                  throw new AndroidRuntimeException(e);
                } finally {
                  Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                }
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
                StrictMode.setThreadPolicy(oldPolicy);
            }
      }
    }

如果是系统id,就抛出异常!
可以通过反射在调用webview 之前,给sProviderInstance 赋值,这样就可以了
在Application调用方法,兼容8.0
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) {
      Log.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 {
      Log.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);
      if(sdkInt < 26){//低于Android O版本
      Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass);
      if (providerConstructor != null) {
          providerConstructor.setAccessible(true);
          sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
      }
      } else {
      Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
      chromiumMethodName.setAccessible(true);
      String chromiumMethodNameStr = (String)chromiumMethodName.get(null);
      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);
      Log.i(TAG,"Hook success!");
      } else {
      Log.i(TAG,"Hook failed!");
      }
    } catch (Throwable e) {
      Log.w(TAG,e);
    }
}


Quincy379 发表于 2019-7-18 12:10

{:301_987:}可以的,感谢分享!

逆向学习 发表于 2019-7-25 18:10

感谢分享

RickoNoNo3 发表于 2019-7-25 23:41

最近开发瓶颈确实在安卓高版本的WebView上,找了半天没找到解决方案,差点上X5了……
有了这个办法可以暂时先绕过这个问题了~

dawancha2020 发表于 2020-4-8 23:10

有帮助,谢谢楼主分享

jiale625 发表于 2021-5-14 16:57

页: [1]
查看完整版本: 解决Android8.0系统应用打开webView报错