Skip to content
Agentmart
Submit a tool

android-vpn-client

Build Android VPN apps with OpenVPN3 engine and VpnService.

Skill by debzroot

IndexedMIT★ 1
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/debzroot-android-vpn-client

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Build Android VPN apps with OpenVPN3 engine and VpnService.

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/android-vpn-client

What's inside

Skill name
android-vpn-client
Description
Build Android VPN apps with OpenVPN3 engine and VpnService.
License
MIT
Instructions
147 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Android VPN Client Development with OpenVPN3

## When to Use
Use when building an Android VPN client app that:
- Connects to VPN servers using OpenVPN protocol
- Needs to integrate OpenVPN3 engine (via io.github.tim06:openvpn library)
- Requires proper VpnService permission flow
- Wants to capture engine logs/events for debugging

## Core Architecture

### 1. VpnService Implementation
```kotlin
class DebOpenVpnService : VpnService(), EngineCallback {
    // Implement EngineCallback (NOT IOpenVPNService - causes overload conflicts)
    // Use Builder() for tun setup
    // startForeground() with proper notification channel
    // runEngine() via VpnController
}
```

### 2. EngineCallback Interface
```kotlin
interface EngineCallback {
    fun setMtu(mtu: Int)
    fun addDNS(server: String)
    fun addRoute(cidrip: CIDRIP, include: Boolean)
    fun addRoute(dest: String, prefix: Int, gateway: String?, device: String?)
    fun addRoutev6(ip: String, prefix: Int)
    fun setDomain(domain: String)
    fun setLocalIP(cidrip: CIDRIP)
    fun setLocalIPv6(ip: String)
    fun protectFd(fd: Int): Boolean
    fun openTun(): ParcelFileDescriptor?
    fun onStateChanged(state: ConnectionState)
    fun onEngineLog(line: String)
    fun onEngineError(msg: String)
    fun onThreadFinished()
}
```

### 3. VpnController.runEngine()
```kotlin
fun runEngine(config: VpnProfile, callback: EngineCallback) {
    val serviceStub = object : IOpenVPNService {
        // Delegate all methods to callback
    }
    
    val thread = object : OpenVPNThreadv3(serviceStub, config.config) {
        override fun log(info: ClientAPI_LogInfo?) { /* capture logs */ }
        override fun event(e: ClientAPI_Event?) { /* capture events, map to state */ }
        override fun connect(): ClientAPI_Status { /* capture connect errors */ }
    }
    thread.run()
}
```

## Permission Flow (Critical)
```kotlin
// In Activity:
val prepared = VpnService.prepare(this)
if (prepared != null) {
    vpnPermissionLauncher.launch(prepared) // Shows system dialog
} else {
    vpnService?.startVpn(config) // Already granted
}
```
**Never call VpnService.prepare() from Service** - must be from Activity context.

## Common Pitfalls & Fixes

| Issue | Fix |
|-------|-----|
| `setMtu/protectFd/openTun` overload conflicts | **Don't implement IOpenVPNService** - only extend VpnService + implement EngineCallback |
| Duplicate `startVpn/stopVpn` methods | Define once in class body, not repeated at end |
| StateFlow assignment fails | Use `fun setConfig(profile: VpnProfile?)` instead of `.value =` on read-only StateFlow |
| Engine logs not visible | Release AAR disables OpenVPNLogger - must override `log()` and `event()` in OpenVPNThreadv3 subclass |
| `VpnService.prepare()` returns null but not connected | Bind service first, then call prepare() after bind |
| Connection stuck on "Connecting..." | Add 20s timeout + fallback to UDP 1194 (SoftEther/VPN Gate always supports UDP) |

## Retry Strategy (VPN Gate / SoftEther)
```kotlin
// Attempt 1: TCP 443 (default)
// Attempt 2: UDP 1194 (change proto to "udp-client", port 1194)
// Always add DNS fallback:
"dhcp-option DNS 1.1.1.1\ndhcp-option DNS 8.8.8.8"
```

## Timeout Handling
```kotlin
timeoutJob = scope.launch {
    delay(20_000)
    if (state != ConnectionState.CONNECTED) {
        reportError("Server penuh/lambat")
        stopEngine()
    }
}
```

## Key Dependencies
```kotlin
implementation("io.github.tim06:openvpn:1.1.3")
implementation("io.github.tim06:basevpnprotocols:1.1.1")
```

## Project Structure
```
app/
├── src/main/java/com/.../
│   ├── VpnController.kt       # Engine runner + state management
│   ├── DebOpenVpnService.kt   # VpnService + EngineCallback impl
│   ├── MainActivity.kt        # Permission flow + UI connection
│   ├── data/VpnGateApi.kt     # VPN Gate server fetching
│   └── ui/DebNetApp.kt        # Compose UI with connection overlay
└── AndroidManifest.xml        # VpnService declaration + permissions
```

## AndroidManifest.xml Template
```xml

From debzroot/Debz-AI-Agent, MIT.

Signals

Stars
1
Forks
0
Open issues
0
Last commit (this folder)
Sep 8, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from debzroot

Cite this page

android-vpn-client skill. Agent Mart. https://agentmart.dev/skills/debzroot-android-vpn-client (last updated 2026-10-24)