Skip to main content
Version: 3.x

iOS

What you'll do
  1. Install the SDK
  2. Set up reward callbacks
  3. Initialize the SDK
  4. Display a placement

Later sections cover user attributes, the user identifier, placement details, custom parameters, and more.

Testing? Your app starts in test mode, so you'll need a test device to see content while you build.

Installation​

See the iOS example apps on GitHub.

Note

Minimum iOS version: 13.0, or 15.0 for SDK 3.8.1 and later.

Replace <version> below with your SDK version from GitHub releases.

CocoaPods​

Podfile
platform :ios, '13.0' # Use '15.0' for SDK 3.8.1 and later.

use_frameworks!

target 'MyApp' do
pod 'TapResearch', '<version>' # Omit the GitHub tag's leading "v".
end

Then run pod install in the Terminal.

Swift Package Manager​

Add the following URL in the Xcode Swift Package Manager:

https://github.com/TapResearch/TapResearch-iOS-SDK
  • Set the Dependency Rule to Exact Version or Up to Next Major Version and enter your SDK version
  • Set "Add to Project" to your project
  • Click "Add Package"

In the resulting "Choose Package Product for TapResearch-iOS-SDK" select the TapResearchSDK row and click "Add Package".

Adding the package with an AI agent

An agent running outside Xcode (a terminal or IDE agent) can add this Swift Package by editing your Xcode project file directly. An agent running inside Xcode (for example Xcode's built-in coding assistant) can't — Xcode holds the project file open, so it can't be modified while Xcode is running. In that case, add the package yourself with the steps above, then hand control back to the agent to continue.

Manual installation​

Download the source archive for a release from GitHub releases, drag TapResearchSDK.xcframework into your project, and set it to Embed & Sign under Frameworks, Libraries, and Embedded Content.

Importing the SDK​

Import the SDK in each file that calls it:

import TapResearchSDK

Integration​

Callbacks​

The TapResearch SDK has two main delegates you can implement: TapResearchSDKDelegate and TapResearchContentDelegate. If you are implementing the delegates as their own objects make sure that the delegate objects derive from NSObject, for example in Swift: class MyDelegates: NSObject, TapResearchSDKDelegate {.

TapResearchSDKDelegate​

  • onTapResearchSdkReady (required): Called when the SDK is ready for use. We recommend showing content only after this callback is called.
  • onTapResearchDidError (required): Called when an error has occurred in the TapResearch SDK. For the full list, see the error codes page.
  • onTapResearchDidReceiveRewards (optional): Called when a user has earned a reward(s). You can implement it here or set a separate reward delegate.
  • onTapResearchQuickQuestionResponse (optional): Called when a quick question result is being returned.

The class that conforms to the TapResearchSDKDelegate protocol (ideally your SceneDelegate) must implement onTapResearchSdkReady and onTapResearchDidError.

Reward object​

Each reward is a TRReward. See TRReward for its properties, including the iOS payoutEvent values.

Quick Question response​

New to Quick Questions? See Quick Questions for what they are and the response payload.

onTapResearchQuickQuestionResponse is an optional method of TapResearchSDKDelegate. It is called when a Quick Question response is being returned, and receives a TRQQDataPayload object.

Use a class to implement the SDK's delegates and pass it to TapResearch at initialization. In UIKit you can adopt the protocol on your SceneDelegate instead.

TapResearchSDKDelegates.swift
import TapResearchSDK

class TapResearchSDKDelegates: NSObject, TapResearchSDKDelegate {

func onTapResearchSdkReady() {
// The SDK is ready: send user attributes, show content, etc.
if let error = TapResearch.sendUserAttributes(attributes: ["attribute1": "some player attribute", "a_number": 12]) {
print("sendUserAttributes: \(error.code) \(error.localizedDescription)")
}
}

func onTapResearchDidError(_ error: NSError) {
print("onTapResearchDidError: \(error.code) \(error.localizedDescription)")
}

func onTapResearchDidReceiveRewards(_ rewards: [TRReward]) {
for reward in rewards {
print("reward: currency = \(reward.currencyName ?? "unknown"), amount = \(reward.rewardAmount)")
}
}

func onTapResearchQuickQuestionResponse(_ qqPayload: TRQQDataPayload) {
for question: TRQQDataPayloadQuestion in qqPayload.questions {
// ...
}
}
}

TapResearchRewardDelegate​

  • onTapResearchDidReceiveRewards: Called when a user has earned a reward(s).

Implementing onTapResearchDidReceiveRewards on your TapResearchSDKDelegate is optional. If you implement it, rewards can be sent to your app as soon as the SDK is ready. If not, your app will not receive any rewards until a reward delegate has been set.

Setting a reward delegate​

To set a reward handler when you are ready to receive rewards, use:

TapResearch.setRewardDelegate(myRewardDelegate)

The object you pass in must conform to TapResearchRewardDelegate and implement onTapResearchDidReceiveRewards.

When you no longer need the reward delegate you can simply pass nil to the same SDK function.

Warning

If you set the reward delegate from a view controller, for example in viewDidLoad, make sure to call TapResearch.setRewardDelegate(nil) when the view controller is no longer in the stack.

Note

Anytime you set a new reward delegate, or nil, it replaces the previously set value. For example: if you have a reward delegate available at init time then later set another reward delegate, the original delegate will be replaced by the new one.

TapResearchQuickQuestionDelegate​

  • onTapResearchQuickQuestionResponse: Called when a quick question result is being returned.

To set a Quick Questions response handler when you are ready to receive Quick Question responses, use:

TapResearch.setQuickQuestionDelegate(myQuickQuestionDelegate)

The object you pass in must conform to TapResearchQuickQuestionDelegate and implement onTapResearchQuickQuestionResponse.

When you no longer need the Quick Questions response delegate you can simply pass nil to the same SDK function.

Warning

If you set the Quick Questions response delegate from a view controller, for example in viewDidLoad, make sure to call TapResearch.setQuickQuestionDelegate(nil) when the view controller is no longer in the stack.

Note

Anytime you set a new Quick Questions response delegate, or nil, it replaces the previously set value. For example: if you have a Quick Questions response delegate available at init time then later set another Quick Questions response delegate, the original delegate will be replaced by the new one.

TapResearchContentDelegate​

  • onTapResearchContentShown: Called when content is successfully presented to the user.
  • onTapResearchContentDismissed: Called when content is dismissed.

You can use these callbacks to pause/resume audio, animations, etc. when content is shown or dismissed.

TapResearchContentDelegates.swift
class TapResearchContentDelegates: NSObject, TapResearchContentDelegate {

func onTapResearchContentShown(forPlacement placement: String) {
print("\(#function): \(placement) was shown")
}

func onTapResearchContentDismissed(forPlacement placement: String) {
print("\(#function): \(placement) was dismissed")
}
}

Initialization​

Tip

We recommend initializing TapResearch as early as possible in your application's lifecycle. This will ensure that your placements are refreshed by the time you are ready to show content.

To initialize the SDK, you'll need your app's API token, shown on your app's Settings tab in the Publisher Dashboard. Refer to the app setup guide for more information.

After obtaining your API Token, add the following snippet to the scene:willConnectToSession:options: method in your SceneDelegate class. Replace API_TOKEN with your API token and UNIQUE_USER_ID with a unique identifier within your application.

Don't put the token in Info.plist

Keep your API token and placement tag in a separate Swift config file (for example TapResearchCredentials.swift) and pass them to initialize. Do not add them to Info.plist — TapResearch never reads them from there, and on SwiftUI projects where Info.plist is auto-generated, hand-creating one to hold credentials will break your build. The token is only ever used in the initialize call.

If initializing the TapResearch SDK isn't possible inside the scene:willConnectToSession:options: method, try and do it as early as possible to ensure that your placements are refreshed by the time you are ready to show content.

Tip

The user identifier passed through initialization must be unique! Only initialize once you are able to provide a unique identifier. Re-using the same user identifier is not supported and will prevent your users from accessing our service.

SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }

// SceneDelegate conforms to TapResearchSDKDelegate
TapResearch.initialize(withAPIToken: apiToken, userIdentifier: userIdentifier, sdkDelegate: self) { (error: NSError?) in
if let error = error {
print("\(error.code) \(error.localizedDescription)")
}
}
}
Note

To change the user after the SDK has started, call setUserIdentifier.

Send user attributes​

User attributes are used to target specific users with content (ex: an offer). The most recent values received are used when determining which content to show.

Pass a dictionary of attributes to sendUserAttributes after the SDK is ready.

Attribute names must be strings and must not begin with tapresearch_, which is reserved for TapResearch. Use string or numeric values for targeting. For booleans, send "true"/"false" or 0/1 instead of native booleans.

Set clearPreviousAttributes to false to merge new values with existing attributes, or true to replace the attributes you previously sent.

ViewController.swift
func sendUserAttributes() {
let date = Date() // Current date and time
let formatter = ISO8601DateFormatter()

let iso8601String = formatter.string(from: date)
let dict: [AnyHashable: Any] = ["app-user": userIdentifier, "roller-type": "high", "roller-type-valid-until": Date().timeIntervalSince1970 + ViewController.threeHours, "some-date": iso8601String, "some-double": 1.11]
if let error = TapResearch.sendUserAttributes(attributes: dict, clearPreviousAttributes: true) {
print(error.localizedDescription)
}
}

You can also pass user attributes when you first initialize the SDK. This is done by changing the TapResearch.initialize(...) call to additionally pass a userAttributes dictionary and the clearPreviousAttributes flag.

Info

If user attributes are known at SDK initialization, it is preferable to pass them through initialize compared to using sendUserAttributes. This will result in quicker load times for targeted content.

let dict: [String: Any] = ["app-user": userIdentifier, "roller-type": "high", "roller-type-valid-until": Date().timeIntervalSince1970 + ViewController.threeHours]
TapResearch.initialize(withAPIToken: apiToken,
userIdentifier: userIdentifier,
userAttributes: dict,
clearPreviousAttributes: true,
sdkDelegate: self) { (error: NSError?) in
if let error = error {
print(error.localizedDescription)
}
}

Setting the user identifier​

You can change the user identifier after the SDK is ready by calling setUserIdentifier with a string.

TapResearch.setUserIdentifier("some-user-id")

Checking if the SDK is ready​

The SDK lets the app know it is ready using a callback:

func onTapResearchSdkReady() {
}

You can also check if the SDK is ready using the isReady call:

let ready: Bool = TapResearch.isReady()

Getting placement details​

Info
Don't cache placement details

Placement details can change as our SDK refreshes placements in the background, so it is not recommended to store or cache these values. Instead, refetch the details each time you need to use them, e.g. to display something in your UI.

To get details for a placement call getPlacementDetails:

let details: TRPlacementDetails? = TapResearch.getPlacementDetails("your-placement-tag") { (error: NSError?) in
// Handle error
}
if let details {
// Use the placement details
}

The TRPlacementDetails objects:​

@objc public final class TRPlacementDetails : NSObject, Encodable {
@objc public let name : String
@objc public let contentType : String
@objc public let currencyName : String
@objc public let isSale : Bool
@objc public let saleType : String?
@objc public let saleEndDate : String?
@objc public let saleMultiplier : Double
@objc public let saleDisplayName : String?
@objc public let saleTag : String?
@objc public let bonusBarProgress : TRBonusBarProgress?
}

@objc public final class TRBonusBarProgress : NSObject, Encodable {
@objc public let isActive : Bool
@objc public let currentCompletes : Int
@objc public let bonusWindowEndAt : String?
@objc public let bonusTiers : [TRBonusTier]?
@objc public let error : NSError?
}

@objc public final class TRBonusTier : NSObject, Encodable {
@objc public let tierNumber : Int
@objc public let completesNeeded : Int
@objc public let rewardAmount : Int
@objc public let status : String?
}

Displaying a placement​

Placements are locations and moments inside the game when content can be shown. To show content for a placement, you'll need to specify a placement tag.

Note that the show content calls are wrapped in a canShowContent check. This is to ensure that the placement is ready to be shown. If the placement is not ready, the SDK will return false. This helps guard against showing the user something that is not ready to be shown yet.

canShowContent accepts an error block. It is optional in Swift; in Objective-C you must pass a block or nil.

If there is an error while showing a placement, it will be returned in the completion handler. The error will contain a code and a description.

Placement tags are listed on your app's Manage tab in the Publisher Dashboard.

ViewController.swift
let canShow: Bool = TapResearch.canShowContent(forPlacement: placementTag) { (error: NSError?) in
// Optional: handle the error
}
if canShow {
let customParameters: [String: Any] = ["param1": 123, "param2": "abc"]

TapResearch.showContent(forPlacement: placementTag, delegate: self, customParameters: customParameters) { (error: NSError?) in
if let error = error {
print("\(error.code) \(error.localizedDescription)")
}
}
}

Passing custom parameters​

Custom parameters allow you to receive additional information about the user when they complete a survey. This can be used to filter out users who have already completed a survey, or to target specific users.

These params will be returned in your server-to-server postbacks.

There are a maximum of 5 custom parameters that can be passed per placement.

The below code is a zoomed-in view of the code above.

Note

Parameters can only be ASCII characters; Unicode is not supported. Values must be strings, numbers, or booleans.

let customParameters: [String: Any] = ["param1": 123, "param2": "abc"]
TapResearch.showContent(forPlacement: placementTag, delegate: self, customParameters: customParameters) { (error: NSError?) in
if let error = error {
print("Error \(error.code) \(error.localizedDescription)")
}
}

Granting boosts​

You can grant a boost to a user with the grantBoost function using Boosts you have set up for your app.

First implement the TapResearchGrantBoostResponseDelegate to receive the result of granting a boost:

func onTapResearchGrantBoostResponse(_ response: TapResearchSDK.TRGrantBoostResponse) {
if response.success {
// Perhaps update display in response to a successful boost
}
else {
if let error = response.error {
// Handle the error
}
}
}

Grant a boost:

// Assuming self implements TapResearchGrantBoostResponseDelegate
TapResearch.grantBoost("BOOST_TAG", delegate: self) { (error: NSError?) in
// Handle any error
}

The TRGrantBoostResponse object:​

@objc public final class TRGrantBoostResponse : NSObject, Encodable {
@objc public let boostTag : String
@objc public let success : Bool
@objc public let error : NSError?
}

NotificationCenter events​

Available from SDK 3.8.0--rc0.

Instead of implementing a delegate method for some callbacks, you can observe a notification on the default NotificationCenter.

Notification namePosted whenReplacesuserInfo
TapResearch.TapResearchSDKReadyThe SDK is ready to be usedonTapResearchSdkReady (TapResearchSDKDelegate)—
TapResearch.TapResearchDidErrorAn error occursonTapResearchDidError (TapResearchSDKDelegate)TapResearch.ErrorKey → NSError
TapResearch.TapResearchContentShownTapResearch content is shownonTapResearchContentShown (TapResearchContentDelegate)TapResearch.PlacementTagKey → placement tag String
TapResearch.TapResearchContentDismissedTapResearch content is dismissedonTapResearchContentDismissed (TapResearchContentDelegate)TapResearch.PlacementTagKey → placement tag String

To register, add an observer for each notification you need, for example TapResearch.TapResearchContentShown:

func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(handleTapResearchNotification(_:)), name: TapResearch.TapResearchContentShown, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleTapResearchNotification(_:)), name: TapResearch.TapResearchDidError, object: nil)
}

@objc func handleTapResearchNotification(_ notification: Notification) {
if let placementTag = notification.userInfo?[TapResearch.PlacementTagKey] as? String {
// Content shown (or dismissed) for placementTag
}
if let error = notification.userInfo?[TapResearch.ErrorKey] as? NSError {
// Handle the error
}
}

Need help?​

If you're experiencing issues or need assistance, reach out to developers@tapresearch.com.


Stay updated: watch the TapResearch iOS SDK on GitHub to get notified about new releases.