顯示具有 vpn 標籤的文章。 顯示所有文章
顯示具有 vpn 標籤的文章。 顯示所有文章

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

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



flutter第三彈,終究有寫不出來的時後,記錄連trojan-go vpn

先說本篇沒有任何程式碼,也不是教學文,畢竟最終結果是失敗的,只是一個紀錄

上一篇說到,公司提供trojan-go協議叫我試試看,我上網查一下除了我以前聽過的,近幾年又多出許多新協議,trojanp-go就是其中一個,他是走443port,偽裝https協議,是因為這樣所以C國不會擋?阿災,總之就動手做做看吧。想不到這一試,人生就浪費了近一週

首先估狗後只找到一個flutter plugin,最後一次commit是三年前.....能不擔心嗎==,然後整個plugin 還沒有上flutter hub,這令我有些擔心,把這個repo載下來後,嘗試放在資料夾內,試圖參照example資料夾的引用方式來因用這個plugin,但一直無法實際產生那些class,嘗試了好半天,第一步宣告放棄。

下一步詢問claude,他建議我到trojan官方github,把二進制的執行檔複製到手機裡,最後透過process.run去執行。原來是go寫的專案,那這一切都相當合理了,只是當一切看似進行順利的時候,最後卻出現Permission Denied......,無論怎麼修改執行權限都不通,最終一樣宣告放棄。

再次聯繫上水哥大神,用一塊雞排換得他的幫助,水哥先是到plugin的release把source code載下來,然整理到可以把example裡的專案run起來才轉給我,他說github上的code沒有aar檔,直接clone下來也是白搭,最後再說一句:這專案真的是爛透了。身為小白的我哪懂這些,只是再復述了一次:這專案真的是爛透了!

幾經折騰,確實把專案run起來了,但真的把配置送進去卻沒有真正連上vpn。

我左思右想,難道要在這裡放棄?既然這個plugin只是透過android跟aar溝通,那我是否可以直接寫android,行吧,在試最後一次

打開近十年沒有開啟的android專案,基本webview都建好了,然後我想說plugin的aar既然起碼是三年前的,那我去官方抓最新的來build好了,所以我重回官方github,然後再載gomobile來 build aar,然後一直都build不出來.....那能否直接使用plugin的aar?這部分我記憶有點模糊,但我印象好像跟新版的class function都不一樣,總之最終我還是放棄了

最終把這不幸的消息告知PM,卻換得一句:那我們再嘗試下一個協議吧!(靠X不是早說不行了嗎)......這趟旅程還要走多久呢==

2024年7月15日 星期一

flutter第二彈,公司要求要先連vpn才能進到我們站,先來試試open vpn吧

眾所周知,C國的網路環境一天天惡化,不想點辦法公司大家都快沒飯吃了。於是股東們提出個這麽天才的想法,如果連了VPN那不就可以繞過管制了嗎?

但骨子裡是前端的我,壓根不相信這事能成,不過轉念一想,既然市面上一堆軟體都可以做到軟體連線VPN,那這件事似乎沒有不可能,好吧那就試試看吧

對VPN協議我不太熟悉,索性選擇我最後一次使用的open vpn,我找到這裡有點資源可以借用,找到你喜歡的國家把ovpn載下來放到靜態資料夾裡

之後開始我們的程式

// add file vpn_webview.dart
import 'package:flutter/material.dart';
import 'package:openvpn_flutter/openvpn_flutter.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

class VpnWebViewPage extends StatefulWidget {
const VpnWebViewPage({Key? key}) : super(key: key);

@override
_VpnWebViewPageState createState() => _VpnWebViewPageState();
}

class _VpnWebViewPageState extends State<VpnWebViewPage> {
late OpenVPN engine;
InAppWebViewController? webViewController;
final String webviewUrl = "https://xxxxxx.com/";
VpnStatus? status;
VPNStage? stage;
bool get isVpnConnected => status?.connectedOn != null;

@override
void initState() {
super.initState();
initPlatformState();
connectVpn();
}

Future<void> initPlatformState() async {
engine = OpenVPN(
onVpnStatusChanged: _onVpnStatusChanged,
onVpnStageChanged: _onVpnStageChanged,
);

engine.initialize(
groupIdentifier: "group.com.laskarmedia.vpnMobile",
providerBundleIdentifier: "id.laskarmedia.vpnMobileVpnExtension",
localizedDescription: "VPN by HD",
lastStage: (stage) {
print(stage.name);
},
lastStatus: (status) {
print(status);
},
);
}

void _onVpnStatusChanged(VpnStatus? _status) {
print('VPN Status: ${status.toString()}');
setState(() {
status = _status;
});
print('isVpnConnected: ${isVpnConnected}');
}

void _onVpnStageChanged(VPNStage? _stage, String string) {
setState(() {
stage = _stage;
});
if (string == VPNStage.disconnected) {
connectVpn();
}
}

Future<void> connectVpn() async {
// 替換為你的 VPN 配置文件路徑,記得去pubspec.yaml增加assets設定
String vpnConfig =
await DefaultAssetBundle.of(context).loadString('web/jac_test.ovpn');
engine.connect(vpnConfig, 'VPN Name');
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: !isVpnConnected
? const Center(
child: CircularProgressIndicator(),
)
: InAppWebView(
initialUrlRequest: URLRequest(url: WebUri(webviewUrl)),
onWebViewCreated: (controller) {
webViewController = controller;
},
initialSettings: InAppWebViewSettings(
mixedContentMode:
MixedContentMode.MIXED_CONTENT_ALWAYS_ALLOW),
));

}
}

至於main那邊就只是引入使用,這邊就不演示了。

結果寫完了邏輯也沒啥問題,卻一直沒辦法成功。最終AI大神給予指示,何不試試清快取、模擬器重新啟動、重裝app試試,然後,然後就成功了....


7/15更新

結果維運說C國也封堵open vpn,建議我嘗試VPN的trojan-go協議....你倒是早說啊,還有你真當我純血android戰士嗎!

我上網爬了很久的文,幾乎沒有文獻說flutter可以做到,於是我拒絕了這項提案,

稍晚一點PM跑來敲我:ChatGPT說可以,你再試試吧!

王惹花小姐!你是不是沒有被AI唬過!當初想說只是幫點小忙,感覺越來越得寸進尺了!