Browse Source

Updated method for setting WebView proxy settings on Lollipop+.

Adam Kruger 6 năm trước cách đây
mục cha
commit
39c83a38da

+ 52 - 50
MobileLibrary/Android/SampleApps/TunneledWebView/app/src/main/java/ca/psiphon/tunneledwebview/WebViewProxySettings.java

@@ -19,10 +19,45 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 public class WebViewProxySettings 
 {
 
+    private static List<Object> getCurrentReceiversSet(Context ctx) {
+        Context appContext = ctx.getApplicationContext();
+        List<Object> receiversList = new ArrayList();
+
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+            return receiversList;
+        }
+
+        try {
+            Class applicationClass = Class.forName("android.app.Application");
+            Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
+            mLoadedApkField.setAccessible(true);
+            Object mloadedApk = mLoadedApkField.get(appContext);
+            Class loadedApkClass = Class.forName("android.app.LoadedApk");
+            Field mReceiversField = loadedApkClass.getDeclaredField("mReceivers");
+            mReceiversField.setAccessible(true);
+            ArrayMap receivers = (ArrayMap) mReceiversField.get(mloadedApk);
+            for (Object receiverMap : receivers.values()) {
+                for (Object receiver : ((ArrayMap) receiverMap).keySet()) {
+                    if (receiver == null) {
+                        continue;
+                    }
+                    receiversList.add(receiver);
+                }
+            }
+        } catch (ClassNotFoundException e) {
+        } catch (NoSuchFieldException e) {
+        } catch (IllegalAccessException e) {
+        }
+
+        return receiversList;
+    }
+
     public static void setLocalProxy(Context ctx, int port)
     {
         setProxy(ctx, "localhost", port);
@@ -131,36 +166,22 @@ public class WebViewProxySettings
         System.setProperty("https.proxyPort", port + "");
         try
         {
-            Class applicationClass = Class.forName("android.app.Application");
-            Field loadedApkField = applicationClass.getDeclaredField("mLoadedApk");
-            loadedApkField.setAccessible(true);
-            Object loadedApk = loadedApkField.get(appContext);
-            Class loadedApkClass = Class.forName("android.app.LoadedApk");
-            Field receiversField = loadedApkClass.getDeclaredField("mReceivers");
-            receiversField.setAccessible(true);
-            ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
-            for (Object receiverMap : receivers.values())
+            for (Object receiver : getCurrentReceiversSet(appContext))
             {
-                for (Object receiver : ((ArrayMap) receiverMap).keySet())
+                Class receiverClass = receiver.getClass();
+                if (receiverClass.getName().contains("ProxyChangeListener"))
                 {
-                    if (receiver == null) {
-                        continue;
-                    }
-                    Class receiverClass = receiver.getClass();
-                    if (receiverClass.getName().contains("ProxyChangeListener"))
-                    {
-                        Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
-                        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+                    Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
+                    Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
 
-                        final String CLASS_NAME = "android.net.ProxyProperties";
-                        Class proxyPropertiesClass = Class.forName(CLASS_NAME);
-                        Constructor constructor = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE, String.class);
-                        constructor.setAccessible(true);
-                        Object proxyProperties = constructor.newInstance(host, port, null);
-                        intent.putExtra("proxy", (Parcelable) proxyProperties);
+                    final String CLASS_NAME = "android.net.ProxyProperties";
+                    Class proxyPropertiesClass = Class.forName(CLASS_NAME);
+                    Constructor constructor = proxyPropertiesClass.getConstructor(String.class, Integer.TYPE, String.class);
+                    constructor.setAccessible(true);
+                    Object proxyProperties = constructor.newInstance(host, port, null);
+                    intent.putExtra("proxy", (Parcelable) proxyProperties);
 
-                        onReceiveMethod.invoke(receiver, appContext, intent);
-                    }
+                    onReceiveMethod.invoke(receiver, appContext, intent);
                 }
             }
             return true;
@@ -168,9 +189,6 @@ public class WebViewProxySettings
         catch (ClassNotFoundException e)
         {
         }
-        catch (NoSuchFieldException e)
-        {
-        }
         catch (IllegalAccessException e)
         {
         }
@@ -199,26 +217,13 @@ public class WebViewProxySettings
         System.setProperty("https.proxyHost", host);
         System.setProperty("https.proxyPort", port + "");
         try {
-            Class applictionClass = Class.forName("android.app.Application");
-            Field mLoadedApkField = applictionClass.getDeclaredField("mLoadedApk");
-            mLoadedApkField.setAccessible(true);
-            Object mloadedApk = mLoadedApkField.get(appContext);
-            Class loadedApkClass = Class.forName("android.app.LoadedApk");
-            Field mReceiversField = loadedApkClass.getDeclaredField("mReceivers");
-            mReceiversField.setAccessible(true);
-            ArrayMap receivers = (ArrayMap) mReceiversField.get(mloadedApk);
-            for (Object receiverMap : receivers.values())
+            for (Object receiver : getCurrentReceiversSet(appContext))
             {
-                for (Object receiver : ((ArrayMap) receiverMap).keySet())
+                Class receiverClass = receiver.getClass();
+                String receiverName = receiverClass.getCanonicalName();
+                if (receiverName != null && receiverName.contains("ProxyChangeListener"))
                 {
-                    if (receiver == null) {
-                        continue;
-                    }
-                    Class clazz = receiver.getClass();
-                    // NOTE: as of Chrome 67 the ProxyChangeListener now has an obfuscated name,
-                    // so we are unable to identify the receiver by name. Instead we'll send the
-                    // PROXY_CHANGE intent to all receivers.
-                    Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class, Intent.class);
+                    Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
                     Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
                     
                     final String CLASS_NAME = "android.net.ProxyInfo";
@@ -240,9 +245,6 @@ public class WebViewProxySettings
         catch (ClassNotFoundException e)
         {
         }
-        catch (NoSuchFieldException e)
-        {
-        }
         catch (IllegalAccessException e)
         {
         }