Overview

For iOS and MacOS, Keychain Core is provided as an Objective-C framework. In order to use it in a Swift project:

  1. Add Keychain-ObjectiveC.xcframework to your swift project

    1. Make sure Keychain-ObjectiveC.xcframework appears in the Build Phases → Link Binary with Libraries section or the target product. If it does not appear there, please add it.

    2. Also be sure to also add Keychain-ObjectiveC.xcframework to the Build Phases → Embeded Frameworks section of the target product

    3. There is no need to add the Keychain Core C++ library to your project, because libkeychain.dylib is already contained within the Objective-C framework.

  2. create a bridging header file in your swift project and add the following imports to it

#import <Keychain-ObjectiveC/Gateway.h>
#import <Keychain-ObjectiveC/Monitor.h>
#import <Keychain-ObjectiveC/Asset.h>
#import <Keychain-ObjectiveC/Persona.h>
#import <Keychain-ObjectiveC/PersonaStatus.h>
#import <Keychain-ObjectiveC/Contact.h>
#import <Keychain-ObjectiveC/Facade.h>
#import <Keychain-ObjectiveC/Uri.h>
#import <Keychain-ObjectiveC/Certificate.h>
#import <Keychain-ObjectiveC/LedgerResult.h>
#import <Keychain-ObjectiveC/LedgerTransaction.h>
#import <Keychain-ObjectiveC/SecurityLevel.h>
#import <Keychain-ObjectiveC/Verification.h>
#import <Keychain-ObjectiveC/Settings.h>
#import <Keychain-ObjectiveC/WrapperErrorCodes.h>

Getting Started

For any iOS application, Keychain supplies three files that need to be placed in your application resource bundle. The files are, keychain.cfg, keychain.sql, and drop_keychain.sql. You will need to get and pass the paths to these files to the Gateway constructor when initializing the gateway.

As the Gateway class is lightweight in that it does not perform network calls. It only accesses the Keychain database. As such, they are generally safe to call on the UI thread. However, if you call Gateway methods on a background thread, be sure to dispatch the result to the main thread if the UI needs to be updated.

Likewise, the Monitor object performs (semi) blocking, synchronous pub/sub network operations to receive updates from Query servers. Monitor automatically creates a thread for you when onStart() is called.

Both Gateway and Monitor should be created in an instance of a singleton class that is accessible anywhere in your application that needs to use them. For example, if you are using Swift, you can create a service class that contains both Gateway and Monitor instances as in the following example:

class GatewayService {

    var gateway: Gateway?

    private var monitor: MonitorService?

    private init() throws {
        try initializePaths()

        guard let configFile = configPath,
              let dropDbFile = dropDbPath,
              let createDbFile = createDbPath,
              let dbFilePath = dbPath else {
                  throw KeychainError.unexpected
              }

        let databasePath = "\(dbFilePath)/keychain.db"

        gateway = try Gateway(configFile, databasePath, false, dropDbFile, createDbFile)
        monitor = try MonitorService(dbFilePath: databasePath, gateway: gateway, refreshInterval: appConfig.refreshInterval)

        var address = ""
        var mnemonicList = NSMutableArray()
        try gateway?.seed(address, mnemonicList)
    }

    static let instance: GatewayService? = {
        do {
            let instance = try GatewayService()
            // setup code
            return instance
        } catch {
            Logger(label: GatewayService.typeName).error("Error initializing gateway: \(error)")
        }

        return nil
    }()

In this case, MonitorService is another service (created by the developer, not supplied by Keychain) that wraps the Monitor instance.

Because the constructor of the GatewayService class is private only the GatewayService class can instantiate itself. Consumers of GatewayService must call GatewayService.instance in order to get the singleton instance that contains the Gateway and Monitor instances.

In this case GatewayService is an example of an application level service that you would create (calling it whatever you want to). Keychain does not supply such a class. It is just an example of what you may consider doing in your own application.

In the main entry point of your application you can create a view model that instantiates the singleton instance of GatewayService (i.e. transactionViewModel), and is annotated with @StateObject, as follows:

@StateObject var transactionViewModel = TransactionViewModel()

Then add it to your main view using like this:app-name:

.environmentObject(transactionViewModel)

Now every view in your app will be able to access the Gateway and Monitor functions by calling methods on the transactionViewModel (implemented by you), which then call the appropriate methods in the GatewayService (also implemented by you), which then calls the appropriate methods in the Gateway and/or Monitor.