public final class Vpn
- Object
- Vpn
Installing and controlling a VPN configuration the operating system runs for you.
if (Vpn.isSupported()) {
Vpn.install(new VpnProfile("vpn.example.com")
.usernamePassword("alice", secret))
.ready(v -> Vpn.start());
}
The tunnel is the platform’s, not this app’s
Nothing here carries packets. The configuration is handed to the operating
system, which runs its own IKEv2 or IPsec client; the app starts it, stops
it and watches it. Implementing the tunnel itself is a different and much
larger undertaking – see the note in the com.codename1.vpn package
documentation – and this API stays useful around it either way, for the
install, the status and the control.
The user may be asked, and the app cannot skip the asking
install shows a system prompt when the platform wants consent, and
there is no way around it: a declined prompt fails with
VpnError.USER_DECLINED, which is an ordinary outcome and not an error to
report to the user again.
It is NOT a prompt on every install. Android asks once and remembers, so
replacing a profile in an app the user has already approved provisions
and answers with nothing shown – the port takes that path whenever
provisionVpnProfile returns no consent intent. An app that treated each
install as a fresh checkpoint, or that told the user a dialog was coming,
was wrong in that case.
So: be ready for the prompt, and do not depend on it appearing.
One configuration per app
Both platforms give an app a single managed configuration, so install
replaces whatever was there rather than adding to it.
Methods
public static boolean isSupported() | Whether this platform can install and control a VPN configuration. |
public static int getCapabilities() | The VpnBridge.CAPABILITY_* mask this platform supports. |
public static VpnStatus getStatus() | Where the tunnel is right now. |
public static AsyncResource<Boolean> install(VpnProfile profile) | Installs or replaces this app’s configuration, after asking the user. |
public static AsyncResource<Boolean> remove() | Removes this app’s configuration. |
public static AsyncResource<VpnProfile> load() | Reads back the installed configuration, resolving null when none is installed. |
public static AsyncResource<Boolean> start() | Brings the tunnel up. |
public static AsyncResource<Boolean> stop() | Takes the tunnel down. |
public static void addStatusListener(VpnStatusListener l) | Adds a status listener. |
public static void removeStatusListener(VpnStatusListener l) | Removes a status listener, stopping delivery when the last one goes. |
Inherited methods
Method details
isSupported
public static boolean isSupported()Whether this platform can install and control a VPN configuration.
False on Android below API 30, and on every port with no VPN
machinery. Note this is a different question from whether a VPN is
running – com.codename1.io.NetworkManager#isVPNActive() answers
that one, on many more platforms and with no entitlement.
getCapabilities
public static int getCapabilities()VpnBridge.CAPABILITY_* mask this platform supports.getStatus
public static VpnStatus getStatus()install
public static AsyncResource<Boolean> install(VpnProfile profile)remove
public static AsyncResource<Boolean> remove()load
public static AsyncResource<VpnProfile> load()Reads back the installed configuration, resolving null when none is installed.
The result never carries the password – the platform keeps it. See
VpnProfile.getPassword().
On Android this is this app’s RECORD, not a platform read
VpnManager provisions, deletes, starts and stops; it has no call
that hands a profile back. So the description here is the one this
app kept when it installed, and it can outlive the real thing – the
user removing the VPN in Settings, or app data restored onto a device
that never had it, both leave the record saying a profile exists.
It corrects itself the first time the platform contradicts it: a
start or a stop that comes back “nothing is provisioned” drops the
record and moves the status to NOT_CONFIGURED. An app that must be
certain should start rather than trust a description, and watch
the status. iOS reads the real configuration and has no such gap.
start
public static AsyncResource<Boolean> start()stop
public static AsyncResource<Boolean> stop()addStatusListener
public static void addStatusListener(VpnStatusListener l)removeStatusListener
public static void removeStatusListener(VpnStatusListener l)