Reconnection strategy
Reconnection strategy
When building iOS applications that rely on a VPN connection, implementing a robust reconnection strategy is crucial to ensure a seamless user experience. One effective approach is to leverage the On-Demand VPN feature, which allows the system to automatically establish the VPN connection based on predefined rules. In this page, we'll explore how to configure On-Demand VPN using the OnDemandConfiguration struct in Swift and how it ties into a reliable reconnection strategy.
Understanding OnDemandConfiguration
The OnDemandConfiguration struct is a codable struct that represents the configuration for On-Demand VPN. It has two main properties:
isEnabled
A boolean value that determines whether the On-Demand VPN feature is enabled or not.
The default value for this setting is
false. When set tofalse, the on-demand rules for automatically reconnecting the VPN are disabled. This means that the VPN will not automatically reconnect based on any rules. In this case, the user must manually manage the VPN connection.When set to
true, the VPN will be automatically triggered by the system after thestartVPNmethod is called. To disable On-Demand VPN, you need to call thestopmethod from your application.
onDemandRules
Defines the rules for triggering the On-Demand VPN connection. These rules specify the conditions under which the VPN should be activated.
If no custom rules are provided,
OnDemandConfigurationuses the default rules defined in theNEOnDemandRule.defaultRulesproperty fromNetworkExtension.You can customize the On-Demand rules based on your specific requirements. For example, you can create rules based on type of network interface (WiFi, cellular, etc), or other criteria supported by the
NEOnDemandRuleclass.
Sample Codes
import NetworkExtension
// ...
// Create custom on-demand rules
let connectRuleWifi = NEOnDemandRuleConnect()
connectRuleWifi.interfaceTypeMatch = .wiFi
let disconnectRuleCellular = NEOnDemandRuleDisconnect()
disconnectRuleCellular.interfaceTypeMatch = .cellular
let onDemandRules = [connectRuleWifi, disconnectRuleCellular]
let hydraConfiguration = HydraConfiguration(
carrierID: "YOUR_CARRIER_ID",
extensionBundleID: "com.yourcompany.demo-test.app.hydra-extension",
groupData: VPNGroupData(
groupID: "group.GROUP_ID",
usesSystemExtension: false
),
fireshieldConfig: FireshieldConfig(
mode: .disabled,
groupData: VPNGroupData(groupID: "group.com.yourcompany.vpnsdk-demo", usesSystemExtension: false)
),
onDemandConfiguration: OnDemandConfiguration(isEnabled: true, onDemandRules: onDemandRules)
)In the sample code above:
import NetworkExtensionsimports the NetworkExtension framework, which provides APIs for configuring and managing VPN connections.Two on-demand rules are created:
connectRuleWifi: Specifies that the VPN should automatically connect when the device is connected to a Wi-Fi network.disconnectRuleCellular: Specifies that the VPN should automatically disconnect when the device switches to a cellular network.
The
HydraConfigurationobject is initialized with various configuration parameters, including theonDemandConfigurationproperty.The
OnDemandConfigurationobject is created withisEnabledset totrue, enabling the on-demand rules, and theonDemandRulesarray is passed as theonDemandRulesparameter.
SDK Implementation and Limitations
Current Implementation Behavior
Our SDK implementation prioritizes explicit VPN control to ensure predictable behavior. The SDK automatically manages VPN On Demand functionality in conjunction with the start() and stop() methods:
On
start(): The VPN connection is established according to your configurationOn
stop(): The SDK automatically disables VPN On Demand by:Setting
isOnDemandEnabledtofalseSaving this configuration to system preferences
Preventing any automatic reconnection based on VPN On Demand rules
This design ensures that when users explicitly stop the VPN, it remains stopped without unexpected reconnections.
Full On-Demand Support (SDK 7.7.0+)
Starting from version 7.7.0, the SDK introduces a new policy that provides full support for the VPN On Demand feature. With this update, the SDK no longer automatically disables VPN On Demand when stop() is called.
New Behavior
On
start(): The VPN connection is established according to your configuration (unchanged)On
stop(): The SDK now respects your VPN On Demand configuration:If VPN On Demand is enabled, it remains enabled after stopping
The VPN will automatically reconnect based on your configured on-demand rules
Users must explicitly disable VPN On Demand through your app to prevent automatic reconnection
Migration Notes
If you are upgrading from a version prior to 7.7.0:
Review your reconnection logic: The SDK will no longer disable VPN On Demand on
stop(), which may change your app's behaviorUpdate user-facing controls: Ensure your app provides clear controls for users to enable/disable VPN On Demand
Remove workarounds: If you previously implemented the workaround described below to maintain VPN On Demand after
stop(), you can now remove that code
Note: The workaround section below is only relevant for SDK versions prior to 7.7.0.
Reconnection Strategy
Workaround for Persistent VPN On Demand (Pre-7.7.0)
If your application requires VPN On Demand to remain active even after calling stop(), you can implement a workaround using direct access to Apple's NetworkExtension API. This approach bypasses the SDK's automatic VPN On Demand management.
Implementation Steps
Configure and start the VPN profile using the SDK as normal
After SDK configuration, access the
NETunnelProviderManagerdirectlyManually enable both VPN On Demand and the VPN profile
Save the configuration to system preferences
Important Considerations
Manual Management Required: When using this workaround, you become responsible for managing VPN On Demand state
SDK
stop()Behavior: The SDK'sstop()method will still attempt to disable VPN On Demand, so you may need to re-enable it after stoppingSystem Behavior: iOS/macOS will continue attempting to connect based on your VPN On Demand rules, even if the VPN encounters errors
User Experience: Consider implementing UI controls to allow users to fully disable VPN On Demand when needed
Handling NEOnDemandRuleConnect Behavior
When NEOnDemandRuleConnect is enabled and matches, the VPN connection will automatically restart even if the user tries to turn it off from system settings. The OS prevents manual disconnection in this mode.
If your goal is to maintain the VPN connection until the user explicitly disables it, keep VPN On Demand enabled. However, you'll need to guide users to disconnect through your app instead of system settings.
Recommended Approach
Add an "Always On" toggle in your app
This setting controls whether VPN On Demand is enabled
Makes it clear to users how to control the behavior
Notify users when automatic restart occurs
Use the User Notifications framework to alert users when they try to disable the VPN from system settings and it restarts automatically
Explain that they need to disable it from within the app
Detecting Automatic Restart
To detect when the VPN is restarting due to VPN On Demand (rather than a crash or error):
vpnWillStop()is called witherror = nilExtension then restarts with
StartupOptions.isOnDemand = trueinvpnWillStart()
This approach successfully distinguishes between:
Manual user stop → automatic restart: Detected via
error == nilinvpnWillStop()followed byisOnDemand == trueinvpnWillStart()Non-user stops (like network changes): Where
error != nil
Since this involves two separate processes, you need to:
Persist a flag when
vpnWillStop()is called with nil errorCheck this flag when the extension restarts with
isOnDemand = trueReset the flag when the app starts (
StartupOptions.isAppStart == true)
When this sequence is detected, show a notification explaining: "VPN must be stopped from the app while 'Always On' is enabled."
Why Not Disable VPN On Demand From the Extension?
While the extension can detect the manual stop + VPN On Demand restart sequence, it cannot modify VPN configuration settings. This is an architectural limitation of iOS/macOS Network Extensions:
Extension capabilities: The Network Extension runs as a separate process and only receives lifecycle callbacks (
vpnWillStart(),vpnDidStart(),vpnWillStop(), etc.). It can observe and react to events but cannot modify VPN configuration.Configuration control: The SDK's
stop()method and VPN On Demand configuration changes can only be called from the main app, not from within the extension. Whenstop()is called from the main app, the SDK automatically disables VPN On Demand by settingisOnDemandEnabledtofalseand saving this configuration to system preferences.
Therefore, when the extension detects a manual stop with VPN On Demand restart:
It can send a notification to inform the user
The user must open the main app
The user must toggle the "Always On" setting in the app to properly disable VPN On Demand and stop the VPN
Last updated
Was this helpful?