Developers SDK

VPN Unlimited SDK v1.12 for iOS

Getting started

Overview

The VPN Unlimited SDK for OS X is shipped as a static framework. It is written in Objective-C and C++ and is available for OS X 10.10 and later.

Setup

Drag and drop VPNUnlimitedSDK.framework into your project. You have to include the VPNUnlimitedSDKResourceOSX.bundle file (drag and drop it, too).

In order to use it you have to add -ObjC linker flag in XCode (Target > Build Settings > Linker > Other Linker Flags). You also have to add the following additional frameworks and libraries to XCode (Target > Build Phases > Link Binary With Libraries):

  • SystemConfiguration.framework
  • libz.tbd
  • libresolv.tbd

After the setup is completed, you should be able to use all the classes from the SDK by including it with the #import <VPNUnlimitedSDK/VPNUnlimitedSDK.h> directive.

Note:

The current version of the VPN Unlimited SDK uses the following libraries under the hood:

  • libcurl
  • libssl
  • libcares
  • libcrypto

If your project uses one of these libraries and you get conflicts, please contact the VPN Unlimited team for further investigation.

Xcode 7.x+ and App Transport Security

The VPN Unlimited SDK uses a local HTTP server to download VPN profiles (which does not use the NEVPNManager class). You must include the Allow Arbitrary Loads flag in your project's Info.plist file if you use Xcode 7.x+. See Apple's documentation regarding this issue.

App Sandbox Mode

For the same reason as in the previous paragraph, you must set Incoming Connections (Server), Outgoing Connections (Client) checkboxes when using the Apple's App Sandbox mode. Also, you must add the com.apple.security.temporary-exception.apple-events exception key to your entitlement with the value of com.apple.Safari as described here.

Using App ID and App secret

Use the following setup code in your AppDelegate's application:didFinishLaunchingWithOptions: method:

[KSVPNUFacade.defaultFacade setApplicationID:@"<#YOUR_APPLICATION_ID#>"];

[KSVPNUFacade.defaultFacade setApplicationSecret:@"<#YOUR_APPLICATION_SECRET#>"];
Network Extension

Supported protocols:

  • IKEv2
  • OpenVPN
  • KeepSolid Wise UDP
  • KeepSolid Wise TCP

Replace NEPacketTunnelProvider with VPNUPacketTunnelProvider.

  #import 

  @interface YourPacketTunnelProvider : VPNUPacketTunnelProvider

  @end

The provider bundle identifier is used for protocols:

  • OpenVPN
  • KeepSolid Wise UDP
  • KeepSolid Wise TCP

Use the following setup code in your AppDelegate's application:didFinishLaunchingWithOptions:> method:

[KSVPNUFacade.defaultFacade setProviderBundleIdentifier:@"<#YOUR_APPLICATION_BUNDLE_ID#>”];
Classes

This SDK is designed in the classic OOP style. We provide a handful of classes which you can use in any desired combination. All network calls are synchronous, so you should never call them from the main thread. This limitation is highlighted by the fact, that you actually can perform several steps in a row serially on the secondary thread and come back to the main thread with a desired result.

Here is the complete list of classes:

  • KSVPNUFacade
  • VPNUTransport
  • VPNURequest
  • VPNUAuthorizer
  • VPNUAccount
  • VPNUAccountStatus
  • VPNUAccountUserInfo
  • VPNUAccountDeviceStatistics
  • VPNUAccountDevice
  • VPNUServersListAccessor
  • VPNUServerItem
  • VPNUConfigurator
  • VPNUPurchaseManager
  • VPNUPurchaseItem
  • VPNUOnDemandConnectionManager
  • VPNUStorage

You can see the complete documentation for each class on the Reference page.

Here we just briefly describe the standard workflow.

Multithreading

As stated previously, all network calls in this SDK are performed synchronously. This means that you should perform them all in a non-main thread, otherwise they will be blocked and never come back. Each method which falls into this category is explicitly documented.

In order to achieve the asynchronous behavior, you can use any multithreading technique you prefer. We recommend Grand Central Dispatch. When the operation is finished you can move back to the main thread. You can stay on the secondary thread and perform more networking actions serially, if you like.

KSVPNUFacade

KSVPNUFacade is a class which serves as a 'facade' to the other VPN Unlimited SDK classes. It hides the complexity of the VPN Unlimited SDK by encapsulating most of the needed features. Please check the documentation for this class, it is suitable for most applications.

FAQ

In every example in the FAQ section it is implicitly considered that the code is being executed on the secondary thread using the following syntax:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Sample code from FAQ
});
How to set a custom name for the downloaded profile?

First, contact our representative and provide a unique string for the profile name. This can be your company or product name, e.g. "My Awesome VPN". This string will be then used on our servers when generating the profile.

Do not forget to set the same string for your KSVPNUFacade singleton:

KSVPNUFacade.defaultFacade.profileName = @"My Awesome VPN";

This action must be done before any other calls to the VPNUConfigurator instance, e.g. in your application:didFinishLaunchingWithOptions: method. Therefore, this step is a part of your initial setup.

How to specify a custom profile download page?

You can specify a path to your custom HTML page by setting the customProfileDownloadHTMLPath property of your KSVPNUFacade singleton:

KSVPNUFacade.defaultFacade.configurator.customProfileDownloadHTMLPath = absolutePathToYourHTMLPage;

This action must be done before any other calls to the VPNUConfigurator instance, e.g. in your application:didFinishLaunchingWithOptions: method. Therefore, this step is a part of your initial setup.

Keep in mind that you must provide the @[email protected] string somewhere in your HTML code as this string will be replaced with a real profile URL. Please consider the following example of your page:

<html>
    <body>
      <div>Download of your "My Awesome VPN" profile will begin shortly...</div>
      <iframe id="download_profile" src="@[email protected]" style="display:none;"></iframe>
    </body>
  </html>
How to log in an existing user?

You can log in using the user's credentials:

NSString *login = @"[email protected]";
NSString *password = @"password";
NSError *error;
VPNUAuthorizer *authorizer = KSVPNUFacade.defaultFacade.authorizer;
VPNUAccountUserInfo *userInfo = [authorizer authorizeWithLogin:login andPassword:password error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
  if (error) {
    NSLog(@"Error: %@", error);
  } else {
    NSLog(@"Logged in user:%@", userInfo.name);
  }
});

If authorization is successful, the used VPNUTransport instance is managing the newly created session and reconnects automatically when this session is expired. From now on, you have to pass the same VPNUTransport instance to all other objects that depend on it.

How to register a new user?

You can register a new user using the user's credentials. registerWithLogin: will automatically log in a newly created user.

NSString *login = @"[email protected]";
NSString *password = @"password";
NSError *error;
VPNUAuthorizer *authorizer = KSVPNUFacade.defaultFacade.authorizer;
VPNUAccountUserInfo *userInfo = [authorizer registerWithLogin:login andPassword:password error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
  if (error) {
    NSLog(@"Error: %@", error);
  } else {
    NSLog(@"Registered and Logged in user:\n%@", userInfo.name);
  }
});
How to log out a logged in user?

You have to be logged in in order to perform this operation successfully. Please refer to two previous answers.

NSError *error; 
BOOL signedOut = [KSVPNUFacade.defaultFacade.authorizer signOutWithError:&error]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
  if (!signedOut && error) { 
    NSLog(@"Error: %@", error); 
  } else { 
    NSLog(@"Logged out"); 
  } 
});
How to retrieve an account status of a logged in user?

Assuming you are logged in:

[KSVPNUFacade.defaultFacade accountStatusWithCompletion:^(NSError *error, VPNUAccountStatus *accountStatus) { 
  if (error) { 
    NSLog(@"Error: %@", error); 
  } else { 
    NSLog(@"Will expire on:\n%@", accountStatus.timeLeftString);     
  } 
});
How to monitor a VPN connection status?

You can callloadPreferencesWithCompletion of your KSVPNUFacade singleton if you want to retrieve the connectionStatus property (incl. KVO) or receive the VPNUConnectionStatusDidChangeNotification notification. Attention: Call this method asynchronously before any call to the configurator.

[KSVPNUFacade.defaultFacade loadPreferencesWithCompletion:^(NSError *error){
  [self addConnectionStatusKVO];
}];
How to retrieve the list of available VPN servers?

[KSVPNUFacade.defaultFacade serverListWithOptions:KSVPNUServerListOptionsOptimal 
                                       completion:^(NSError *error, NSArray *serversList) { 
                                          if (error) { 
                                           NSLog(@"Error: %@", error); 
                                          } else { 
                                           NSLog(@"Available regions:"); 
                                          for (VPNUServerItem *listItem in serversList) { 
                                            NSLog(@"%@ (%@)", listItem.name, listItem.region); 
                                          } 
            
                                          //Selecting some server 
                                          self.selectedServerItem = [serversList firstObject]; 
                                        }];
How to connect to the selected VPN server?

You can set up the selected server item (see the previous question on how to retrieve it). A profile for the selected server item is downloaded every time the setupVPNWithServerItem: method is called.

[KSVPNUFacade.defaultFacade setupVPNWithServerItem:(VPNUServerItem *)serverItem 
                                        completion:^(NSError *error, BOOL successfullyInstalled) { 
                                             if (error) { 
                                                 NSLog(@"Error: %@", error); 
                                             } else { 
                                                 // Now you can connect to VPN 
                                             } 
                                        }];

Now, you can try to connect to the selected server. Please pay attention to the fact that this method returns after the VPN tunnel connection process is started and does not notify about the actual success of the VPN connection. In order to obtain the connection status, use the connectionStatus property of VPNUConfigurator. This method blocks the calling thread.

NSError *error; 
BOOL started = [KSVPNUFacade.defaultFacade.configurator startVPNWithError:&error]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
  if (error) { 
    NSLog(@"Error: %@", error); 
  } else { 
    NSLog(@"Connection started: %d", started); 
  } 
});
Other versions: 1.1 / 1.7 / 1.9 / 1.10 / 1.11