2024年7月23日 星期二

flutter第四彈,vpn旅途的終點?v2ray vpn連線

繼上一篇trojan-go後,這篇v2ray起步算是用飛的,至少flutter plugin有上官方hub,好笑的是,反而android連線v2ray好像沒有相關資訊

但...好像也沒這麼順利

我把程式碼寫好之後,一直無法正常觸發onStatusChanged(等等看到程式碼就知道我在說什麼了),連線也時好時壞,且無法掌握觸發時機

好在有trojan開發經驗,我學乖了,直接到官方github把release的source code載回家(code一樣沒有aar,唉~)

一開始在run也沒這麼順利,各種報錯,難道歷史要重演了嗎?

參考AndroidX MultiDex not found這篇,在example/android/app/build.gradle加上

dependencies {
implementation "androidx.multidex:multidex:2.0.1"
}

然後就run起來了,真是可喜可賀,接下來可以開始搬code了

// lib/man.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_v2ray/flutter_v2ray.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter V2Ray',
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
),
home: const Scaffold(
body: HomePage(),
),
);
}
}

class HomePage extends StatefulWidget {
const HomePage({super.key});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
late final FlutterV2ray flutterV2ray = FlutterV2ray(
onStatusChanged: (status) {
v2rayStatus.value = status;
setState(() {});
print("my status: ${v2rayStatus.value.state}");
},
);

final V2RayURL parser = FlutterV2ray.parseFromURL(
"vmess://......");

var v2rayStatus = ValueNotifier<V2RayStatus>(V2RayStatus()); // 類似signal可以監聽value

String? coreVersion;
bool get isVpnConnected => v2rayStatus.value.state == "CONNECTED"; // getter
late InAppWebViewController webViewController;

void connect() async {
if (await flutterV2ray.requestPermission()) {
flutterV2ray.startV2Ray(
remark: parser.remark, config: parser.getFullConfiguration());
}
}

@override
void initState() {
super.initState();
flutterV2ray.initializeV2Ray();
    // 類似setTimeout,可能是因為initialize還沒完成,所以需要延遲
    // 它異步沒寫好,就算放在await後也無法順利執行,只好這樣
Future.delayed(const Duration(milliseconds: 500), () async {
coreVersion = await flutterV2ray.getCoreVersion();
print("coreVersion: ${coreVersion}");
connect();
});
}

onBackClick(bool didPop) async {
if (await webViewController?.canGoBack() ?? false) {
webViewController?.goBack();
} else {
SystemNavigator.pop();
}
}

@override
Widget build(BuildContext context) {
return SafeArea(
top: true,
right: true,
bottom: true,
left: true,
child: PopScope(
canPop: false,
onPopInvoked: onBackClick,
child: Scaffold(
body: !isVpnConnected
? Column( // 置中文字
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
child: new Text("Connect"),
onPressed: connect,
),
Container(height: 20.0), //SizedBox(height: 20.0),
],
)
: InAppWebView(
initialUrlRequest:
URLRequest(url: WebUri("https://www.xxx.com/")),
onWebViewCreated: (controller) {
webViewController = controller;
},
onReceivedError: (controller, req, error) {
                          // 如果收到錯誤嘗試重整(怕遞迴),不管他了,反正不是我要用
controller.reload();
},
onConsoleMessage: (controller, consoleMessage) {
print('Console message: ${consoleMessage.message}');
},
initialSettings: InAppWebViewSettings(
mixedContentMode:
MixedContentMode.MIXED_CONTENT_ALWAYS_ALLOW),
))));
}
}

因為沒有需要關閉app時disconnect vpn需求,我就暫時沒有研究這塊

但因為我是直接修改example/lib/main.dart檔案,所以沒辦法透過ide直接build apk那該怎麼做呢?答案是,直接透過terminal下指令

~% cd example

~% flutter build apk

這就做個紀念,提供給有需要的人,我要去補眠了



沒有留言:

張貼留言