Skip to main content

iOS SDK

This guide explains how to integrate an MTRIBES Space into your iOS application.

You'll learn how to synchronize changes from your Space into your codebase using our CLI's code generation, and how to use this code to control the UX of your end users.

Sample apps

Check out our sample apps covering SwiftUI & Storyboard to fast-track your integration.

Requirements#

  1. Xcode 11.0+ / Swift 5.1+
  2. An iOS project ready to integrate with MTRIBES
  3. An MTRIBES Space with at least one Collection and Experience
  4. The MTRIBES CLI installed
  5. Swift code generated for your Space

Our SDK is designed to use in modern iOS applications with support for backward compatibility, up to devices running iOS 10.0.

Swift is treated as our first class language. The SDK will support Objective C in coming releases.

We support both callbacks and the Combine framework for our asynchronous functionalities. You can use either way to start a session or monitor change events.

Code integration#

With your Space code generated, you're ready to integrate MTRIBES into your iOS application.

In the code examples which follow, we'll build out an example Space containing:

  1. A homepage Collection, which contains:
    1. A banner Experience
    2. A body Section, which supports:
      1. Hero Experience types
      2. Carousel Experience types

The generated code is output to ./src/mtspace/example.

Don't worry if this isn't clear yet, as it will make more sense after we run through some examples.

iOS SDK integration#

note

We have removed Swift Package Manager support from version 0.4.1 of our SDK. This was due to compatibility issues discovered with SPM. Once these are resolved by SPM we'll look to add support again.

We recommend installing our SDK via CocoaPods. We'll be supporting Swift Package Manager and Carthage in the future.

CocoaPods#

CocoaPods 1.9.0 or newer is required to install a XCFramework.

To install the library using CocoaPods, follow these steps:

  1. Add the following in your Podfile:
pod 'Mtribes'
  1. Then run the following command in the terminal to install dependency:
pod install

Manual installation#

  1. Download the latest library from releases and place the framework under your application.
  2. Select your application project in the Project Navigator and select the application target under the "TARGETS" heading.
  3. Select the General tab at the top.
  4. Drag and drop Mtribes.xcframework under the Frameworks, Libraries, and Embedded Content section, and make sure the library is Embed & Sign.

Client initialization#

The MTRIBES MTClient is a top level object for configuring your MTRIBES SDK.

An MTClient instance is generated along with your Space integration code and can be accessed via Mtribes.client.

Before using the SDK, first initialize the MTRIBES MTClient with the API key of the MTRIBES Environment you wish to target.

You can find Environment API keys under your Space settings page.

Mtribes.initialize(apiKey: "YOUR_MTRIBES_API_KEY_GOES_HERE")

Client configuration#

The MTRIBES MTClient will expose some optional settings. We've given these sensible defaults, but you can override them to further harmonize MTRIBES with your application.

Example: Disable session locking to enable live Section and Experience change events during a user session.

Mtribes.client.sessionLock = false

It's best to configure the Client before starting the session, but configuration can be adjusted at any time.

See the full list of client configuration options.

Session start#

Before accessing an Experience, it's important to start a session for the active user, so we can serve them personalized states.

We represent an MTRIBES session via the session object, which you can access via Mtribes.session.

You can also start a session with Combine framework.

Anonymous user#

Start a session for an anonymous user.

Mtribes.session.startWithCallback()

This should be done:

  • on app launch if the user is anonymous
  • when a user logs out

It's important to wait for the completion of start() or startWithCallback() before accessing Experiences and Sections.

Logged in user#

Starting a session for a logged in user is similar to an anonymous one, except you must provide their unique identifier.

let options = StartOptions(userId: id)Mtribes.session.startWithCallback(options: options)

This should be done:

  • on app launch if the user is already logged in
  • when a user logs in

Again, wait for the completion of start() or startWithCallback() before accessing Experiences and Sections.

Note
  1. User Id passed to SDK has to be consistent across all the devices/platforms.
  2. User Id passed should be attached to a same user for at least 30days.
Personal Information

A user ID should be opaque and not personally identifiable. For example, you should avoid email addresses, social security numbers or similarly personal information.

If you don't have an opaque ID for a user, you can use a secure hashing algorithm such as SHA256 to encode it before passing it to session.start or session.startWithCallback.

Contextual properties#

When starting a session, you can also provide fields with values specific to the user. These open up powerful Tribe targeting options in the MTRIBES platform.

Number contextual fields

It is preferred to use Int, Double, Float or CGFloat rather than Decimal when passing a number contextual field, as you may experience precision lose when using Decimal objects.

Example 1: Start a session for an anonymous user with a contextual properties of campaign.

let options = StartOptions(fields: ["campaign": campaignId])Mtribes.session.startWithCallback(options: options)

Example 2: Start a session for a logged in user with a contextual properties of subscription.

let options = StartOptions(    userId: user.id,    fields: ["subscription": user.subscription])Mtribes.session.startWithCallback(options: options)

We currently support the following contextual property types.

  • Boolean: true or false

  • Int/Double/Float/Decimal/CGFloat: e.g. 842, 0.332

  • String: e.g. "gold"

  • Date: ISO-8601 UTC string encoded timestamp e.g. "2020-12-02T02:45:02.076Z" This must include the date and time.

    Property Limits

    A maximum of 50 contextual properties can be active at one time. You can remove unused properties to make room for new ones in the contextual property settings page.

    To avoid exceeding these limits or sending PII by mistake, we recommend selecting specific contextual properties to include when starting a session.

Experience access#

With the session primed, you can now check whether Experiences modeled in the Space are enabled for a user, and if so, what custom data properties have been defined for them.


// example of a render function in your app to present a Bannerfunc renderBanner() {    // access the banner Experience from the homepage Collection    let banner = Mtribes.collections.homepage.banner    // only render the banner Experience if it's enabled    if banner.enabled {        // access customized data for the banner        let imageURL = banner.data.imageURL        drawBanner(imageURL)    }}

Section iteration#

Sections contain a list of child Experiences defined at runtime by a Scheduler in the MTRIBES platform. You can iterate over these child Experiences and render each in turn, depending on its type.

Each Section defines its Supported Experience types enum. You can use these in switch cases and render appropriately.

// access the body Section from the homepage Collectionlet body = Mtribes.collections.homepage.body
func renderBody() {    // render each Experience of the Section in order    body.forEach { exp in        switch exp {        case let heroExp as HomepageSection.Supported.Hero:            drawHero(heroExp.data)        case let carouselExp as HomepageSection.Supported.Carousel:            drawCarousel(carouselExp.data)        default: break        }    }}

Change events#

The state of an Experience or Section may change for a user during their session. You can monitor these changes and reflect them in your code.

You can also monitor change events with the Combine framework.

Live updates

If you want published change events to fire during a user's session, then you'll need to set Client.sessionLock to false. By default session locking is enabled to avoid published changes negatively impacting UX.

// access the members of the homepage Collectionlet banner = Mtribes.collections.homepage.bannerlet body = Mtribes.collections.homepage.body
// when the banner Experience changes, re-render itbanner.changedWithCallback(owner: self) { [weak self] event in    self?.renderBanner()}
// when the body Section changes, re-render itbody.changedWithCallback(owner: self) { [weak self] event in    self?.renderBody()}

Behavior tracking#

To help you gather user analytical behavioral patterns associated with an Experience, we expose a track function.

Analytic events support a Category and Action to help with event classification. These properties are encoded as a string in the format <category>/<action>. If only <action> is provided, a default Category of user is assumed.

Analytic events also support two different optional parameters: metadata and payload.

Metadata allows up to 3 key/value pairs of additional information to be associated with the event. Metadata can be within event based tribe filters. Each key should be unique.

The payload parameter is optional and allows you to include any custom string data you wish to track along with the event. This string can be no larger than 1024 bytes.

Here are a few examples from our banner Experience above.

// access the banner Experience from the homepage Collectionlet banner = Mtribes.collections.homepage.banner
// track an ad viewed event// category 'advert', action 'viewed'banner.track(type: "advert/viewed")
// track a signed in event// category 'user' (default), action 'signed_in'banner.track(type: "signed_in")
// optional metadata can be provided via key/value pairs// limited to 3 pairs with unique keys only// Value is a string array. If you only have one value,// supply an array with one element.banner.track(type: "item/clicked", details:    EventMetadata(        ("source", ["promotion", "event"]),        ("target_id", ["42070"]),        ("state", ["active"])))
// [Deprecated] // You can supply a single string for metadata valuesbanner.track(type: "item/clicked", details:    EventMetadata(        ("source", "promotion")))
// an optional event payload of type string can be provided as a third parameter// limited to 1024 bytesbanner.track(    type: "item/clicked",    details: nil, // this is metadata which is optional    payload: "My arbitrary payload")

Global Event tracking#

To track events globally, across your application, which aren't necessarily associated with an Experience, we expose session.track.


// track an ad viewed eventMtribes.session.track(type: "ad/viewed")
// track a sign in event// category 'user' (default), action 'signed_in'Mtribes.session.track("signed_in")
// optional metadata can be provided via key/value pairs// limited to 3 pairs with unique keys only// Value is a string array. If you only have one value,// supply an array with one element.Mtribes.session.track(type: "item/clicked", details:    EventMetadata(        ("source", ["promotion", "event"]),        ("target_id", ["42070"]),        ("state", ["active"])))
// [Deprecated] // You can supply a single string for metadata valuesMtribes.session.track(type: "item/clicked", details:    EventMetadata(        ("source", "promotion")))

Trusted identity#

Trusted Identity helps ensure the authenticity of users identified into your MTRIBES Space. View our comprehensive Trusted Identity guide to understand what this is and how to enable it.

Once you have a hashed user signature returned from your server, you should pass this as an option when starting a session for a logged in user.

let options = StartOptions(userId: user.id, signed: signature)Mtribes.session.startWithCallback(options: options)

Using MTRIBES with Combine#

MTRIBES offers the ability to start session and subscribe to change events using a custom Publisher type.

Session start#

Start a session using Combine is similar to Start a session with callbacks, except it returns a custom Publisher. It is important to wait for the completion of start before accessing Experiences and Sections.

// Logged in userlet options = StartOptions(userId: user.id, signed: signature)let publisher = Mtribes.session.start(options: options)
// Anonymous userlet publisher = Mtribes.session.start()

Change events#

You can also monitor state changes of an Experience or Section by subscribing to a Publisher.

// access the members of the homepage Collectionlet banner = Mtribes.collections.homepage.bannerlet body = Mtribes.collections.homepage.body
// when the banner Experience changes, re-render itbanner.changed()    .sink { [weak self] event in        self?.renderBanner()    }    .store(in: &cancellables)
// when the body Section changes, re-render itbody.changed()    .sink { [weak self] event in        self?.renderBody()    }    .store(in: &cancellables)

Troubleshooting#

You can enable internal SDK logs to gain a deeper understanding of some workflows.

Below is an example of where you can enable the debug log in your app:

#if DEBUG    Mtribes.client.isDebugMode = true#endif

Configuration options#

See below a list of all available client configuration options.

sessionLock#

var sessionLock: Bool { get set }

Defaults to true. Determines whether the session lock cache is enabled or not. When true, the default backing store of the cache will be memory. This means app refreshing will cause the cache to be purged, and updated Experience and Section states to be made available. When set to 'false', all session caching is disabled. Published updates from MTRIBES will be pushed in real-time to connected clients. We’d recommend you only use this in development, or when dealing with scheduled updates that need to be real-time. In all other cases, this can negatively impact the user experience, as published changes can alter the UI a user is currently engaging with.

waitForMsec#

var waitForMsec: Int { get set }

Defaults to 1200 milliseconds (1.2 seconds). When session.start() is called, a network request is made to prime the session with Experience and Section states for the user. This returns a Closure which should be awaited until the session is ready to be accessed. The priming request is designed to return quickly, however, poor network conditions may impact the response time. To ensure that UX is not adversely impacted due to unexpected network delays, you can set waitForMsec to cap the number of milliseconds before the Closure is resolved and the application can begin accessing Experience and section states. If the defined wait time has elapsed, then accessing the session's Experience and Section states will target code generated fallbacks. In the case that the same user was recently active, their session will target previously primed session states. Priming will continue in the background if wait time elapses and populate the session state once loaded.

userTracking#

var userTracking: Bool { get set }

Defaults to true. Determines whether user behavioral tracking events may be sent to the MTRIBES platform. Analytics events are needed to support meaningful insights and intelligent targeting decisions in MTRIBES. Set this option to false if the user did not give tracking consent.

includeTribes#

var includeTribes: Bool { get set }

Defaults to false. When true, Tribes for the current user will be evaluated when their session starts. Any Tribe the current user belongs to will have their IDs exposed via session.tribeIds

log#

var isDebugMode: Bool { get set }

Enables a custom logger to consume and manage internal logs from the SDK.