6

我知道 android.net.VpnService 基本上是构建自定义 vpn 解决方案的基类,但我想要的只是创建和使用 PPTP 或 L2TP VPN 连接(只是内置 VPN 管理器的新配置文件)。我认为最简单的方法是对 com.android.settings.vpn.VpnSettings 使用 Java 反射。这是另一篇文章中的代码片段(如何将自己的 VPN 设置添加到系统 VPN 设置页面?

package com.nikola.despotoski.whatever;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class VpnSetter {

    private static Map<String , Class<?>> getMappedFields(){
        Map<String , Class<?>> fieldsAndTypes = new HashMap<String, Class<?>>();
        fieldsAndTypes.put("name", String.class);        // 0
        fieldsAndTypes.put("type" , int.class);   // 1
        fieldsAndTypes.put("server", String.class);        // 2
        fieldsAndTypes.put("username", String.class);
        fieldsAndTypes.put("password", String.class);
        fieldsAndTypes.put("dnsServers", String.class);
        fieldsAndTypes.put("searchDomains", String.class);
        fieldsAndTypes.put("routes", String.class);
        fieldsAndTypes.put("mppe", boolean.class);
        fieldsAndTypes.put("l2tpSecret", String.class);
        fieldsAndTypes.put("ipsecIdentifier", String.class);
        fieldsAndTypes.put("ipsecSecret", String.class);
        fieldsAndTypes.put("ipsecUserCert", String.class);
        fieldsAndTypes.put("ipsecCaCert", String.class);
        fieldsAndTypes.put("saveLogin", boolean.class);
        return fieldsAndTypes;
    }
    public static final Set<String> VPN_PROFILE_KEYS = getMappedFields().keySet(); // contains keys for quicker generation of key-value map for each 

    public static void addVpnProfile(String vpnProfileKey, Map<String, Object> values) throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException{
        Class<?> vpnSettings = Class.forName("com.android.settings.vpn2.VpnSettings");
        Class<?>[] privateVpnSettingsClasses = vpnSettings.getDeclaredClasses();
        Class<?> vpnPreference = null;
        Class<?> vpnProfileClass = Class.forName("com.android.settings.vpn2.VpnProfile");
        for(Class<?> priv :privateVpnSettingsClasses ){
            if(priv.getName().equals("VpnPreference")){
                vpnPreference = priv;
                break;
            }
        }
        Field vpnProfileFromVpnPreferenceField = vpnPreference.getDeclaredField("mProfile");
        vpnProfileFromVpnPreferenceField.setAccessible(true);
        Object vpnProfile = vpnProfileFromVpnPreferenceField.get(vpnProfileClass);
        Constructor<?> constructor = vpnProfileFromVpnPreferenceField.getClass().getConstructors()[0];
        constructor.setAccessible(true);
        vpnProfile = constructor.newInstance(vpnProfileKey);//creating new instance of VpnProfile class
        Map<String, Class<?>> vpnProfileMap = getMappedFields();
        Iterator<String> profileKeysIterator = vpnProfileMap.keySet().iterator();
        while(profileKeysIterator.hasNext()){
            String key = profileKeysIterator.next();
            Field field = vpnProfile.getClass().getField(key);
            field.setAccessible(true);
            if(vpnProfileMap.get(key).equals(String.class) && values.get(key)!=null){
                String s = new String();
                field.set(s, "value");//change this
            }else if(vpnProfileMap.get(key).equals(boolean.class) && values.get(key)!=null){
                int i = 0;
                field.setInt(i, 1111111);// change this
            }else if(values.get(key)!=null){
                boolean  b = false;
                field.setBoolean(b, true);// change this
            }

        }
        vpnSettings = Class.forName("com.android.settings.vpn.VpnSettings"); //time to add it to settings
        Method addProfileMethod = vpnSettings.getDeclaredMethod("addProfile", vpnProfile.getClass()); 
        addProfileMethod.setAccessible(true);
        addProfileMethod.invoke(vpnSettings, vpnProfile);
    }
}

当我运行此代码时,我得到:java.lang.classnotfoundexception: com.android.settings.vpn2.vpnsettings

只是知道我做错了什么。我尝试使用 API 14、15 .. 18设备未植根。

如果您对如何向内置 VPN 管理器添加新配置文件有其他建议,请告诉我。

4

2 回答 2

4

基本上,您正在尝试的内容不会起作用,因为VpnSettings该类在您的应用程序中不可用。它不是 Android 框架的私有部分;它是设置应用程序的一部分,与您的应用程序完全不同。这就像尝试org.mozilla.firefox.App从 Firefox 应用程序访问课程一样。你不能这样做。如果可以,您会发现它仍然无法工作,因为VpnSettings它会将其设置保存到您的应用无权访问的位置。

如果您的设备植根,并且您的应用具有 root 访问权限,您可能会自己写入该位置。否则,你没有这个机会。

于 2013-11-28T18:35:29.443 回答
1

因此,似乎将我的 Android 项目构建目标更改为 Google API 目标而不仅仅是 Android 目标已经解决了这个问题(或者至少我不再得到 ClassNotFoundException)。

尝试自己设置:右键单击您的项目。Build Path -> Configure Build Path... 转到左侧窗格中的 Android 设置。为您的项目检查相应的 Google API 目标。

编辑:这解决了VpnProfile我遇到的问题,但不是VpnSettings您遇到的问题(现在我遇到了这个问题)。

编辑 2: VpnSettings 类位于设置应用程序中。如果您愿意,可以下载“设置”应用的源代码:https://android.googlesource.com/platform/packages/apps/Settings.git

于 2013-11-11T17:36:28.667 回答