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.
On your device, you should navigate to Settings and select Network; 2. Then navigate to the VPN category and tap the options icon next to the installed VPN apps on your device; 3.
As per the docs, JDK 17 isn't supported yet in Android Studio.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With