iOS Integration Reference

System Requirements

ApptentiveKit is written entirely in Swift, but features that are not directly available in Objective-C (due to the use of value types or generics) have Objective-C-friendly wrappers.

The current version of ApptentiveKit is primarily intended for use with UIKit-based apps on iOS and iPadOS. Apps using SwiftUI may be able to make use of ApptentiveKit, but currently can’t provide support for this use case.

  • Minimum Deployment Target: iOS 11.0
  • Minimum Xcode Version: 13.0
  • No external dependencies required

SDK Size

The SDK is estimated to add approximately 2.3MB to the size of your app.

Supported Languages

We have translated all hard-coded strings in our SDK into the following languages. The content of all Interactions comes from our server, and you may translate the text for each Interaction by visiting the Translations Page.

Please note that you must also specify the target language in your Xcode project by selecting the project, clicking Info, and then, under Localizations, click the Add button for the desired language.

Locale Qualifier Language Name
None English
ar Arabic
el Greek
da Danish
de German
es Spanish
fr French
fr-CA French Canadian
it Italian
ja Japanese
ko Korean
nl Dutch
pl Polish
pt-BR Brazilian Portuguese
ru Russian
sv Swedish
tr Turkish
zh-Hant Chinese (Traditional)
zh-Hans Chinese (Simplified)

Adding ApptentiveKit

There are several ways to add the ApptentiveKit dependency to your app. We recommend using Swift Package Manager.

Swift Package Manager

In Xcode, choose Add Packages… from the File menu, and enter https://github.com/apptentive/apptentive-kit-ios in the search field.

If necessary, select the project or target to add the package to, and click Add Package.

CocoaPods

If you are using CocoaPods to manage your project’s dependencies, add pod 'ApptentiveKit' to the section for your app target in your Podfile. If you were previously using the apptentive-ios pod, be sure to remove it.

Carthage

If you are using Carthage to manage your project’s dependency,

  1. Add github "apptentive/apptentive-kit-ios" to your Cartfile.
  2. Run carthage update --use-xcframeworks.
  3. On your application targets’ General settings tab, in the Frameworks, Libraries, and Embedded Content section, drag and drop the Apptentive.xcframework folder from the Carthage/Build folder on disk.

XCFramework

You can download the latest release as a pre-built framework from our Github releases page and drag it into your project. This requires that you manually download any new releases of ApptentiveKit to keep your project up to date.

Sub-Project

You can also clone the ApptentiveKit repository and drag the ApptentiveKit.xcodeproj file into your project in Xcode. This requires that you manually pull any new code from the ApptentiveKit repository to keep your project up to date.

Import ApptentiveKit

Swift

Add import ApptentiveKit to each Swift file where you plan to reference Apptentive methods and properties (typically where you would also import the UIKit or Foundation frameworks).

Objective-C

Add @import ApptentiveKit; to each implementation file where you plan to reference Apptentive methods and properties (typically where you would import its corresponding header file).

Initialize the SDK

Early in your app’s lifecycle, it should call Apptentive’s register(with:completion:) method. For example:

import UIKit
import ApptentiveKit

class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    Apptentive.shared.register(with: .init(key: "<#Your Apptentive App Key#>", signature: "<#Your Apptentive App Signature#>"))
    
    // Set the log level to debug Apptentive
    ApptentiveLogger.default.logLevel = .debug

    // Other app initialization...

    return true
  }
}

CAUTION: The app credentials (Apptentive App Key and Apptentive App Signature) passed to the register(with:completion:) are saved to the SDK’s data store in the app’s Application Support directory and cannot be changed unless the app is fully uninstalled from the device/simulator. Installing a build with different app credentials without first uninstalling will result in a mismatchedCredentials error being passed to the completion handler, and, in development builds, an assertion failure.

NOTE: The easiest way to get started with ApptentiveKit is to use the shared instance of the Apptentive class (Apptentive.shared) to call its methods and access its properties. If you prefer, you can also explicitly create an instance of the Apptentive class (let myApptentiveInstance = Apptentive()) and manage the process of passing it to the places in your app that it will be used. In this case your app must never access the shared static property of the Apptentive class. Doing so will result in an assertion failure in debug builds and unpredictable behavior in release builds.

Engage Events

Events record user interaction. You can use them to determine if and when an Interaction will be shown to your customer. You will use these Events later to target Interactions, and to determine whether an Interaction can be shown. You trigger an Event with the engage(event:from:) method. This will record the Event, and then check to see if any Interactions targeted to that Event are allowed to be displayed, based on the logic you set up in the Apptentive Dashboard.

One good place to engage an event is when a view controller appears, for example in the view controller’s viewDidAppear(_:) method:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    // Engage the "viewed_list" event.
    Apptentive.shared.engage(event: "viewed_list", from: self)
}

Another good place to engage events is from the action methods in your view controllers:

@IBAction func likeArticle(_ sender: AnyObject?) {
    // ...

    // Engage the "liked_article" event.
    Apptentive.shared.engage(event: "liked_article", from: self)
}

If you want to engage an event when a modal view is dismissed, you will want to call the engage method in the completion block, and pass the presenting view controller as the from parameter:

@IBAction func save(_ sender: AnyObject?) {
    // save the item...

    self.dismiss(animated: true) { 
        // Engage the "saved_item" event.
        Apptentive.shared.engage(event: "saved_item", from: self.presentingViewController)
    }
}

This ensures that the view controller you pass in will still be visible if the event you engage results in an interaction being displayed.

Finally, you can engage an event when your app encounters an error:

do {
    try context.save()
} catch let error as NSError {
    print("Error saving context: \(error)")

    // Engage the "core_data_save_failed" event.
    Apptentive.shared.engage(event: "core_data_save_failed", from: self)
}

This may allow you to let users know if there is a workaround or app update that fixes the problem.

Using a Variable as the Event Name

The engage(event:from:) method accepts an Event object as its first argument (the Event object conforms to the ExpressibleByStringLiteral protocol, so in most cases you can treat events as strings). If you are passing a non-literal string, you will have to wrap it in an Event object:

engage(event: .init(name: myEventName), from: self)

We recommend that your app engage at least 10 distinct Events. This gives you the flexibility to choose the best place for Interactions to display after your app is live, without having to update your app.

Our web dashboard works best for up to several dozen unique event names. It does not work well if you auto-generate thousands of unique event names. If you plan to target users based on viewing a piece of content out of a collection of hundreds or thousands (say, SKUs in an online retail app), do not create event names for each piece of content. Instead, you can use Custom Person Data for item viewed.

For example, you could set a key of viewed_item with a value 123456. You could then target users for whom that key matches, or is not null.

Monitoring Events

The SDK will post a notification (Notification.Name.apptentiveEventEngaged) to the default NotificationCenter when an event is engaged, whether the source of that event is your app or the SDK itself.

Your app can listen to this notification and then examine the values in the userInfo dictionary for the following keys:

  • eventType: the extended name of the event, for example com.apptentive#Survey#submit
  • interactionType: the type of the interaction that engaged the event, or app if not applicable
  • interactionID: the internal identifier of the interaction that engaged the event, if applicable
  • eventSource: the source of the event, either com.apptentive (for events that are engaged by the SDK itself) or local.app (for events that are engaged by your app)

List of Internal Events

  • com.apptentive#<InteractionType>#launch (when an interaction is launched)
  • com.apptentive#<InteractionType>#cancel (when an interaction is dismissed)
  • com.apptentive#app#launch (when the app enters the foreground, or the SDK is first initialized following the app being terminated)
  • com.apptentive#app#exit (when the app enters the background)
  • com.apptentive#Survey#submit
  • com.apptentive#Survey#continue_partial (when a user continues with a survey after an action sheet is displayed that explains that they will discard any answers that they entered)
  • com.apptentive#Survey#cancel_partial (when a user exits a survey after the aforementioned action sheet is displayed)
  • com.apptentive#MessageCenter#read (when a previously-unread message in Message Center is displayed to the user)
  • com.apptentive#AppleRatingDialog#request (when requestReview is called on SKStoreReviewController)
  • com.apptentive#AppleRatingDialog#shown (when the above method call results in a review request being presented)
  • com.apptentive#AppleRatingDialog#not_shown (when the above method call does not result in a review request being presented)
  • com.apptentive#EnjoymentDialog#yes (when the user taps Yes in the Love Dialog)
  • com.apptentive#EnjoymentDialog#no (when the user taps No in the Love Dialog)
  • com.apptentive#NavigateToLink#navigate (when the SDK has opened a URL from a Note button)
  • com.apptentive#TextModal#interaction (when the SDK launches an interaction from a Note button)
  • com.apptentive#TextModal#dismiss (when the user taps the dismiss button in a Note)

Message Center

With the Apptentive Message Center your customers can send feedback, and you can reply, all without making them leave the app. Handling support inside the app will increase the number of support messages received and ensure a better customer experience.

Message Center lets customers see all the messages they have sent you, read all of your replies, and even send screenshots that may help debug issues.

⚠️ Note: Message Center uses a QLPreviewController instance to display attachments, which includes a default share sheet that allows saving images to the device’s photo library.

This feature requires a key to be added to the app’s Info.plist file under the “Privacy – Photo Library Usage Description” key. We suggest setting the value to something like “This will enable the Save Image feature for attachments.”

If this key is not present, iOS 15 devices will omit the Save Image option from the share sheet. Versions prior to iOS 15 will crash (in development builds) or fail silently (in release builds) if a photo library usage description is not set and the user chooses the Save Image option from the share sheet.

Showing Message Center

Find a place in your app for a button that will launch Message Center. This will allow customers to contact you with feedback, or questions if they are having trouble using your app, as well as allow them to see your responses.

import UIKit
import ApptentiveKit

class SettingsViewController: UIViewController {

  // ...

  @IBAction func openMessageCenter(sender: UIButton) {
    Apptentive.shared.presentMessageCenter(from: self)
  }
}

Checking Unread Message Count

You can also check to see how many messages are waiting to be read in the customer’s Message Center using Apptentive’s unreadMessageCount property. This property is compatible with Key-Value Observing (KVO), so your app can monitor it and be notified when it changes:

var observation = Apptentive.shared.observe(\.unreadMessageCount, options: [.new]) { _, change in
    print("Unread message count changed to: \(change.newValue!)")
}

Attachments

Attachments are messages that you can send from the SDK programmatically, which will be visible to you in the Conversation View, but will not be visible to your customers in Message Center. They are great for sending contextual information or logs from rare crash events.

Hidden File Attachments

let fileData = try Data(contentsOf: fileURL)

sendAttachment(fileData, mediaType: "application/zip")

Hidden Image Messages

let image = UIImage(named: "my image")

sendAttachment(image)

Hidden Text Messages

sendAttachment("Error creating file: \(error)")

Customer Information

Set Customer Contact Information

If you already know the customer’s email address or name, you can pass them to us to display in the conversation view on your Apptentive dashboard.

Apptentive.shared.personEmailAddress = <#Email Address#>
Apptentive.shared.personName = <#Person Name#>

Message Center provides dialogs that allow your customers to set their name and email as well. Calling the above methods will overwrite what your customer enters. If you don’t want to overwrite what they enter, you can check their values first, using Apptentive.shared.personEmailAddress and Apptentive.shared.personName.

Custom Data

You can send Custom Data associated with a person’s profile that is using the app, or the device. In particular, this is useful for sending a Customer ID and other information that helps you understand and support your users better. Custom Data can also be used for configuring when Interactions will run. You can add custom data of type String, Int, and Bool.

In general, Custom Data can be sent as Person Custom Data or Device Custom Data. However, if sending a Customer ID, you must send it as Person Custom Data. For more on the benefits of setting a Customer ID, see here.

After the Custom Data field has been set, it will appear on the targeting screen for any Interaction within a few minutes. You may need to refresh your browser to see recent changes.

Apptentive.shared.personCustomData["CustomerID"] = "1234321"
Apptentive.shared.personCustomData["city"] = "Seattle"
Apptentive.shared.personCustomData["points"] = 500
Apptentive.shared.personCustomData["is_premium"] = true

Apptentive.shared.deviceCustomData["primary_account"] = "test@apptentive.com"
Apptentive.shared.deviceCustomData["user_count"] = 5
Apptentive.shared.deviceCustomData["full_version"] = false

Because the CustomData type is a struct, you will need to use these alternative methods in Objective-C:

[Apptentive.shared addCustomPersonDataString: @"1234321", withKey: @"CustomerID"];
[Apptentive.shared addCustomPersonDataString: @"Seattle", withKey: @"city"];
[Apptentive.shared addCustomPersonDataNumber: @500, withKey: @"points"];
[Apptentive.shared addCustomPersonDataBool: true, withKey: @"is_premium"];

[Apptentive.shared addCustomDeviceDataString: @"test@apptentive.com", withKey: @"primary_account"];
[Apptentive.shared addCustomDeviceDataNumber: @5, withKey: @"user_count"];
[Apptentive.shared addCustomDeviceDataBool: false, withKey: @"full_version"];

Theming and Customization

There are several different options for customizing the look and feel of ApptentiveKit’s interactions.

Themes

The SDK will ordinarily apply a styling theme using Apptentive’s default colors alongside system fonts and symbols. This theme is designed to look consistent across our iOS and Android SDKs, but may differ from your app’s look and feel and the rest of the iOS system.

By setting the Apptentive class’s theme property to .none (note: this must be done before calling the register(with:completion:) method), the interactions take on a more native iOS look and feel, but it will differ substantially from the Android SDK.

Setting the theme to .none may also provide an easier starting point for customizing the user interface to your liking.

UIAppearance

With the use of the .none theme, the ApptentiveKit interaction UI will pick up certain UIAppearance overrides that your app has set (for example, navigation bar tint).

If an appearance setting in your app makes ApptentiveKit interactions unattractive or unreadable, you can use appearance(whenContainedInInstancesOf: [ApptentiveNavigationController.self]) to make a corrective appearance change to ApptentiveKit interactions (specifically those, like Message Center and Surveys, that use view controllers other than UIAlertController).

UIKit Extensions

For styling changes that aren’t amenable to UIAppearance, ApptentiveKit defines a number of extensions to common UIKit classes to allow setting colors, fonts, images, and more. For more information, see our forthcoming Customization Guide.

Overriding InteractionPresenter

For particularly extensive customizations, we recommend subclassing the InteractionPresenter class and setting your subclass as the value for Apptentive’s interactionPresenter property. You can override the methods that present each interaction type, instantiating your own view controllers and presenting them as you see fit. A view model for each interaction is provided to configure your view controllers for displaying the interaction and reacting to user input. More information on this technique will be added soon.

Updated on May 24, 2022

Was this article helpful?

Related Articles