VPN Service
On Android the tunnel runs inside an android.net.VpnService. The VPN service is an ordinary component of your app
process, registered in your AndroidManifest.xml. The SDK provides KapeVpnService; the minimal
integration is to subclass it (or use it directly):
// KapeVpnTunnelService.kt
import com.kape.platformsdk.vpn.KapeVpnService
class KapeVpnTunnelService : KapeVpnService()
The base class handles:
- SDK initialization with the shared, encrypted credential store
- Endpoint discovery and authentication
- Tunnel setup and handshake (WireGuard, Lightway, or OpenVPN)
- Running as a foreground service with the required ongoing notification
- Connection status and traffic stats updates back to the app
Supplying Your Own Configurations
Most integrations never touch this. If you depend on KapeVPN-VpnService directly and drive
KapeSessionController yourself, you supply a VpnConfigurationGenerator:
fun interface VpnConfigurationGenerator {
suspend fun nextConfiguration(): VpnConfiguration?
}
The session controller calls it once per connection attempt and connects to whatever comes back, so
your generator owns discovery, ordering, credentials, and re-fetching when it runs out of endpoints.
Return null when you have nothing available right now — the session backs off and asks again rather
than tearing the tunnel down. Throw KapeVpnTunnelException for a failure the app can act on; the
reason is recorded in lastTunnelError and the session retries with backoff.
A configuration you return has to be ready to connect. For WireGuard that means authorizing it
first, which your WireGuardAuthenticator does for you:
override suspend fun nextConfiguration(): VpnConfiguration? {
val config = endpoints.removeFirstOrNull() ?: return null
return authenticator.authorize(config)
}
authorize throws when authorization fails. The connection controller no longer sees that failure,
so log it yourself: toAuthFailureLog() includes the HTTP status of a
WireGuardAuthenticationException and redacts public IP addresses, which your logger may not do.
The built-in WireGuard authenticator throws one, with the KapeError as its cause, when the auth
server rejects the request; any other failure is a KapeError.
Manifest Registration
Register the service in your app's AndroidManifest.xml. The system requires the
BIND_VPN_SERVICE permission on the <service> element and the android.net.VpnService intent
filter:
<service
android:name=".KapeVpnTunnelService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:foregroundServiceType="specialUse"
android:exported="false">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
Your app must also declare the supporting permissions (see Installation):
INTERNET, ACCESS_NETWORK_STATE, FOREGROUND_SERVICE (plus FOREGROUND_SERVICE_SPECIAL_USE on
API 34+), and POST_NOTIFICATIONS (API 33+).
How the App and Service Communicate
| Direction | Mechanism |
|---|---|
| App → Service | Context.startService(...) / service binding |
| Service → App | Status broadcasts / bound-service callbacks |
| Shared config | kape_sdk_settings.xml (read by both) |
| Shared state | DataStore (selected location, protocol, last error) |
You don't interact with these directly. KapeVpnManager and KapeVpnService handle all
inter-component communication.