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" "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.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
import com.example.studyapp.config.ConfigLoader;
import com.example.studyapp.utils.V2rayUtil; import com.example.studyapp.utils.V2rayUtil;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -22,9 +23,8 @@ import java.util.List;
public class CustomVpnService extends VpnService { 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 PREFIX_LENGTH = 28; // 子网掩码
private static final int MAX_RETRY = 5;
private ParcelFileDescriptor vpnInterface; // TUN 接口描述符 private ParcelFileDescriptor vpnInterface; // TUN 接口描述符

View File

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