原文地址


1.问题起源

报错语句是:java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
因难以避免WebView存在安全漏洞,系统遭受攻击,Android不允许特权进程应用使用WebView。如果使用了,便会抛出以上异常。
特权进程包括sharedUserId为ROOT_UID和SYSTEM_UID的进程,从Android O(8.0)开始共享PHONE_UID、NFC_UID、BLUETOOTH_UID的进程也属于特权进程。
如果不幸,你的应用共享了以上的UserId,又有使用WebView,将会Crash掉,并抛出异常。下面提供一种Hook代码的方法,可以不用修改sharedUserId且避免Crash。
不过为了安全起见,还是不建议在Google规定的特权进程里继续使用WebView。下面提供的方案仅供不方便很快去掉WebView,临时避免Crash使用。

2.解决方法

请自行搜索了解为什么会想起这样解决,我是分析了Android8.0 frameworks源码,对网上的方法进行了改进,以使其在Android 8.0(SDK版本号为26)上使用.
在你的Application OnCreate方法里调用下面的方法即可。

  1. public static void hookWebView(){
  2. int sdkInt = Build.VERSION.SDK_INT;
  3. try {
  4. Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
  5. Field field = factoryClass.getDeclaredField("sProviderInstance");
  6. field.setAccessible(true);
  7. Object sProviderInstance = field.get(null);
  8. if (sProviderInstance != null) {
  9. Log.i(TAG,"sProviderInstance isn't null");
  10. return;
  11. }
  12. Method getProviderClassMethod;
  13. if (sdkInt > 22) {
  14. getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
  15. } else if (sdkInt == 22) {
  16. getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
  17. } else {
  18. Log.i(TAG,"Don't need to Hook WebView");
  19. return;
  20. }
  21. getProviderClassMethod.setAccessible(true);
  22. Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
  23. Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
  24. Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor();
  25. delegateConstructor.setAccessible(true);
  26. if(sdkInt < 26){//低于Android O版本
  27. Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass);
  28. if (providerConstructor != null) {
  29. providerConstructor.setAccessible(true);
  30. sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
  31. }
  32. } else {
  33. Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
  34. chromiumMethodName.setAccessible(true);
  35. String chromiumMethodNameStr = (String)chromiumMethodName.get(null);
  36. if (chromiumMethodNameStr == null) {
  37. chromiumMethodNameStr = "create";
  38. }
  39. Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
  40. if (staticFactory!=null){
  41. sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
  42. }
  43. }
  44. if (sProviderInstance != null){
  45. field.set("sProviderInstance", sProviderInstance);
  46. Log.i(TAG,"Hook success!");
  47. } else {
  48. Log.i(TAG,"Hook failed!");
  49. }
  50. } catch (Throwable e) {
  51. Log.w(TAG,e);
  52. }
  53. }