Question

I know that android.net.VpnService is basically a base class to build custom vpn solutions, but all I want is to create and use PPTP or L2TP VPN connection (just a new profile for built-in VPN manager). I think that the easiest way to do that is to use Java reflection for com.android.settings.vpn.VpnSettings. Here's the code snippet for that from the other post (How to add own VPN settings to system VPN settings page?)

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);
    }
}

When I run this code I get: java.lang.classnotfoundexception: com.android.settings.vpn2.vpnsettings

Just what to know what I'm doing wrong. I tried with API 14, 15 .. 18 Device is not rooted.

If you have another suggestion how to add a new profile to built-in VPN manager please let me know.

Was it helpful?

Solution

Basically, what you're trying isn't going to work because the VpnSettings class is not available within your app. It's not a private part of the Android framework; it's part of the Settings app, which is a completely separate app from yours. It's like trying to access the org.mozilla.firefox.App class from the Firefox app. You can't do it. And if you could, you'd find that it still wouldn't work, because VpnSettings saves its settings to a location that your app doesn't have permission to access.

If your device was rooted, and your app had root access, you could potentially write to that location yourself. Otherwise, you have no chance at this.

OTHER TIPS

So it seems that changing my Android Project Build Target to the Google APIs target instead of just the Android target has fixed the issue (or at least I no longer get the ClassNotFoundException any longer).

Try setting this yourself: Right click on your project. Build Path -> Configure Build Path… Go to the Android settings in the left pane. Check the corresponding Google APIs target for your project.

EDIT: This fixed the VpnProfile issue I had, but not the VpnSettings that you're having (now I'm having that issue).

EDIT 2: VpnSettings class is located in the Settings app. You can download the source for the Settings app if you'd like: https://android.googlesource.com/platform/packages/apps/Settings.git

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top