最近在做项目时,遇到了一个无法使用webView的问题,apk是系统应用,点击加载webView时应用就是崩溃,原因是系统应用时,Android会觉得webView不安全,不避让加载。
解决的思路就是使用映射,把原生的拦截设置为ture,不让系统拦截。
设置hook代码如下
public static void hookWebView() {
Log.i(TAG, "==hookWebView start==");
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;
getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
getProviderClassMethod.setAccessible(true);
Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor();
delegateConstructor.setAccessible(true);
@SuppressLint("SoonBlockedPrivateApi") 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!");
isHookSuccess = true;
} else {
Log.i(TAG, "Hook failed!");
isHookSuccess = false;
}
} catch (Throwable e) {
Log.w(TAG, e);
}
}
此方法还需要时机,如果加载太晚或者太早也会不生效,要在Android原生设置属性前,并且isUserUnlocked后调用。
我本项目是在三个地方多次调用了
1、第一个地方是Myapplication的onCreate方法里面并判断了isUserUnlocked
boolean isUserUnlock = getSystemService(UserManager.class).isUserUnlocked();
if (isUserUnlock) {
Myapplication.hookWebView();
}
2、在MainActivity的onCreate方法里面
if (!Myapplication.isHookSuccess) {
Myapplication.hookWebView();
}
3、在开机广播里面
public class ReceiverLocalSetting extends BroadcastReceiver {
private static final String TAG = "ReceiverLocalSetting";
private static final String USER_UNLOCKED_ACTION = "android.intent.action.USER_UNLOCKED";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "==onReceive==");
if (!Myapplication.isHookSuccess) {
Myapplication.hookWebView();
}
}
}
}
以上就是解决的思路和方法,留着以后备用。