# iOS native app integration

iOS native apps can be developed in both Swift and Objective-C.

For Flutter apps, jump to [Flutter integration](https://docs.electricbolt.co.nz/getting-started/flutter-integration). For React Native apps, jump to [React Native integration](https://docs.electricbolt.co.nz/getting-started/react-native-integration).

## Prerequisites

You must have the following:

* Xcode 16.4+
* iOS SDKs and associated Simulators.
* AppfigurateSE macOS app.
* Appfigurate Simulator app installed into one or more iOS Simulators (use the [AppfigurateSE macOS app](https://docs.electricbolt.co.nz/appfigurate-se-user-guide/setup-ios-simulator-app) for easy 1 click installation).
* Your iOS app must target iOS 15.0+ in order to link Appfigurate Library.

## Add AppfigurateLibrary.xcframework to the iOS app target

Choose one of the following integration methods (all of which are compatible with both Swift and Objective-C):

{% tabs %}
{% tab title="Swift Package Manager" %}
Add a package dependency `File ‣ Add Package Dependencies` with the URL `https://github.com/electricbolt/appfiguratesdk`
{% endtab %}

{% tab title="Manual" %}
Clone the github repo:

```bash
git clone 
https://github.com/electricbolt/appfiguratesdk.git
```

Drag and drop `AppfigurateLibrary.xcframework` into your project.
{% endtab %}
{% endtabs %}

## Add new app into Appfigurate Simulator

Run Appfigurate in the iOS Simulator.

Tap `≡` `Add app`.

Select app type `iOS`.

Enter a URL scheme that will be used by Appfigurate to launch your app in order to read or apply configuration. The URL scheme must be 4-64 ASCII characters in length and must be unique to your app. e.g. `YOUR-APP-URLSCHEME`

Tap `Add app`.

## Output source code snippets

Tap `≡` `YOUR-APP-URLSCHEME`.

The Edit app screen will be displayed.

{% tabs %}
{% tab title="Swift" %}
Under the `SWIFT/IOS LIBRARY INTEGRATION` section:

Tap `Output implementation` then tap `Clipboard`.
{% endtab %}

{% tab title="Objective-C" %}
Open the macOS `Console.app`. Select the iOS Simulator device in the left hand pane. Type `process:appfigurate` in the search box in the top right.

In Appfiguate Simulator app, under the `OBJ-C/IOS LIBRARY INTEGRATION` section:

Tap `Output header` then tap `Console`.

Tap `Output implementation` then tap `Console`.
{% endtab %}
{% endtabs %}

## Create APLConfiguration subclass

{% tabs %}
{% tab title="Swift" %}
In Xcode, tap `File` ‣ `New` ‣ `New "Configuration.swift"` file from Clipboard.

{% hint style="info" %}
**Note:** *your* public key copied into the clipboard in the [Output source code snippets](#output-source-code-snippets) section above **will** be different to the public key in the following example.
{% endhint %}

> Swift Configuration example

```swift
import Foundation
import AppfigurateLibrary

@inline(__always)
func CONFIGURATION() -> Configuration {
    return APLConfiguration.shared() as! Configuration
}

@objcMembers class Configuration: APLConfiguration {
    @BoolProperty(description: "Log debug output to console", restart: false)
    var debugLogging: Bool

    @StringPropertyListEdit(regex: #"https://[\w\.-]+\.yourappserver.com/.*"#, description: "Application server url", restart: false, values: ["Dev":"https://dev.yourappserver.com/api", "Prod":"https://www.yourappserver.com/api"])
    var serverURL: String

    override func allowInvalidSignatures() -> Bool {
        return !ENCRYPTED()
    }

    override func publicKey() -> String {
        // 41 36 87 71 0D 05
        return "-----BEGIN PUBLIC KEY-----\n" +
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4TZnKfGeXttN7Rr3eiAZ\n" +
            ...
            "ywIDAQAB\n" +
            "-----END PUBLIC KEY-----\n";
    }

    override func reset() {
        debugLogging = true
        serverURL = "https://www.yourappserver.com/api"
    }

}

@_cdecl("APLConfigurationClass")
func APLConfigurationClass() -> AnyClass {
    return Configuration.self
}
```

The [<mark style="color:blue;">`APLConfigurationClass`</mark>](https://www.electricbolt.co.nz/api/Functions.html#/c:@F@APLConfigurationClass) function with C calling convention must be implemented in your app otherwise a linker error will be issued. The recommended place to implement is at the bottom of your [<mark style="color:blue;">`APLConfiguration`</mark>](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html) subclass.
{% endtab %}

{% tab title="Objective-C" %}
In Xcode, add a new Cocoa Touch class, subclassing [<mark style="color:blue;">`APLConfiguration`</mark>](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html), e.g. `Configuration`

In your apps `Configuration.h` file, paste the .h header file output to the Console in the section [Output source code snippets](#output-source-code-snippets) above.

> Objective-C Configuration header example

```objectivec
@import Foundation;
@import AppfigurateLibrary;

#define CONFIGURATION ((Configuration*) [APLConfiguration sharedConfiguration])

@interface Configuration : APLConfiguration

@property(nonatomic, strong) NSString* serverURL;
@property(nonatomic, assign) BOOL debugLogging;

@end
```

In your apps `Configuration.m` file, paste the .m implementation file output to the Console in the section [Output source code snippets](#output-source-code-snippets) above.

{% hint style="info" %}
**Note:** *your* public key copied into the clipboard in the [Output source code snippets](#output-source-code-snippets) section above **will** be different to the public key in the following example.
{% endhint %}

> Objective-C Configuration implementation example

```objectivec
#import "Configuration.h"

@implementation Configuration

BOOL_PROPERTY(debugLogging, @"Log debug output to console", NO)
STRING_PROPERTY_LIST_EDIT(serverURL, @"https:\\/\\/[\\w\\.-]+\\.yourappserver.com/.*", @"URL of app server", NO, @{@"Dev":@"https://dev.yourappserver.com/api", @"Prod":@"https://www.yourappserver.com/api"});

- (BOOL) allowInvalidSignatures {
#if DEBUG
    return YES;
#else
    return NO;
#endif
}

- (NSString*) publicKey {
    // E4 8B B6 25 EE 01
    return @"-----BEGIN PUBLIC KEY-----\n" \
        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnD67fMex1KkP7kltlNaO\n" \
        ...
        "EQIDAQAB\n" \
        "-----END PUBLIC KEY-----\n";
}

- (void) reset {
    self.debugLogging = NO;
    self.serverURL = @"https://www.yourappserver.com/api";
}

@end

Class APLConfigurationClass(void) {
    return [Configuration class];
}
```

The [`APLConfigurationClass`](https://www.electricbolt.co.nz/api/Functions.html#/c:@F@APLConfigurationClass) function must be implemented in your app otherwise a linker error will be issued. The recommended place to implement is at the bottom of your [`APLConfiguration`](https://www.electricbolt.co.nz/api/Classes/APLConfiguration.html) subclass.
{% endtab %}
{% endtabs %}

## Edit Info.plist

In your apps `Info.plist` file (right click, `Open As` ‣ `Source Code`) include the following. Replace the text `YOUR-APP-URLSCHEME` with your own app's URL Scheme - the same value you added in the section [Add new app into Appfigurate Simulator](#add-new-app-into-appfigurate-simulator) above.

> `Info.plist` example

```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>appfigurate.YOUR-APP-URLSCHEME</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>YOUR-APP-URLSCHEME</string>
        </array>
    </dict>
</array>
```

If you already have an existing `CFBundleURLTypes` array in your `Info.plist` file, then insert just the `<dict> ... </dict>` portion.

## UIApplicationDelegate

In your apps `AppDelegate.swift/.m` file, include calls to [<mark style="color:blue;">`APLApplicationOpenURL`</mark>](https://www.electricbolt.co.nz/api/Functions.html#/c:@F@APLApplicationOpenURL) and [<mark style="color:blue;">`APLDidFinishLaunchingWithOptions`</mark>](https://www.electricbolt.co.nz/api/Functions.html#/c:@F@APLApplicationDidFinishLaunchingWithOptions). Create any missing delegate methods as appropriate.

{% tabs %}
{% tab title="Swift" %}

> Swift `UIApplicationDelegate` example

```swift
import AppfigurateLibrary

...

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // When your app opens a URL while running or suspended in memory.
    return APLApplicationOpenURL(url)
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // After launch.
    APLApplicationDidFinishLaunchingWithOptions(launchOptions)
    return true
}
```

{% endtab %}

{% tab title="Objective-C" %}

> Objective-C `UIApplicationDelegate` example

```objectivec
@import AppfigurateLibrary;

...

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    // When your app opens a URL while running or suspended in memory.
    return APLApplicationOpenURL(url);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // After launch.
    APLApplicationDidFinishLaunchingWithOptions(launchOptions);
    return YES;
}
```

{% endtab %}
{% endtabs %}

## For apps using UIWindowSceneDelegate

If your app has a `UIWindowSceneDelegate`, in your apps `SceneDelegate.swift/m` file, include calls to [<mark style="color:blue;">`APLApplicationOpenURL`</mark>](https://www.electricbolt.co.nz/api/Functions.html#/c:@F@APLApplicationOpenURL). Create any missing delegate methods as appropriate.

{% tabs %}
{% tab title="Swift" %}

> Swift `UIWindowSceneDelegate` example

```swift
import AppfigurateLibrary

...

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    // When your app opens a URL while running or suspended in memory.
    APLApplicationOpenURL(URLContexts.first?.url)
}

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // After launch.
    APLApplicationOpenURL(connectionOptions.urlContexts.first?.url)
}
```

{% endtab %}

{% tab title="Objective-C" %}

> Objective-C `UIWindowSceneDelegate` example

```objectivec
@import AppfigurateLibrary;

...

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    // When your app opens a URL while running or suspended in memory.
    NSURL *url = [[[URLContexts allObjects] firstObject] URL];
    APLApplicationOpenURL(url);
}

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // After launch.
    NSURL *url = [[[connectionOptions.URLContexts allObjects] firstObject] URL];
    APLApplicationOpenURL(url);
}
```

{% endtab %}
{% endtabs %}

## Test your iOS app

To test that you've successfully updated your app to use Appfigurate:

* Compile and run your app to the Simulator instance.
* Launch the Appfigurate Simulator app.
* Tap your applications row. The app will be run and made visible, it's configuration read, and then swap back to Appfigurate.
* Appfigurate's [Configure app](https://docs.electricbolt.co.nz/appfigurate-user-guide/configure-app) screen will now be displayed. You can now change the `debugLogging` and `serverURL` properties. Tap `Apply⌄` to apply the configuration to your app.

Now jump to [Supported property types](https://docs.electricbolt.co.nz/configuration-subclasses/supported-property-types).
