Skip to content

nizwar/openvpn_flutter

Repository files navigation

Connect OpenVPN service with Flutter, Issues and PRs are very welcome!

Android Setup

1. Permission handler

JAVA

Add this to your onActivityResult in MainActivity.java (if you are using Java)

    OpenVPNFlutterPlugin.connectWhileGranted(requestCode == 24 && resultCode == RESULT_OK);

So it look like this

    ...
    import id.laskarmedia.openvpn_flutter.OpenVPNFlutterPlugin;
    ...
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        OpenVPNFlutterPlugin.connectWhileGranted(requestCode == 24 && resultCode == RESULT_OK);
        super.onActivityResult(requestCode, resultCode, data);
    }

Kotlin

Add this to your onAcivityResult in MainActivity.kt (if you are using Kotlin)

    OpenVPNFlutterPlugin.connectWhileGranted(requestCode == 24 && resultCode == RESULT_OK);

So it look like this

   ...
    import id.laskarmedia.openvpn_flutter.OpenVPNFlutterPlugin
   ...
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        OpenVPNFlutterPlugin.connectWhileGranted(requestCode == 24 && resultCode == RESULT_OK)
        super.onActivityResult(requestCode, resultCode, data)
    }

iOS Setup

1. Add Capabillity

Add 2 capabillity on Runner's Target, App Groups and Network Extensions, Look at the image below to get clearer details

2. Add New Target

Click + button on bottom left, Choose NETWORK EXTENSION, and follow instruction's image bellow

Add Capabillity on VPNExtension, Do it same like Runner's Capabillitiy

3. Copy Paste

Add the following lines to your Podfile (ios/Podfile)

target 'VPNExtension' do
  use_frameworks!
  pod 'OpenVPNAdapter', :git => 'https://github.com/ss-abramchuk/OpenVPNAdapter.git', :tag => '0.8.0'
end

Open VPNExtension > PacketTunnelProvider.swift and copy paste this script PacketTunnelProvider.swift

Note

You must use iOS Devices instead of Simulator to connect

Recipe

Initialize

Before start, you have to initialize the OpenVPN plugin.

    late OpenVPN openvpn;

    @override
    void initState() {
        openvpn = OpenVPN(onVpnStatusChanged: _onVpnStatusChanged, onVpnStageChanged: _onVpnStageChanged);
        openvpn.initialize(
            groupIdentifier: "GROUP_IDENTIFIER", ///Example 'group.com.laskarmedia.vpn'
            providerBundleIdentifier: "NETWORK_EXTENSION_IDENTIFIER", ///Example 'id.laskarmedia.openvpnFlutterExample.VPNExtension'
            localizedDescription: "LOCALIZED_DESCRIPTION" ///Example 'Laskarmedia VPN'
        );
    }

    void _onVpnStatusChanged(VPNStatus? vpnStatus){
        setState((){
            this.status = vpnStatus;
        });
    }

    void _onVpnStageChanged(VPNStage? stage){
        setState((){
            this.stage = stage;
        });
    }

Connect to VPN

void connect() {
  openvpn.connect(
    config,
    name,
    username: username,
    password: password,
    bypassPackages: [],
    // In iOS connection can stuck in "connecting" if this flag is "false". 
    // Solution is to switch it to "true".
    certIsRequired: false,
  );
}

Disconnect

    void disconnect(){
        openvpn.disconnect();
    }

Publishing to Play Store and App Store

Android

  1. You can use appbundle to publish the app
  2. Add this to your files in android folder (special thanks to #10). Otherwise connection will not be established in some cases and will siliently report "disconnected" when trying to connect. Most likely it's related to some symbols stripping by Google Play.
gradle.properties > android.bundle.enableUncompressedNativeLibs=false
AndroidManifest > android:extractNativeLibs="true" in application tag

app/build.gradle add these inside android tag

android{
    ...
    //from here ======
    lintOptions {
        disable 'InvalidPackage'
        checkReleaseBuilds false
    }

    packagingOptions {
        jniLibs {
            useLegacyPackaging = true
        }
    }

    bundle {
        language {
            enableSplit = false
        }
        density {
            enableSplit = false
        }
        abi {
            enableSplit = false
        }
    }
    //to here
    ...
}

Notifications

As the plugin shows notification for connection status and connection detail, you have to request permission by using 3rd-party packages.

Example by using permission_handler

    ///Put it anywhere you wish like once you initialize the vpn or pre-connect the server
    Permission.notification.isGranted.then((_) {
      if (!_) Permission.notification.request();
    });

iOS

  1. View Apple Guidelines Relating to VPN
  2. This plugin DOES use Encryption BUT, It uses Exempt Encryptions

Licenses

Love my work?

Don't forget to give me a 👍  or support me with a cup of ☕️