https://medium.com/@satish.nada98/guide-to-impleme...
생성일: 2026년 1월 23일
답변에 사용된 모델 GPT-5.2 Thinking by Chat01
생성일: 2026년 1월 23일
답변에 사용된 모델 GPT-5.2 Thinking by Chat01
That Medium post is member-only in a way I can’t fully fetch here, but I can see its outline: it’s a Kotlin + VpnService walkthrough focused on (1) controlling a WireGuard tunnel programmatically and (2) keeping it running via a Foreground Service under Android 14+ restrictions. (Medium)
Below is a concrete “do-this” implementation path using the official WireGuard Android tunnel library + the relevant Android VPN/foreground-service requirements.
WireGuard publishes an Android tunnel library on Maven Central and documents the Gradle + desugaring setup. (git.zx2c4.com)
Gradle (module):
gradledependencies { implementation("com.wireguard.android:tunnel:<version>") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3") } android { compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 coreLibraryDesugaringEnabled true } }
(Those exact desugaring bits are called out by the WireGuard repo docs.) (git.zx2c4.com)
Android’s VPN guide requires your service:
VpnServiceandroid.permission.BIND_VPN_SERVICEandroid.net.VpnService intent filter (Android Developers)xml<service android:name=".MyVpnService" android:permission="android.permission.BIND_VPN_SERVICE" android:exported="true"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> </service>
Before your VPN can become active, Android shows a system confirmation dialog; the guide’s flow starts with VpnService.prepare(). (Android Developers)
kotlinval intent = VpnService.prepare(this) if (intent != null) { startActivityForResult(intent, REQ_VPN) } else { // Already authorized startMyVpn() }
The tunnel library provides a Config class that can parse a wg-quick style config from an InputStream. (Javadoc)
kotlinval config = assets.open("wg0.conf").use { stream -> com.wireguard.config.Config.parse(stream) }
To control the tunnel programmatically, GoBackend exposes setState(tunnel, state, config) and getState(...). (Javadoc)
Conceptually:
kotlinval backend = GoBackend(applicationContext) val tunnel = object : Tunnel { override fun getName() = "wg0" override fun onStateChange(newState: Tunnel.State) { /* update UI */ } } backend.setState(tunnel, Tunnel.State.UP, config) // connect backend.setState(tunnel, Tunnel.State.DOWN, null) // disconnect
If you want to rely on WireGuard’s provided VpnService implementation, the library also includes GoBackend.VpnService (a VpnService subclass). (Javadoc)
Android’s VPN guide explicitly notes that on API 26+ you need to transition your service to the foreground with Service.startForeground(). (Android Developers)
It also recommends a non-dismissible notification while active. (Android Developers)
Android 14 requires foreground service types; for VPN apps, the relevant type is systemExempted, and the docs explicitly list “VPN apps (configured using Settings > Network & Internet > VPN)” as allowed to use it—otherwise you can get ForegroundServiceTypeNotAllowedException. (Android Developers)
So you typically do both:
android:foregroundServiceType="systemExempted"FOREGROUND_SERVICE_SYSTEM_EXEMPTEDstartForeground(..., FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED) on Android 14+(Exact constants/permissions are listed on the Android 14 foreground-service-types page.) (Android Developers)
When the user disconnects/forgets the VPN (or always-on toggles), Android can call onRevoke() and you should tear down resources. (Android Developers)
VpnService + user consent + foreground notification + lifecycle (onStartCommand, onRevoke) (Android Developers)Config.parse) + flip tunnel state (GoBackend.setState) (Javadoc)systemExempted for VPN apps (Android Developers)If you tell me what you’re building (full-tunnel vs split-tunnel/per-app, always-on or not), I can give you a tighter skeleton with the exact manifest + service wiring for that mode.