# Application Extension Setup (iOS/macOS)

This guide covers setting up a Network Extension using the traditional Application Extension approach for iOS and macOS platforms.

## Prerequisites

You should already have prepared application target in order to continue. If you haven't done it yet, please see [Application Setup](/paas/sdk/unified-vpn-sdk-for-apple/setup/application-setup.md).

## Setup for iOS/macOS

### Create network extension target

You need to create network extension in order to use Hydra and WireGuard protocols.

Go to *Project -> Targets*, and in menu bar select *Editor > Add Target*.

<figure><img src="/files/gHXo8wywQDHAKKINbwgM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/C8mtnNZ11nP9LdBPGqNc" alt=""><figcaption></figcaption></figure>

Select needed platform (iOS or macOS), then type 'Network' into the search bar then click `Network Extension`.

<figure><img src="/files/29ehIHlbG6TSWQbpsl72" alt=""><figcaption></figcaption></figure>

Provide the following for this [**Network Extension**](https://developer.apple.com/reference/networkextension) target: name, bundle ID (if needed) and change Provider Type to "Packet Tunnel". Then click finish.

<figure><img src="/files/4OXy9FOQShjSWaICu6Gj" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
It is recommended to give distinctive names to your targets and bundle IDs with mention of target protocol, e.g. for Hydra:

* Application target: MyApp, com.companyname.myapp
* Network extension target: MyApp Hydra Provider, com.companyname.myapp.hydraprovider
  {% endhint %}

### Install tunnel provider SDK

At this point you have to have at least two targets:

* **Application** target
* **Network Extension** target

<figure><img src="/files/Lg9Azrs7LeVpdcnhsdSy" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/K6IcbEfZmRk0ZfI1RFKJ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/PVW3uK2EjLP6wgJc0APm" alt=""><figcaption></figcaption></figure>

Now you should link tunnel provider SDK to the **Network Extension** target. We're providing SDK packed as `xcframework`, which means it can be used both for iOS and macOS apps.

### **Manual Installation**

{% hint style="info" %}
Important Note

Each VPN protocol (Hydra and WireGuard) requires its own separate Network Extension target. Do not add both frameworks to the same target as this will cause critical build issues.
{% endhint %}

#### **Hydra**

* Copy **HydraTunnelProvider.xcframework** file to some place inside your project folder on disk.

<figure><img src="/files/PJl93tSXGc5z4m6L8SmH" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/mQll61LNihlRjFypX7xV" alt=""><figcaption></figcaption></figure>

* Go to *Project -> Network Extension Target -> General* and drag copied framework to *Frameworks, Libraries and Embedded Content* section.
* Set `Do Not Embed` under `Embed` option for **HydraTunnelProvider.framework**.

<figure><img src="/files/bFgjtZVPYWaHW5BsrbYI" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
In the SDK folder, the `HydraTunnelProvider.xcframework` file in your downloads folder with in the `VPNSDK x.x.x` (for example, `VPNSDK 6.4.0`) folder. Go to Project -> Network Extension Target -> General and drag copied framework to Frameworks, Libraries and Embedded Content section.
{% endhint %}

#### **WireGuard**

* Copy **WireguardTunnelProvider.framework** file to some place inside your project folder on disk.

<figure><img src="/files/d5new5tu6FvpjLLZm4GS" alt=""><figcaption></figcaption></figure>

* Go to *Project -> Network Extension Target -> General* and drag copied framework to *Frameworks, Libraries and Embedded Content* section.

<figure><img src="/files/SlZXdQkFVFrIv3WD8KVu" alt=""><figcaption></figcaption></figure>

* Set `Do Not Embed` under `Embed and sign` option for **WireguardTunnelProvider.framework**.

<figure><img src="/files/xdYJFKJTN25PUSplq27S" alt=""><figcaption></figcaption></figure>

2. To the **Network Extension** target, click the '+' button, search for **libz.tbd**, and add it. Click the '+' button again, search for **libresolv.tbd**, and add it.

<figure><img src="/files/lisYMzeSN8x2HsupWWup" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/H7sH5Wsh2kXlkxvS4D2H" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/kHHSIOEhQ8Y8vhNeS3hg" alt=""><figcaption></figcaption></figure>

3. Go to *Project -> Network Extension Target -> Build Settings* and:

* Set *Enable Bitcode* to **NO**;
* [Add](https://developer.apple.com/library/content/qa/qa1490/_index.html) `-ObjC` to *Other Linker Flags*.
* Select your Network Target
* Select 'All' in the ribbon just under the ribbon with 'General, Signing & Capabilities … Build Settings'
* Search "Other Linker Flags" in the search bar on the top right
* Select the + button next to Debug, type in '-ObjC' (case sensitive) into the box and hit enter
* Select the + button next to Release, type in '-ObjC' (case sensitive) into the box and hit enter

<figure><img src="/files/C0sWgafAWGjROO9uFpky" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/GeCTLKVNXWYM5zD7HOm1" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Note that Bitcode is [deprecated](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes).
{% endhint %}

### Conform to Network Extension delegate

[After the **Network Extension** target is created](#create-network-extension-target), you should observe that new class is added to your project (file *PacketTunnelProvider.swift*). Go to the *PacketTunnelProvider.swift*, rename it to *ProviderDelegate.*

<figure><img src="/files/KQV0IyDtnrbW1WkncWQW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/H1P6oy8MUKejjtw5wEYT" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZwdEnvlhreK1Aqde2G6t" alt=""><figcaption></figcaption></figure>

Make this class implement `BaseNetworkExtensionDelegate` instead of `NEPacketTunnelProvider`. It should now look like:

For Hydra Protocol

```swift
import HydraTunnelProvider

class ProviderDelegate: NSObject, BaseNetworkExtensionDelegate {
    // ...
}
```

For Wireguard Protocol

```swift
import WireguardTunnelProvider

class ProviderDelegate: NSObject, BaseNetworkExtensionDelegate {
    // ...
}
```

Remove Xcode-generated empty `PacketTunnelProvider`'s implementation. Now you can implement needed methods from *BaseNetworkExtensionDelegate*. Also, if you want to use Fireshield related methods in network extension you can make your *ProviderDelagate* class conform to *FireshieldNetworkExtensionDelegate* protocol which extends base delegate. Pay attention that it makes sense only if you're using Hydra protocol, otherwise Fireshield methods won't be called.

### Setup Info.plist

#### What is a plist?

In Xcode, a plist (short for property list) is a structured data format used to store and manage application settings, configuration data, and other key-value pairs in macOS and iOS applications. Plist files use XML or binary format to represent a hierarchical data structure, which can include dictionaries, arrays, strings, numbers, dates, and boolean values.

#### Creating a plist

1. Navigate to your root project, click on your Application Target (the top of the target list), then click 'Info' in the settings ribbon at the top of the page
2. Go to the 'URL Types (0)' section at the bottom of the page
3. Expand the section and then click the '+' button
4. The section will populate with a icon that says "No Image Specified" and a few drop down menus. Leave these alone.
5. On the left in the project navigator section of Xcode, a new 'Info' file will appear

<figure><img src="/files/ngVUm9K8FvHrJPDnuTlW" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/IshsSq0qHwZUUzQcpsR5" alt=""><figcaption></figcaption></figure>

This box will appear after hitting the '+' button, you can leave this alone

<figure><img src="/files/tuvyNAQeUtSNwwLUAin6" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/SfhXGnrQwMOPnC2LfaCO" alt=""><figcaption></figcaption></figure>

1. Staying in **Network Extension** target, set `NSExtensionPrincipalClass` in `NSExtension` dictionary of `Info.plist` to corresponding value depending on protocol:

* Hydra: `AFHydraTunnelProvider`
* WireGuard: `AFWireGuardTunnelProvider`

2. Add new key to a plist root: `NetworkExtensionDelegate` with a value that is your provider delegate class from the previous step. For example, if your class named `ProviderDelegate`, then the value would be `$(PRODUCT_MODULE_NAME).ProviderDelegate`.

Read more about [Creating a Packet Tunnel Provider Extension](https://developer.apple.com/reference/networkextension/nepackettunnelprovider#2110153) from Apple docs.

Right click the new Info file select Open As > Source Code

To properly configure your Network Extension target, it is essential to set the `NSExtensionPrincipalClass` and `NetworkExtensionDelegate` in the Info.plist file. These configurations ensure that the correct tunnel provider and delegate classes are used, enabling the functionality of your network extension.\\

<figure><img src="/files/IeinKO0thfp2VEAu8jk3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/iwfp8RBwtz92usAaMkDG" alt=""><figcaption></figcaption></figure>

1. Create a new line #9 so that is on line #8 and is on line #10
2. Paste the following code snippet into the blank line #9:

<figure><img src="/files/a3xUk6NRVGxSMUfKljV8" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/LNEeQNpbypBPEN3TeNMw" alt=""><figcaption></figcaption></figure>

Note the commented out code on lines #14, 15 and 16. You will need to uncomment the line which corresponds to the VPN protocol that you will be using. You can leave the unused protocol line either commented out or delete it all together.

<figure><img src="/files/Q2W8RFiuxE0Cbg2aIFKj" alt=""><figcaption></figcaption></figure>

### Setup App ID

Next you need to perform all needed setup on [Apple developer portal](https://developer.apple.com).

#### **Setup on Developer Portal**

You should already have app ID for **Application** target, now you need another one for **Network Extension** target. Go to *Apple developer portal->Certificates, IDs & Profiles->Identifiers* and add new identifier for your Network Extension. Turn on following capabilities for both app IDs (**Application** and **Network Extension**):

* Access WiFi Information
* App Groups
* Network Extensions
* Personal VPN

<figure><img src="/files/hx90IuN8ks1MU7hMgsWb" alt=""><figcaption></figcaption></figure>

### **Create App Group**

Since HydraSDK is mostly a Network Extension you also have to create an App Group and provide group ID to the SDK to allow Hydra to interact with Packet Tunnel Provider Extension. See [Configuring App Groups](https://developer.apple.com/documentation/xcode/configuring-app-groups) for more information about how to create app group.

Please note that one of the steps within the Configuring App Groups will ask you to input your Team ID. For more details, see [Locate Your Team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id).

You need to assign this group to both, the **Application** and the **Network Extension** targets and App IDs.

<figure><img src="/files/cBOTRvGc1N28x50Lbjaq" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/wNoQUFewk4atzRRFYohJ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/USVZ21rvKy7vsd7rSyby" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/7Gyqumd7m9sUHLB2D1vv" alt=""><figcaption></figcaption></figure>

### **Turn on capabilities in project**

For both, **Application** and **Network Extension** targets, go to *Project -> Target -> Capabilities* and enable the following capabilities:

* Access WiFi Information
* Network Extensions
  * Packet Tunnel
* Personal VPN
* App Groups

<figure><img src="/files/u33Aah9UtdnVU2ztRtDk" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/y4A9mJ5capUrgO1Y9EwG" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/i0bJwJTMY1HVgFpUe9sn" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/3ZbOsHgTIucWH5Url3Tz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/mRwu93B43qInnbd5D4TF" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/qkwKkMvo1JfqvjvxHbrw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/be7JOqToM830IxoZnLx4" alt=""><figcaption></figcaption></figure>

For macOS targets, enable Keychain Sharing capability with your Group ID

{% hint style="info" %}
Make sure that respective **.entitlement** files are added to the project for both targets.
{% endhint %}

### Re/Generate Provision Profiles

Application and Network Extension, both have to have its respective Provision Profiles generated from the Developer Portal. When creating and/or regenerating Provision Profiles, make sure you select Network Extension entitlement.

<figure><img src="/files/9hkrA6lbtyrKS3hE2WPV" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/drzdMqMoLqhJjT2D5XUm" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZLqXoOG1wCOWp74kBoZq" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/DnCrb651yMlQDXaJX5s3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/1HxCHjWXDMw2qCtuqSdT" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The Provision Profiles' entitlements must corresponds to entitlements configured through Xcode's project Capabilities tab. If there is a missconfiguration between the two, VPN connection will not be established.
{% endhint %}

### Finding an iPhone UUID

#### **Option 1: Using Finder**

If you're using macOS Catalina (10.15) or later, you can use Finder to obtain the UDID.

1. Connect your iPhone or iPad to your Mac using a USB cable.
2. Open a Finder window.
3. In the left sidebar under "Locations," your connected device should appear. Click on the device's name.
4. You'll see general information about your device, such as its name, storage capacity, and software version.
5. Click on the device's serial number. It will change to display the UDID. You can right-click the UDID to copy it for easy pasting into the Apple Developer Portal.

#### Option 2: Using iTunes (macOS Mojave and earlier or Windows)

If you're using macOS Mojave (10.14) or earlier, or a Windows PC, you'll use iTunes to obtain the UDID.

1. Connect your iPhone or iPad to your computer using a USB cable.
2. Launch iTunes if it doesn't open automatically.
3. In iTunes, click on the device icon located near the top-left corner of the window. This will open the Summary page for your device.
4. On the Summary page, you'll see information about your device, including its serial number.
5. Click on the serial number, and it will change to display the UDID. You can right-click the UDID to copy it for easy pasting into the Apple Developer Portal.

#### Option 3: Using Xcode

If you have Xcode installed, you can also use it to obtain the UDID.

1. Connect your iPhone or iPad to your Mac using a USB cable.
2. Launch Xcode.
3. In Xcode, go to the menu bar and click on Window > Devices and Simulators.
4. Under the Devices tab, you'll see your connected device listed on the left side. Click on the device's name.
5. The UDID will be displayed under the Identifier label in the details panel on the right. You can select and copy it.

<figure><img src="/files/aC2dE9cJKt5ifZyPXbgm" alt="" width="335"><figcaption></figcaption></figure>

<figure><img src="/files/LFGtlQNf1UUSsnFEViKo" alt="" width="222"><figcaption></figcaption></figure>

<figure><img src="/files/Vc70k3QfViunxuodZBSr" alt="" width="370"><figcaption></figcaption></figure>

<figure><img src="/files/30hYpPRZiAgXqpUoFUSq" alt="" width="375"><figcaption></figcaption></figure>

## Integration Checklist

Checklist that should help you to verify correct integration:

<table><thead><tr><th width="197">Category</th><th>Description</th></tr></thead><tbody><tr><td>Network Extension</td><td>Ensure it is created</td></tr><tr><td>Frameworks</td><td><ul><li><code>VPNApplicationSDK.framework</code> is added to the Application target.</li><li><code>HydraTunnelProvider.framework</code> is added to the Extension target (for Hydra).</li><li><code>WireguardTunnelProvider.framework</code> is added to the Extension target (for WireGuard)</li></ul></td></tr><tr><td>Libraries</td><td><code>libz.tbd</code> and <code>libresolv.tbd</code> are added to the Extension target</td></tr><tr><td>Linker Flags</td><td><ul><li>In <code>User-Defined</code>, <code>ENABLE_BITCODE</code> is set to <code>No</code>.</li><li>In <code>Linking-General</code>, <code>Other Linker Flags</code> is set to <code>-ObjC</code> .</li></ul></td></tr><tr><td>App Groups</td><td>You have created and enabled App Groups (General > Capabilities) for both targets, active App Group is set to "builder.groupId" (App Groups is enabled for both bundle ids (Application and Extension) in Apple Developer Portal).</td></tr><tr><td>Personal VPN</td><td>Personal VPN (General > Capabilities) is enabled for both targets (Personal VPN is enabled for both bundle ids (Application and Extension) in Apple Developer Portal).</td></tr><tr><td>Entitlements</td><td>You have added Network Extension (iOS) entitlement for both Application and Extension provisioning profiles.</td></tr><tr><td>SDK Configuration</td><td>SDK instance is configured with correct <code>groupData</code> and <code>extensionBundleID</code>.</td></tr></tbody></table>

## Troubleshooting

### The bundle identifier of the embedded binary does not have the parent application's bundle identifier as a prefix.

![](https://lh7-us.googleusercontent.com/docsz/AD_4nXelxcZa1MVnD0HTUPmHWbNsktl1en4dD0b7xBwLdIcRX8WbKeXElPo6bwaym-TkR-8PTsnKNod27OiMRI-p7LoW8h0aJn1lBh5g7YOU3GVXHa6VOUR-6qvUE2asUvWRkTH1geJ41gQl1ZCQ6GEuQOxTA6Zt?key=9DChzDQom1-To5fkcwxLMw)

To resolve this:

1. Log in to your Apple Developer account and navigate to the "Certificates, Identifiers & Profiles" section.
2. Remove the existing Identifiers and Profiles associated with the embedded extensions of your app.

{% hint style="info" %}
You do not need to remove the main app identifier, only the extension identifiers.
{% endhint %}

3. Create new Identifiers and Profiles for the extensions you removed in the previous step. Ensure that the bundle identifiers for the new Identifiers are properly prefixed with the parent app's bundle identifier.
4. Open your Xcode project and navigate to the "Signing & Capabilities" tab for each of the affected targets (i.e., the extensions).
5. Under the "Provisioning Profile" section, click on the "Download Profile" button to download the new Profiles you created in step 3.
6. Select the appropriate downloaded Provisioning Profile for each target.
7. Clean and rebuild your project.

### Xcode won't pause at this breakpoint because it has not been resolved

When you're developing an app extension, such as a `PacketTunnelProvider`, and you find that Xcode won't pause at your breakpoints, you might see the following message:

```
Xcode won't pause at this breakpoint because it has not been resolved.

resolving it requires:
- library for the breakpoint is loaded
- line at the breakpoint is compiled
- compiler generates .. that is not stripped out
```

<figure><img src="/files/LVpnOBSfdO978PI1rvkG" alt=""><figcaption></figcaption></figure>

Follow these steps to resolve the issue and get your breakpoints working again:

1. In Xcode, clean and rebuild your project. Enable the VPN connection within the app.
2. Click on **Debug** in the menu bar, then select **Attach to Process by PID or Name…**.

<figure><img src="/files/fuZG6z4nj52uDwkV4Tqa" alt="" width="375"><figcaption></figcaption></figure>

2. In the dialog that appears, enter the name of your extension target. For example, `VPNSDK Demo Hydra Provider`, type that into the field. Keep in mind that your app and extension run as separate processes, so be sure to attach to the correct one.
3. Once you've selected the correct process, click the **Attach** button.

<figure><img src="/files/TQQDSWc2cDsvcHdVXlxy" alt="" width="375"><figcaption></figcaption></figure>

4. You should now see breakpoint highlighted, indicating it is active.

<figure><img src="/files/5XvAiHtoKojg3imuufMH" alt=""><figcaption></figcaption></figure>

It's important to note that if you want to set a breakpoint in start lifecycle methods (such as `vpnWillStart`), you need to attach the debugger before connecting to the VPN. Otherwise, these methods will have already been called by the time you attach, and the breakpoint will not be hit.

{% hint style="info" %}
If Xcode seems to be stuck while waiting to attach to your extension process, please ensure that:

1. Your app is already running
2. The VPN connection is active (VPN icon is visible in the status bar)
   {% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pango.gitbook.io/paas/sdk/unified-vpn-sdk-for-apple/setup/network-extension-setup/application-extension-setup-ios-macos.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
