问题起源:
当我们申请我们的app为系统应用,也就是当我们在AndroidManifest文件中添加
android:sharedUserId=""
这一行的时候,如果我们使用webView就会报错:For security reasons, WebView is not allowed in privileged processes。
这个是8.0代码中的一种安全机制。
网上查找资料,解决方案都是通过Hook技术根本思想是在异常发生前就给sProviderInstance赋值,因为在getProvider方法中当判断这个值不为空就直接返回了就不会抛异常了
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;
final int uid = ();
if (uid == .ROOT_UID || uid == .SYSTEM_UID
|| uid == .PHONE_UID || uid == .NFC_UID
|| uid == .BLUETOOTH_UID) {
throw new UnsupportedOperationException(
"For security reasons, WebView is not allowed in privileged processes");
}
oldPolicy = ();
(Trace.TRACE_TAG_WEBVIEW, "()");
try {
Class<WebViewFactoryProvider> providerClass = getProviderClass();
Method staticFactory = null;
try {
staticFactory = (
CHROMIUM_WEBVIEW_FACTORY_METHOD, );
} catch (Exception e) {
if (DEBUG) {
(LOGTAG, "error instantiating provider with static factory method", e);
}
}
(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
try {
sProviderInstance = (WebViewFactoryProvider)
(null, new WebViewDelegate());
if (DEBUG) (LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
(LOGTAG, "error instantiating provider", e);
throw new AndroidRuntimeException(e);
} finally {
(Trace.TRACE_TAG_WEBVIEW);
}
} finally {
(Trace.TRACE_TAG_WEBVIEW);
(oldPolicy);
}
}
}
通过源码可以看到这一行代码if (sProviderInstance != null) return sProviderInstance; 紧接着就有抛异常的代码。
所以我们要让sProviderInstance不为空。
网上查找反射方法,发现了良好总方案:
方案一:
public static void hookWebView() {
int sdkInt = .SDK_INT;
try {
Class<?> factoryClass = ("");
Field field = ("sProviderInstance");
(true);
Object sProviderInstance = (null);
if (sProviderInstance != null) {
("sProviderInstance isn't null");
return;
}
Method getProviderClassMethod;
if (sdkInt > 22) {
getProviderClassMethod = ("getProviderClass");
} else if (sdkInt == 22) {
getProviderClassMethod = ("getFactoryClass");
} else {
("Don't need to Hook WebView");
return;
}
(true);
Class<?> providerClass = (Class<?>) (factoryClass);
Class<?> delegateClass = ("");
Constructor<?> providerConstructor = (delegateClass);
if (providerConstructor != null) {
(true);
Constructor<?> declaredConstructor = ();
(true);
sProviderInstance = (());
("sProviderInstance:{}", sProviderInstance);
("sProviderInstance", sProviderInstance);
}
("Hook done!");
} catch (Throwable e) {
(e);
}
搜索了好多博客都是这个答案,于是兴致勃勃的cv打法一顿操作,但是发现当执行到
Constructor<?> providerConstructor = (delegateClass);
这一行代码的时候必然会报NoSuchMethod的错误,仔细看了一下frameWork代码,发现WebViewFactoryProvider这个类是个借口类,里面没有构造方法,自然会报这个错误。
又是一通百度,终于找打了另一种hook方案:
方案2:
private static String TAG = "hookWebView";
public static void hookWebView(){
int sdkInt = .SDK_INT;
try {
Class<?> factoryClass = ("");
Field field = ("sProviderInstance");
(true);
Object sProviderInstance = (null);
if (sProviderInstance != null) {
(TAG,"sProviderInstance isn't null");
return;
}
Method getProviderClassMethod;
if (sdkInt > 22) {
getProviderClassMethod = ("getProviderClass");
} else if (sdkInt == 22) {
getProviderClassMethod = ("getFactoryClass");
} else {
(TAG,"Don't need to Hook WebView");
return;
}
(true);
Class<?> factoryProviderClass = (Class<?>) (factoryClass);
Class<?> delegateClass = ("");
Constructor<?> delegateConstructor = ();
(true);
if(sdkInt < 26){//低于Android O版本
Constructor<?> providerConstructor = (delegateClass);
if (providerConstructor != null) {
(true);
sProviderInstance = (());
}
} else {
Field chromiumMethodName = ("CHROMIUM_WEBVIEW_FACTORY_METHOD");
(true);
String chromiumMethodNameStr = (String)(null);
if (chromiumMethodNameStr == null) {
chromiumMethodNameStr = "create";
}
Method staticFactory = (chromiumMethodNameStr, delegateClass);
if (staticFactory!=null){
sProviderInstance = (null, ());
}
}
if (sProviderInstance != null){
("sProviderInstance", sProviderInstance);
(TAG,"Hook success!");
} else {
(TAG,"Hook failed!");
}
} catch (Throwable e) {
(TAG,e);
}
}
这个方案完美的解决了这个问题。因为中间做了一次判断,判断是低于o版本还是高于o版本。
然后我只要在Activity的oncreate方法中调用就行了,切记一定要在setContentView之前调用,或者在webVIew创建之前调用,不然还是会报错的。
方案2转自:/68xi/p/