2019-05-24 15:13:28 +02:00
|
|
|
package app.fedilab.android.webview;
|
|
|
|
/* Copyright 2019 Thomas Schneider
|
|
|
|
*
|
|
|
|
* This file is a part of Fedilab
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
|
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
|
|
* Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
|
|
|
* see <http://www.gnu.org/licenses>. */
|
2019-09-06 17:55:14 +02:00
|
|
|
|
2019-05-24 15:13:28 +02:00
|
|
|
import android.annotation.SuppressLint;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.net.Proxy;
|
|
|
|
import android.util.ArrayMap;
|
|
|
|
|
|
|
|
import java.lang.reflect.Constructor;
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
|
|
|
public class ProxyHelper {
|
|
|
|
|
|
|
|
|
2020-04-25 11:18:42 +02:00
|
|
|
public static void setProxy(Context context, CustomWebview webview, String host, int port, String applicationClassName) {
|
2019-05-24 15:13:28 +02:00
|
|
|
|
2020-02-02 12:08:11 +01:00
|
|
|
setProxyKKPlus(context, webview, host, port, applicationClassName);
|
2019-05-24 15:13:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("all")
|
2020-04-25 11:18:42 +02:00
|
|
|
private static boolean setProxyICS(CustomWebview webview, String host, int port) {
|
2019-09-06 17:55:14 +02:00
|
|
|
try {
|
2019-05-24 15:13:28 +02:00
|
|
|
Class jwcjb = Class.forName("android.webkit.JWebCoreJavaBridge");
|
|
|
|
Class params[] = new Class[1];
|
|
|
|
params[0] = Class.forName("android.net.ProxyProperties");
|
|
|
|
Method updateProxyInstance = jwcjb.getDeclaredMethod("updateProxy", params);
|
|
|
|
|
|
|
|
Class wv = Class.forName("android.webkit.WebView");
|
|
|
|
Field mWebViewCoreField = wv.getDeclaredField("mWebViewCore");
|
|
|
|
Object mWebViewCoreFieldInstance = getFieldValueSafely(mWebViewCoreField, webview);
|
|
|
|
|
|
|
|
Class wvc = Class.forName("android.webkit.WebViewCore");
|
|
|
|
Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");
|
|
|
|
Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldInstance);
|
|
|
|
|
|
|
|
Class bf = Class.forName("android.webkit.BrowserFrame");
|
|
|
|
Field sJavaBridgeField = bf.getDeclaredField("sJavaBridge");
|
|
|
|
Object sJavaBridge = getFieldValueSafely(sJavaBridgeField, mBrowserFrame);
|
|
|
|
|
|
|
|
Class ppclass = Class.forName("android.net.ProxyProperties");
|
|
|
|
Class pparams[] = new Class[3];
|
|
|
|
pparams[0] = String.class;
|
|
|
|
pparams[1] = int.class;
|
|
|
|
pparams[2] = String.class;
|
|
|
|
Constructor ppcont = ppclass.getConstructor(pparams);
|
|
|
|
|
|
|
|
updateProxyInstance.invoke(sJavaBridge, ppcont.newInstance(host, port, null));
|
|
|
|
return true;
|
2019-09-06 17:55:14 +02:00
|
|
|
} catch (Exception ex) {
|
2019-05-24 15:13:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set Proxy for Android 4.1 - 4.3.
|
|
|
|
*/
|
|
|
|
@SuppressWarnings("all")
|
2020-04-25 11:18:42 +02:00
|
|
|
private static boolean setProxyJB(CustomWebview webview, String host, int port) {
|
2019-05-24 15:13:28 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
Class wvcClass = Class.forName("android.webkit.WebViewClassic");
|
|
|
|
Class wvParams[] = new Class[1];
|
|
|
|
wvParams[0] = Class.forName("android.webkit.WebView");
|
|
|
|
Method fromWebView = wvcClass.getDeclaredMethod("fromWebView", wvParams);
|
|
|
|
Object webViewClassic = fromWebView.invoke(null, webview);
|
|
|
|
|
|
|
|
Class wv = Class.forName("android.webkit.WebViewClassic");
|
|
|
|
Field mWebViewCoreField = wv.getDeclaredField("mWebViewCore");
|
|
|
|
Object mWebViewCoreFieldInstance = getFieldValueSafely(mWebViewCoreField, webViewClassic);
|
|
|
|
|
|
|
|
Class wvc = Class.forName("android.webkit.WebViewCore");
|
|
|
|
Field mBrowserFrameField = wvc.getDeclaredField("mBrowserFrame");
|
|
|
|
Object mBrowserFrame = getFieldValueSafely(mBrowserFrameField, mWebViewCoreFieldInstance);
|
|
|
|
|
|
|
|
Class bf = Class.forName("android.webkit.BrowserFrame");
|
|
|
|
Field sJavaBridgeField = bf.getDeclaredField("sJavaBridge");
|
|
|
|
Object sJavaBridge = getFieldValueSafely(sJavaBridgeField, mBrowserFrame);
|
|
|
|
|
|
|
|
Class ppclass = Class.forName("android.net.ProxyProperties");
|
|
|
|
Class pparams[] = new Class[3];
|
|
|
|
pparams[0] = String.class;
|
|
|
|
pparams[1] = int.class;
|
|
|
|
pparams[2] = String.class;
|
|
|
|
Constructor ppcont = ppclass.getConstructor(pparams);
|
|
|
|
|
|
|
|
Class jwcjb = Class.forName("android.webkit.JWebCoreJavaBridge");
|
|
|
|
Class params[] = new Class[1];
|
|
|
|
params[0] = Class.forName("android.net.ProxyProperties");
|
|
|
|
Method updateProxyInstance = jwcjb.getDeclaredMethod("updateProxy", params);
|
|
|
|
|
|
|
|
updateProxyInstance.invoke(sJavaBridge, ppcont.newInstance(host, port, null));
|
|
|
|
} catch (Exception ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// from https://stackoverflow.com/questions/19979578/android-webview-set-proxy-programatically-kitkat
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
@SuppressWarnings("all")
|
2020-04-25 11:18:42 +02:00
|
|
|
private static void setProxyKKPlus(Context appContext, CustomWebview webView, String host, int port, String applicationClassName) {
|
2019-05-24 15:13:28 +02:00
|
|
|
|
|
|
|
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("android.app.Application");
|
|
|
|
Field loadedApkField = applictionCls.getDeclaredField("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(Proxy.PROXY_CHANGE_ACTION);
|
|
|
|
|
|
|
|
onReceiveMethod.invoke(rec, appContext, intent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchFieldException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchMethodException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvocationTargetException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Object getFieldValueSafely(Field field, Object classInstance) throws IllegalArgumentException, IllegalAccessException {
|
|
|
|
boolean oldAccessibleValue = field.isAccessible();
|
|
|
|
field.setAccessible(true);
|
|
|
|
Object result = field.get(classInstance);
|
|
|
|
field.setAccessible(oldAccessibleValue);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|