Refactor VPN service to dynamically load tunnel address.

Replaced hardcoded TUN address with a dynamic loader using `ConfigLoader`. Introduced `ConfigLoader` to parse `tun_address` from the configuration file or fallback to a default value. Improved file handling in `V2rayUtil` for better readability and maintainability.
This commit is contained in:
yjj38 2025-05-28 14:18:25 +08:00
parent c852142262
commit 208e977d2f
4 changed files with 67 additions and 21 deletions

View File

@ -119,5 +119,6 @@
"outboundTag": "direct"
}
]
}
},
"tun_address": "172.19.0.1"
}

View File

@ -0,0 +1,48 @@
package com.example.studyapp.config;
import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class ConfigLoader {
// assets 中读取 JSON 文件并解析
public static String getTunnelAddress() {
String jsonStr;
// 获取应用私有目录的文件路径
File configFile = new File("/data/v2ray/config.json");
// 检查文件是否存在
if (!configFile.exists()) {
return "172.19.0.1"; // 返回默认地址
}
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(configFile)))) {
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
jsonStr = stringBuilder.toString();
// 解析 JSON
JSONObject jsonObject = new JSONObject(jsonStr);
return jsonObject.optString("tun_address", "172.19.0.1");
} catch (FileNotFoundException e) {
e.printStackTrace();
return "172.19.0.1";
} catch (IOException | JSONException e) {
e.printStackTrace();
return "172.19.0.1";
}
}
}

View File

@ -5,6 +5,7 @@ import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.example.studyapp.config.ConfigLoader;
import com.example.studyapp.utils.V2rayUtil;
import java.io.BufferedReader;
@ -22,9 +23,8 @@ import java.util.List;
public class CustomVpnService extends VpnService {
private static final String TUN_ADDRESS = "172.19.0.1"; // TUN IP 地址
private static final String TUN_ADDRESS = ConfigLoader.getTunnelAddress(); // TUN IP 地址
private static final int PREFIX_LENGTH = 28; // 子网掩码
private static final int MAX_RETRY = 5;
private ParcelFileDescriptor vpnInterface; // TUN 接口描述符

View File

@ -10,6 +10,7 @@ import java.io.IOException;
import java.io.InputStream;
public class V2rayUtil {
private static File v2rayConfig,v2rayBinary;
public static void startV2Ray(Context context) {
try {
@ -19,10 +20,6 @@ public class V2rayUtil {
return;
}
// 获取文件路径
File v2rayBinary = new File(context.getCodeCacheDir(), "v2ray");
File v2rayConfig = new File(context.getCodeCacheDir(), "config.json");
// 构建命令
ProcessBuilder builder = new ProcessBuilder(v2rayBinary.getAbsolutePath(), "-config", v2rayConfig.getAbsolutePath()).redirectErrorStream(true);
@ -48,18 +45,18 @@ public class V2rayUtil {
try {
// 检查并复制 v2ray 可执行文件
String abi = Build.SUPPORTED_ABIS[0]; // 获取当前设备支持的 ABI 架构
File binaryOutputFile = new File(context.getCodeCacheDir(), "v2ray");
v2rayBinary = new File(context.getCodeCacheDir(), "v2ray");
if (!binaryOutputFile.exists()) {
if (!v2rayBinary.exists()) {
InputStream binaryInputStream = context.getAssets().open("v2ray/" + abi + "/v2ray");
FileOutputStream binaryOutputStream = new FileOutputStream(binaryOutputFile);
FileOutputStream binaryOutputStream = new FileOutputStream(v2rayBinary);
try {
byte[] buffer = new byte[1024];
int length;
while ((length = binaryInputStream.read(buffer)) > 0) {
binaryOutputStream.write(buffer, 0, length);
}
Log.i("V2Ray", "Copied v2ray binary to: " + binaryOutputFile.getAbsolutePath());
Log.i("V2Ray", "Copied v2ray binary to: " + v2rayBinary.getAbsolutePath());
} catch (Exception e) {
Log.e("V2rayUtil", "Failed to copy v2ray binary", e);
return false;
@ -68,12 +65,12 @@ public class V2rayUtil {
binaryOutputStream.close();
}
}
binaryOutputFile.setExecutable(true, false);
binaryOutputFile.setReadable(true, false);
binaryOutputFile.setWritable(true, false);
v2rayBinary.setExecutable(true, false);
v2rayBinary.setReadable(true, false);
v2rayBinary.setWritable(true, false);
// 检查文件是否已经具有可执行权限
if (!binaryOutputFile.canExecute()) {
if (!v2rayBinary.canExecute()) {
Log.e("V2rayUtil", "Binary file does not have execute permission. Aborting start.");
return false;
}
@ -81,18 +78,18 @@ public class V2rayUtil {
// 检查并复制 config.json 文件
File configFile = new File(context.getCodeCacheDir(), "config.json");
v2rayConfig = new File("/data/v2ray/config.json");
if (!configFile.exists()) {
if (!v2rayConfig.exists()) {
InputStream configInputStream = context.getAssets().open("v2ray/" + abi + "/config.json");
FileOutputStream configOutputStream = new FileOutputStream(configFile);
FileOutputStream configOutputStream = new FileOutputStream(v2rayConfig);
try {
byte[] buffer = new byte[1024];
int length;
while ((length = configInputStream.read(buffer)) > 0) {
configOutputStream.write(buffer, 0, length);
}
Log.i("V2Ray", "Copied v2ray config.json to: " + configFile.getAbsolutePath());
Log.i("V2Ray", "Copied v2ray config.json to: " + v2rayConfig.getAbsolutePath());
} catch (Exception e) {
Log.e("V2rayUtil", "Failed to copy config.json", e);
return false;
@ -101,8 +98,8 @@ public class V2rayUtil {
configOutputStream.close();
}
}
configFile.setReadable(true, false);
configFile.setWritable(true, false);
v2rayConfig.setReadable(true, false);
v2rayConfig.setWritable(true, false);
return true;
} catch (IOException e) {