This commit is contained in:
eric
2026-03-25 12:29:03 -05:00
parent fce2c49b62
commit cc2f30b6e2
180 changed files with 20523 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,63 @@
package expo.modules.easytier
import android.content.Context
import android.net.VpnService
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
/**
* 与 PC 同源保存 EasyTier 组网 JSON;请求 Android VPN 授权。
* 数据面隧道需将 easytier-core(与 easytier-gui Android 同源)以 JNI 形式接入后,再在此处启动/绑定 tun。
*/
class ExpoEasyTierVpnModule : Module() {
override fun definition() = ModuleDefinition {
Name("ExpoEasyTierVpn")
Function("isAvailable") {
true
}
AsyncFunction("saveAndPrepareTunnel") { configJson: String ->
val ctx = appContext.reactContext ?: throw Exception("no context")
val prefs = ctx.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
prefs.edit().putString(KEY_CONFIG, configJson).apply()
val intent = VpnService.prepare(ctx)
if (intent != null) {
val act = appContext.currentActivity
if (act != null) {
@Suppress("DEPRECATION")
act.startActivityForResult(intent, REQUEST_VPN)
mapOf(
"ok" to true,
"needsVpnPermission" to true,
)
} else {
mapOf(
"ok" to false,
"error" to "no_activity",
"needsVpnPermission" to true,
)
}
} else {
mapOf(
"ok" to true,
"vpnPermissionGranted" to true,
"stub" to true,
)
}
}
AsyncFunction("checkVpnPermissionGranted") {
val ctx = appContext.reactContext ?: return@AsyncFunction mapOf("granted" to false)
val intent = VpnService.prepare(ctx)
mapOf("granted" to (intent == null))
}
}
companion object {
private const val PREFS = "expo_easytier_vpn"
private const val KEY_CONFIG = "config_json"
private const val REQUEST_VPN = 0x4554
}
}