我正在开发一个 Android 应用程序,该应用程序需要创建本地 VPN 来路由所有设备网络流量以实现内容过滤目的。我的目标不是使用远程 VPN 服务器,而是开发在设备上本地运行的 VPN 服务。
以下是我想要实现的目标的关键方面:
本地 VPN 设置:
内容过滤:
VPN 生命周期管理:
当前实施:
这是我的
MainActivity
和MyVpnService
的简化版本:
主要活动:
package com.example.adblocker
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.net.VpnService
import android.os.Bundle
import android.preference.PreferenceManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.adblocker.ui.theme.AdblockerTheme
class MainActivity : ComponentActivity() {
private var websiteList by mutableStateOf(emptyList<String>())
private lateinit var sharedPreferences: SharedPreferences
private val websiteReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val newWebsites = intent?.getStringArrayListExtra("websiteList") ?: emptyList()
websiteList = newWebsites
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
setContent {
AdblockerTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
VpnScreen(
websiteList = websiteList,
onStartVpnClick = { startVpnService() },
onStopVpnClick = { stopVpnService() }
)
}
}
}
registerReceiver(websiteReceiver, IntentFilter("com.example.adblocker.UPDATE_WEBSITES"))
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(websiteReceiver)
}
private fun startVpnService() {
val vpnIntent = VpnService.prepare(this)
if (vpnIntent != null) {
startActivityForResult(vpnIntent, 0)
} else {
onActivityResult(0, RESULT_OK, null)
}
}
private fun stopVpnService() {
val intent = Intent(this, MyVpnService::class.java)
stopService(intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 0 && resultCode == RESULT_OK) {
val intent = Intent(this, MyVpnService::class.java)
startService(intent)
}
}
}
@Composable
fun VpnScreen(
websiteList: List<String>,
onStartVpnClick: () -> Unit,
onStopVpnClick: () -> Unit
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "AdBlocker VPN",
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 20.dp)
)
Button(onClick = onStartVpnClick) {
Text(text = "Enable VPN")
}
Spacer(modifier = Modifier.height(20.dp))
Button(onClick = onStopVpnClick) {
Text(text = "Disable VPN")
}
Spacer(modifier = Modifier.height(20.dp))
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
items(websiteList) { website ->
Text(text = website)
}
}
}
}
@Preview(showBackground = true)
@Composable
fun VpnScreenPreview() {
AdblockerTheme {
VpnScreen(websiteList = emptyList(), onStartVpnClick = {}, onStopVpnClick = {})
}
}
我的VPN服务:
package com.example.adblocker
import android.net.VpnService
import android.os.ParcelFileDescriptor
import android.util.Log
class MyVpnService : VpnService() {
private var vpnInterface: ParcelFileDescriptor? = null
override fun onCreate() {
super.onCreate()
startVpn()
}
override fun onDestroy() {
super.onDestroy()
vpnInterface?.close()
}
private fun startVpn() {
try {
val builder = Builder()
builder.setSession("My VPN Service")
builder.addAddress("10.0.0.2", 24) // Local VPN IP address
builder.addRoute("0.0.0.0", 0) // Route all traffic through the VPN
builder.addDnsServer("8.8.8.8") // DNS server for name resolution
builder.addDnsServer("8.8.4.4") // Optional additional DNS server
vpnInterface = builder.establish()
Log.d("MyVpnService", "VPN started with address 10.0.0.2")
} catch (e: Exception) {
e.printStackTrace()
Log.e("MyVpnService", "Error starting VPN: ${e.message}")
}
}
}
AndroidmanifestXml: `
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Adblocker">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<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>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.faketouch" android:required="false" />
`
问题:
启动 VPN 服务后,网络连接无法正常工作,并且我看到一条错误消息,指示“无互联网连接”。 VPN 服务已启动,但设备无法访问互联网或正确路由流量。 在此输入图片描述
问题:
如何解决启动VPN服务后网络无法连接的问题?是否需要特定配置或额外步骤来确保 VPN 正确路由和过滤设备上的网络流量?
请根据需要随意调整或扩展问题。
采取的故障排除步骤:
我和你的问题有同样的问题。仍在努力寻找一些东西...... 如果您或某人有答案或指导,请告诉我。 谢谢。