采得百花成蜜后,为谁辛苦为谁甜。这篇文章主要讲述上次更新Android System Webview后,代理设置停止工作相关的知识,希望能为你提供帮助。
在android System Webview的最后一次更新(2018年5月30日)之后,代理设置停止了为我工作,代理不再适用于webview。在其他具有代理的浏览器中,它具有相同的效果,代理不设置,阻止的网站无法打开,ip不会更改。返回的错误是主机无解析器或连接失败。我的设备是Nexus 5X,Android 8.1.0。其他人是否面临同样的问题?
我用它来设置代理:
private static boolean setProxyKKPlus(WebView webView, String host, int port, String applicationClassName) {
Log.d(LOG_TAG, "Setting proxy with >
= 4.4 API.");
Context appContext = webView.getContext().getApplicationContext();
System.setProperty("http.proxyHost", host);
System.setProperty("http.proxyPort", port + "");
System.setProperty("https.proxyHost", host);
System.setProperty("https.proxyPort", port + "");
try {
Class applictionCls = Class.forName(applicationClassName);
Field loadedApkField = applictionCls.getField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(appContext);
Class loadedApkCls = Class.forName("android.app.LoadedApk");
Field receiversField = loadedApkCls.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
for (Object rec : ((ArrayMap) receiverMap).keySet()) {
Class clazz = rec.getClass();
if (clazz.getName().contains("ProxyChangeListener")) {
Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
Intent intent = new Intent("android.intent.action.PROXY_CHANGE");
onReceiveMethod.invoke(rec, appContext, intent);
}
}
}Log.d(LOG_TAG, "Setting proxy with >
= 4.4 API successful!");
return true;
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Log.v(LOG_TAG, e.getMessage());
Log.v(LOG_TAG, exceptionAsString);
}
return false;
}
答案【上次更新Android System Webview后,代理设置停止工作】此代码适用于我的环境(Chrome 67 + Android 7.0)
for (Object receiverMap : receivers.values()) {
for (Object rec : ((ArrayMap) receiverMap).keySet()) {
Class clazz = rec.getClass();
boolean targetReceiverFound = false;
if (clazz.getName().contains("ProxyChangeListener")) {
targetReceiverFound = true;
} else {
final Field[] obfuscatedFields = clazz.getDeclaredFields();
for (Field f : obfuscatedFields) {
if (f.getType().getName().contains("ProxyChangeListener")) {
targetReceiverFound = true;
break;
}
}
}if (targetReceiverFound) {
// invoke onReceive() here
}
}
}
另一答案为了扩展@Anmerris提供的答案,以下是一个适合我的完整代码集。我使用WebView 30.0.0.0到67.0.3396.87对API 19到27进行了测试。
public static void setProxy(Context context, String proxyHost, String proxyPort) {
// Set the proxy values
System.setProperty("http.proxyHost", proxyHost);
System.setProperty("http.proxyPort", proxyPort);
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", proxyPort);
// Use reflection to apply the new proxy values.
try {
// Get the application and APK classes.Suppress the lint warning that reflection may not always work in the future and on all devices.
Class applicationClass = Class.forName("android.app.Application");
@SuppressLint("PrivateApi") Class loadedApkClass = Class.forName("android.app.LoadedApk");
// Get the declared fields.Suppress the lint warning that `mLoadedApk` cannot be resolved.
@SuppressWarnings("javaReflectionMemberAccess") Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
Field mReceiversField = loadedApkClass.getDeclaredField("mReceivers");
// Allow the values to be changed.
mLoadedApkField.setAccessible(true);
mReceiversField.setAccessible(true);
// Get the APK object.
Object mLoadedApkObject = mLoadedApkField.get(context);
// Get an array map of the receivers.
ArrayMap receivers = (ArrayMap) mReceiversField.get(mLoadedApkObject);
// Set the proxy.
for (Object receiverMap : receivers.values()) {
for (Object receiver : ((ArrayMap) receiverMap).keySet()) {
// `Class<
?>
`, which is an `unbounded wildcard parameterized type`, must be used instead of `Class`, which is a `raw type`.Otherwise, `receiveClass.getDeclaredMethod` is unhappy.
Class<
?>
receiverClass = receiver.getClass();
// Get the declared fields.
final Field[] declaredFieldArray = receiverClass.getDeclaredFields();
// Set the proxy for each field that is a `ProxyChangeListener`.
for (Field field : declaredFieldArray) {
if (field.getType().getName().contains("ProxyChangeListener")) {
Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
onReceiveMethod.invoke(receiver, context, intent);
}
}
}
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) {
Log.d("enableProxyThroughOrbot", "Exception: " + exception);
}
}
推荐阅读
- Android浮动按钮和高级webview不起作用
- 将Playbuzz加载脚本加载到Android中的WebView中
- 如何使用java在appium中垂直滚动混合应用程序
- 原生Android Webview HTML5兼容性
- 让Facebook登录使用Android Webview
- WebView得到致命(jni_android.cc(233)]错误)
- 在WebView Android应用程序中推送通知
- React Native WebView处理android硬件按钮
- 当URL相似时,Android WebView canGoBack()返回false