Skip to content

Commit

Permalink
Expose port and name settings
Browse files Browse the repository at this point in the history
Migrated to dart null safety
  • Loading branch information
ctrysbita committed Feb 22, 2021
1 parent c490ca0 commit f5ea32d
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 160 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
.packages
.pub/

pubspec.lock
build/
android/src/main/libs
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ group 'io.xdea.flutter_vpn'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.4.10'
ext.kotlin_version = '1.4.21'
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// For downloading prebuilt libs
classpath 'de.undercouch:gradle-download-task:4.0.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,11 @@ public int onStartCommand(Intent intent, int flags, int startId) {
profile = new VpnProfile();
profile.setId(1);
profile.setUUID(UUID.randomUUID());
profile.setName(bundle.getString("Address"));
profile.setGateway(bundle.getString("Address"));
profile.setUsername(bundle.getString("UserName"));
profile.setName(bundle.getString("Name"));
profile.setGateway(bundle.getString("Server"));
if (bundle.containsKey("Port"))
profile.setPort(bundle.getInt("Port"));
profile.setUsername(bundle.getString("Username"));
profile.setPassword(bundle.getString("Password"));
profile.setMTU(bundle.getInt("MTU"));
profile.setVpnType(VpnType.fromIdentifier(bundle.getString("VpnType")));
Expand Down
229 changes: 116 additions & 113 deletions android/src/main/kotlin/io/xdea/flutter_vpn/FlutterVpnPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,123 +36,126 @@ import io.flutter.plugin.common.PluginRegistry

/** FlutterVpnPlugin */
class FlutterVpnPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var activityBinding: ActivityPluginBinding

/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel
private lateinit var eventChannel: EventChannel

private var vpnStateService: VpnStateService? = null
private val _serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
vpnStateService = (service as VpnStateService.LocalBinder).service
VpnStateHandler.vpnStateService = vpnStateService
vpnStateService?.registerListener(VpnStateHandler)
private lateinit var activityBinding: ActivityPluginBinding

/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel
private lateinit var eventChannel: EventChannel

private var vpnStateService: VpnStateService? = null
private val _serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
vpnStateService = (service as VpnStateService.LocalBinder).service
VpnStateHandler.vpnStateService = vpnStateService
vpnStateService?.registerListener(VpnStateHandler)
}

override fun onServiceDisconnected(name: ComponentName) {
vpnStateService = null
VpnStateHandler.vpnStateService = null
}
}

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
// Load charon bridge
System.loadLibrary("androidbridge")

// Register method channel.
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_vpn")
channel.setMethodCallHandler(this);

// Register event channel to handle state change.
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "flutter_vpn_states")
eventChannel.setStreamHandler(VpnStateHandler)

flutterPluginBinding.applicationContext.bindService(
Intent(flutterPluginBinding.applicationContext, VpnStateService::class.java),
_serviceConnection,
Service.BIND_AUTO_CREATE
)
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
eventChannel.setStreamHandler(null)
}

override fun onServiceDisconnected(name: ComponentName) {
vpnStateService = null
VpnStateHandler.vpnStateService = null

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activityBinding = binding
}
}

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
// Load charon bridge
System.loadLibrary("androidbridge")

// Register method channel.
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_vpn")
channel.setMethodCallHandler(this);

// Register event channel to handle state change.
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "flutter_vpn_states")
eventChannel.setStreamHandler(VpnStateHandler)

flutterPluginBinding.applicationContext.bindService(
Intent(flutterPluginBinding.applicationContext, VpnStateService::class.java),
_serviceConnection,
Service.BIND_AUTO_CREATE
)
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
eventChannel.setStreamHandler(null)
}


override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activityBinding = binding
}

override fun onDetachedFromActivity() {
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activityBinding = binding
}

override fun onDetachedFromActivityForConfigChanges() {
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"prepare" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
if (intent != null) {
var listener: PluginRegistry.ActivityResultListener? = null
listener = PluginRegistry.ActivityResultListener { req, res, _ ->
if (req == 0 && res == RESULT_OK) {
result.success(true)
} else {
result.success(false)

override fun onDetachedFromActivity() {
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activityBinding = binding
}

override fun onDetachedFromActivityForConfigChanges() {
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"prepare" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
if (intent != null) {
var listener: PluginRegistry.ActivityResultListener? = null
listener = PluginRegistry.ActivityResultListener { req, res, _ ->
if (req == 0 && res == RESULT_OK) {
result.success(true)
} else {
result.success(false)
}
listener?.let { activityBinding.removeActivityResultListener(it) };
true
}
activityBinding.addActivityResultListener(listener)
activityBinding.activity.startActivityForResult(intent, 0)
} else {
// If intent is null, already prepared
result.success(true)
}
}
listener?.let { activityBinding.removeActivityResultListener(it) };
true
}
activityBinding.addActivityResultListener(listener)
activityBinding.activity.startActivityForResult(intent, 0)
} else {
// If intent is null, already prepared
result.success(true)
}
}
"prepared" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
result.success(intent == null)
}
"connect" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
if (intent != null) {
// Not prepared yet
result.success(false)
return
"prepared" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
result.success(intent == null)
}
"connect" -> {
val intent = VpnService.prepare(activityBinding.activity.applicationContext)
if (intent != null) {
// Not prepared yet
result.success(false)
return
}

val map = call.arguments as HashMap<*, *>

val profileInfo = Bundle()
profileInfo.putString("VpnType", "ikev2-eap")
profileInfo.putString("Name", map["name"] as String)
profileInfo.putString("Server", map["server"] as String)
profileInfo.putString("Username", map["username"] as String)
profileInfo.putString("Password", map["password"] as String)
profileInfo.putInt("MTU", map["mtu"] as? Int ?: 1400)
if (map.containsKey("port"))
profileInfo.putInt("Port", map["port"] as Int)

vpnStateService?.connect(profileInfo, true)
result.success(true)
}
"getCurrentState" -> {
if (vpnStateService?.errorState != VpnStateService.ErrorState.NO_ERROR)
result.success(4)
else
result.success(vpnStateService?.state?.ordinal)
}
"getCharonErrorState" -> result.success(vpnStateService?.errorState?.ordinal)
"disconnect" -> vpnStateService?.disconnect()
else -> result.notImplemented()
}

val map = call.arguments as HashMap<String, String>

val profileInfo = Bundle()
profileInfo.putString("Address", map["address"])
profileInfo.putString("UserName", map["username"])
profileInfo.putString("Password", map["password"])
profileInfo.putString("VpnType", "ikev2-eap")
profileInfo.putInt("MTU", map["mtu"]?.toInt() ?: 1400)

vpnStateService?.connect(profileInfo, true)
result.success(true)
}
"getCurrentState" -> {
if (vpnStateService?.errorState != VpnStateService.ErrorState.NO_ERROR)
result.success(4)
else
result.success(vpnStateService?.state?.ordinal)
}
"getCharonErrorState" -> result.success(vpnStateService?.errorState?.ordinal)
"disconnect" -> vpnStateService?.disconnect()
else -> result.notImplemented()
}
}
}
17 changes: 17 additions & 0 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ android {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug

ndk {
if (!project.hasProperty('target-platform')) {
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
} else {
def platforms = project.property('target-platform').split(',')
def platformMap = [
'android-arm' : 'armeabi-v7a',
'android-arm64': 'arm64-v8a',
'android-x86' : 'x86',
'android-x64' : 'x86_64',
]
abiFilters = platforms.stream().map({ e ->
platformMap.containsKey(e) ? platformMap[e] : e
}).toArray()
}
}
}
}
}
Expand Down
37 changes: 18 additions & 19 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
///
/// Copyright (C) 2018 Jason C.H
/// Copyright (C) 2018-2020 Jason C.H
///
/// This library is free software; you can redistribute it and/or
/// modify it under the terms of the GNU Lesser General Public
Expand All @@ -10,8 +9,6 @@
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
/// Lesser General Public License for more details.
///
import 'package:flutter/material.dart';
import 'package:flutter_vpn/flutter_vpn.dart';

Expand All @@ -28,7 +25,7 @@ class _MyAppState extends State<MyApp> {
final _passwordController = TextEditingController();

var state = FlutterVpnState.disconnected;
var charonState = CharonErrorState.NO_ERROR;
CharonErrorState? charonState = CharonErrorState.NO_ERROR;

@override
void initState() {
Expand Down Expand Up @@ -62,30 +59,32 @@ class _MyAppState extends State<MyApp> {
obscureText: true,
decoration: InputDecoration(icon: Icon(Icons.lock_outline)),
),
RaisedButton(
ElevatedButton(
child: Text('Connect'),
onPressed: () => FlutterVpn.simpleConnect(
_addressController.text,
_usernameController.text,
_passwordController.text,
),
),
RaisedButton(
ElevatedButton(
child: Text('Disconnect'),
onPressed: () => FlutterVpn.disconnect(),
),
RaisedButton(
child: Text('Update State'),
onPressed: () async {
var newState = await FlutterVpn.currentState;
setState(() => state = newState);
}),
RaisedButton(
child: Text('Update Charon State'),
onPressed: () async {
var newState = await FlutterVpn.charonErrorState;
setState(() => charonState = newState);
}),
ElevatedButton(
child: Text('Update State'),
onPressed: () async {
var newState = await FlutterVpn.currentState;
setState(() => state = newState);
},
),
ElevatedButton(
child: Text('Update Charon State'),
onPressed: () async {
var newState = await FlutterVpn.charonErrorState;
setState(() => charonState = newState);
},
),
],
),
),
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Demonstrates how to use the flutter_vpn plugin.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

environment:
sdk: ">=2.7.0 <3.0.0"
sdk: ">=2.12.0 <3.0.0"

dependencies:
flutter:
Expand Down
Loading

0 comments on commit f5ea32d

Please sign in to comment.