Link Search Menu Expand Document

Snapyr For iOS SDK: Swift

The Snapyr iOS SDK makes it simple to connect your iPhone or iPad apps to the Snapyr platform.

This document includes Swift examples. See Objective-C documentation here.

Snapyr supports any device running iOS 10.0 and higher.

Using the iOS SDK

Step 1: Install the Library

Automatically Via Cocoapods

We recommend using the Cocoapods system which makes versions of Snapyr easy to install and upgrade.

Add the Snapyr dependency to your Podfile, like so:

target 'MyApplication' do
    pod "Snapyr"
end

Then install by running

$ pod install

Manually

Download a zip file of the latest version of the framework from the Snapyr iOS SDK releases page.

Extract the zip file and add the Snapyr.framework file to your Frameworks folder.

Make sure the framework is both Linked with the Binary as well as Embedded. Be sure to check “Code Sign on Copy” as well (under Build Phases -> Embed Frameworks)

Embed Framework

Step 2. Initialize

Initialize wherever you wish, but generally the best place is in your application delegate’s application(_:didFinishLaunchingWithOptions:) method. Be sure to import the library in any class that uses it:

import Snapyr

You’ll need your app’s Snapyr Write Key. To obtain your write key, please contact Snapyr Customer Service.

let configuration = SnapyrConfiguration(writeKey: "YOUR_WRITE_KEY")
configuration.trackApplicationLifecycleEvents = true // Enable this to record certain application events automatically
configuration.recordScreenViews = true // Enable this to record screen views automatically
// Add this to enable Snapyr in-app messaging. See more info in in-app section below
// NOTE: requires Snapyr SDK 1.1.0 or later
configuration.actionHandler = { msg in
    print("Received Snapyr in-app message! \(msg)");
    // trigger your own callback code here
}
Snapyr.setup(with: configuration)

You can also automatically track screen views as well as lifecycle events such as Application Opened, Application Installed, Application Updated to start quickly with core events. These are enabled by default.

Main Snapyr SDK Calls

Identify

This lets you setup information about the current user and tie that individual to all actions taken. You can set traits for a specific user and these traits will be tied to every tracking action taken. Note that if you do not call Identify, the Snapyr SDK will generate an AnonymousID for the user.

Snapyr.shared().identify("a user's id", traits: ["email": "a user's email address"])

Snapyr recommends that you make an Identify call once when the user first registers or logs in to his / her account, and then call Identify again if traits are added – for example if the user links her account to Facebook or email and you now have desired data. Snapyr will merge any old traits with new ones and update any traits that use the same key.

Remember, you can replace the properties and traits in the code samples with variables that represent the data you actually collected.

The Identify call has the following fields:

userId NSString*,optional The unique ID for this user that your app uses.
traits NSDictionary *,optional A map of traits about the user, such as their first name, Facebook ID, email address, etc. This map must be flat. All keys are strings, and supported value types are string, boolean, integer, and float.

The SDK automatically sends the userId and anonymousId as traits.

Track

The Track call is at the heart of Snapyr and allows you to keep track of events or actions your users perform. Every event can also have associated properties.

Snapyr.shared().track("<event_name>", properties: ["<name>": "<value>"])

By default, Snapyr tracks a few key common events automatically such as the Application Installed, Application Updated and Application Opened. You can turn automatic tracking off during initialization by setting the trackApplicationLifecycleEvents paramater to false.

You might also want to track events that indicate key spots hit such as Registered, Logged In, Complete Tutorial, or Purchased an Item.

The Track call properties can be anything you want to record. For example:

Snapyr.shared().track("purchase", properties: ["item": "Bag of Gold", "revenue": 9.99])

The Track call includes the following fields:

name NSString *,required A name for the tracked action.
properties NSDictionary *,optional A map of properties for this action, e.g. revenue if the action was a purchase. This map must be flat. All keys are strings, and supported value types are string, boolean, integer, and float.

Retrieve AnonymousId

By default, a Snapyr user will be granted an anonymousID String tied to his or her device (if you don’t set one up explicitly using the Identity method). You can get this ID using the method:

Snapyr.shared().getAnonymousId

Reset

The Reset method can clear the SDK’s internal data for the current user, such as user traits. This is useful if a user logs out so that multiple users with different identities can be tracked properly. Note that when you call Reset, Snapyr will assign the new user an AnonymousID until a new id is explicitly set via the Identify method.

Snapyr.shared().reset()

Debug Logging

If you want to dive deeper into the Snapyr SDK and all of the events it is sending, you can enable logging.

Snapyr.debug(true)

We recommend setting debug to false for the production build of your app or game.

Opt-out

Due to various laws or age groups, you may need to opt out of tracking. You can turn tracking off using:

Snapyr.shared().disable()

This flag persists across device reboots, so you can call it once (such as in a settings screen) and Snapyr will remember your decision.

In-App Messaging

The Snapyr SDK makes it easy to handle in-app messages that are triggered by a Snapyr campaign.

Snapyr supports two different types of messages:

  • HTML overlay: if your campaign sends this type of message, the Snapyr SDK will render a window over your application showing the message automatically.
  • Custom: if your campaign sends this type of message, the Snapyr SDK will call a callback that you provide at config time. You can then decide how to use the data in this message - for example, you might update your user’s account balance, or jump to a different screen in your app.

Configuration

To get started, all you need to do is set a callback on configuration.actionHandler when initializing Snapyr, and provide a couple of details. See above for more information about intialization.

NOTE: In-app messaging requires Snapyr SDK version 1.1.0 or later.

let configuration = SnapyrConfiguration(writeKey: "YOUR_WRITE_KEY")
... // other config options here...
configuration.actionHandler = { msg in // add this section to enable in-app messaging
    print("Received Snapyr in-app message! \(msg)");
    // trigger your own callback code here
}
// Optional - change the frequency (in ms) at which Snapyr polls for new messages
// If omitted, the default polling rate is 30000 ms, i.e. once every 30 seconds
configuration.actionPollInterval = 5000
Snapyr.setup(with: configuration)

Fetching/Receiving In-App Messages

When you have in-app messaging enabled, the SDK handles fetching/receiving of in-app messages automatically. There are two ways in which the SDK can receive messages:

  1. Whenever your track or identify events are flushed to the back end, if this triggers any Snapyr campaigns that generate an in-app message for the current user, they will be returned by the back end and trigger in the SDK immediately.
  2. The SDK will also check the back end for any queued-up messages when it first begins, and then start polling the back end for new messages every 30 seconds, or at an interval that you specify in your config.

Acting on a custom InAppMessage

By setting configuration.actionHandler, you can provide your own code that will be triggered whenever a custom in-app message arrives. The value for this config is a function that receives a SnapyrInAppMessage object as its parameter.

The SnapyrInAppMessage Class

var content: SnapyrInAppContent { get } The content of the in-app message. This is defined in the Snapyr UI when setting up the campaign that triggered this message, and typically contains the custom data you'll want to reference in your callback code. See the next section for more details on SnapyrInAppContent.
var timestamp: NSDate { get } The datetime when the message was originally sent or scheduled from the back end
var actionType: SnapyrInAppActionType { get } An enum, either .custom, for a message that triggers your callback code, or .overlay, for a message that Snapyr automatically displays.
var actionToken: NSString { get } A unique token for this message, which is used for tracking KPIs such as impressions for this message.
var userId: NSString { get } The user ID that this message was sent to. This should generally be the same as the user ID that your current user is identified with. But in the event that your user has changed accounts, you may want to check that the userId on the message matches your current user ID before acting on the message.

The SnapyrInAppContent Class

var contentType: SnapyrInAppContentType { get } An enum, either .json or .html, as specified on the message and campaign in the Snapyr UI.
func getJsonContent() throws -> NSDictionary The content of a JSON message, parsed as an NSDictionary.
NOTE: only valid if the contentType for this message is .json; if not, this call will throw an exception.
func getHtmlContent() throws -> NSString The content of an HTML message, as an NSString.
NOTE: only valid if the contentType for this message is .html; if not, this call will throw an exception.

Tracking Analytics for In-App Messages

Snapyr lets you track user interaction metrics for your in-app messages to enable your team to measure the performance of your campaigns.

Automatic tracking with HTML Overlay messages

If you use an HTML overlay message, the Snapyr SDK automatically manages the entire message lifecycle - displaying, closing, and recording metrics. Metrics will be tracked as follows:

  • Impression - this metric is recorded as soon as the HTML overlay is displayed on the user’s screen.
  • Click - this metric is recorded any time a user clicks or taps one of the links or buttons within the overlay. If the click is on a link, the URL will be tracked as an additional piece of data.
  • Dismiss - if the user closes the overlay without clicking on something inside of it first, it’s recorded as a dismiss. If a user clicks a link, then later closes the overlay, it is not tracked as a dismiss.

Manual tracking for custom messages

For custom in-app messages, your code has full control over how, and whether, it displays content to the user. The Snapyr SDK can’t measure analytics automatically for custom code. Instead it provides a set of tracking functions that you can call from your code at the appropriate time. These calls cover the same set of metrics as those of HTML overlay messages.

Every incoming in-app message includes an actionToken parameter, which is a unique string for the message. You’ll need to pass this value back to the tracking calls, which allows Snapyr to automatically connect metrics back to the source message and campaign.

Impression: func trackInAppMessageImpression(withActionToken: NSString) Call immediately after you've presented a message to the user.
Click: func trackInAppMessageClick(withActionToken: NSString) trackInAppMessageClick(final @NonNull String actionToken) Call when a user clicks on, or otherwise has a positive engagement with, the message. Use this method if you don't have any additional metadata to record for this click.
Click: func trackInAppMessageClick(withActionToken: NSString, withProperties: NSDictionary) Call when a user clicks on, or otherwise has a positive engagement with, the message. Use this method if you have additional data to record for this click, which you can include as a Dictionary of properties. For example, you might include the url for a link that was clicked.
Dismiss: func trackInAppMessageDismiss(withActionToken: NSString) Call if your user dismisses the message without first performing any clicks or other positive engagement.

Push Notification Calls

Snapyr makes it easy to trigger and track Apple push notifications (APNs).

Setting Up Push Notifications

In order for APNs to work, you will need to make sure your app ID supports Push Notifications. To do this you’ll need access to a paid Apple Developer account. You will also need a Mac with XCode 11+.

  1. Go the the ‘Identifiers’ section under the Certificates, Identifiers, & Profiles of page of your Apple Developer account

  2. Make sure Push Notifications are checked on.

  3. If you haven’t already created a Push Notification SSL Certificate go ahead and create one by tapping ‘Configure’ and then ‘Create Certificate’

  4. Choose platform as ‘iOS’ and then ‘Choose File’ to upload your Certificate Signing Request. If you don’t have a CSR file yet, see the next section. Hit ‘Continue’

  5. Hit ‘Download to download your certifiate as a cer file.

  6. You now can tie your Push Notification certificate back to your development machine by double-clicking on the cer file in Finder.

  7. This opens the Keychain Access app on your Mac. Now select ‘Login’ > ‘My Certificates’ to see the certificate you just imported.

  8. Right click on the certificate and key and select ‘Export “Apple Push Services” as the option. Save it as a p12 file with a filename that will be easy to find later. You can also select a password of your choosing – pick something you can remember later.

  9. You will need to upload the p12 to the Snapyr platform while onboarding, along with its password. See the Onboarding Documentation for more information.

Creating a Certificate Signing Request file

You can easily generate a new certificate from a Certificate Authority to prove that your personal machine is the one setting up Push Notifications.

  1. Open the Keychain Access app which comes with every macOS. Go to the ‘Keychain Access’ menu and choose: ‘Certficiate Assistant’ > ‘Request a Certificate From a Certificate Authority…’

  2. Fill in your email address, Common Name, and choose ‘Save to Disk’ then hit ‘Continue’ to save your new CSR file to your disk. Name it something handy so you can find it later.

Enabling Push Notifications in Your XCode App

  1. In XCode, select your main app target’s project settings and choose the ‘Signing & Capabilities’ tab.

  2. Make sure to select ‘All’ so all environments are covered.

  3. Make sure ‘Background Modes’ and ‘Push Notifications’ show up as capabilities.

  4. If not, tap ‘+ Capability’ and then select ‘Push Notifications’ and do the same for ‘Background Modes’

  5. Under ‘Background Modes’, make sure ‘Remote notifications’ is checked.

Sending Up Your Token

Your app will need to send up each user’s push notification token, so that the Snapyr platform can send the APN to the right device. To have your app request push notificattions add the following to your AppDelegate.swift:

import UserNotifications

You may need to add the UserNotifications.framework to your Frameworks (to the ‘Linked Frameworks and Libraries’ in the General settings of your project).

Then to register for push, add the following near the end of application(_:didFinishLaunchingWithOptions:), just before the return:

// Push notifications
if #available(iOS 10, *) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
        guard error == nil else {
            print("Error with push notifications \(String(describing: error))")
            return
        }
        if granted {
            DispatchQueue.main.async {
                application.registerForRemoteNotifications()
            }
        }
        else {
            print("User denied push.")
        }
    }
    application.registerForRemoteNotifications()
}

After the application(_:didFinishLaunchingWithOptions:) method, add the following code. This will interact with various parts of the push notification handling system. Feel free to customize this code to your needs - for example, you may wish to hide foreground notifications instead of displaying them, so that notifications don’t interrupt your user’s gameplay.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // After successful push registration, this code decodes the device token and registers it with Snapyr. This is required to allow Snapyr campaigns to send push notifications to the device.
    let deviceTokenString = deviceToken.map {String(format:"%02.2hhx",$0)}.joined()
    Snapyr.shared().setPushNotificationToken(deviceTokenString)
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    // This tells Snapyr that a notification successfully arrived on the device, and is required to allow your Snapyr campaigns to track the "received" rate for campaigns.
    if let snapyrData = userInfo["snapyr"] as? [String: AnyObject] {
        Snapyr.shared().pushNotificationReceived(snapyrData)
    }
    completionHandler(UIBackgroundFetchResult.noData)
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    if let snapyrData = response.notification.request.content.userInfo["snapyr"] as? [String: AnyObject] {
    // This tells Snapyr that a notification was tapped, and is required to allow your Snapyr campaigns to track the "clicked" rate for campaigns.
        Snapyr.shared().pushNotificationTapped(snapyrData)
    // If the notification from the Snapyr campaign has a deep link URL set, the following code will open it.
        if let urlString = snapyrData["deepLinkUrl"] as? String,
            let url = URL(string: urlString) {
            UIApplication.shared.open(url, completionHandler: nil)
        }
    }
    // Do not remove the following line!
    completionHandler()
}

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    // This method is triggered if a notification is received while the app is in the foreground.
    // This tells Snapyr that a notification successfully arrived on the device, and is required to allow your Snapyr campaigns to track the "received" rate for campaigns.
    if let snapyrData = notification.request.content.userInfo["snapyr"] as? [String: AnyObject] {
        Snapyr.shared().pushNotificationReceived(snapyrData)
    }
    // Optional: by default, notifications received in the foreground are not displayed. If you would like to display the notification over the app, run the following line.
    completionHandler(UNNotificationPresentationOptions.banner)
}

Features to enable rich push notification functionality

Snapyr allows marketers to create push notification templates that include rich media and interaction capabilities, such as embedded images in the notification.

In order to enable these capabilities, we need to add a Notification Service Extension to the app.

First, add a new Notification Service Extension target to the project:

  1. Open the project settings. Under the target list, click the + on the bottom to add a new target: Add Target

  2. Find and select Notification Service Extension, and click Next. Notification Service Extension

  3. Enter a name of your choice for the extension, and be sure to select your team in the dropdown. Xcode will automatically append the name you enter to the name of the primary target to produce a matching Bundle Identifier. Click Finish to create the extension. Enter Extension Name

    • NOTE: if Xcode shows a prompt asking if you want to activate the new scheme, you can simply click Cancel.

You now have a Notification Service Extension! Now we need to update the code in NotificationService.swift to handle rich push features.

In the Xcode file navigator, find and open NotificationService.swift under the new extension, and update the code to the following:

import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        // This method will be called when the notification arrives on the device, before the notification is displayed
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            // Download Snapyr-provided image from URL, if specified
            if let snapyrData = request.content.userInfo["snapyr"] as? Dictionary<String, AnyObject>,
               let urlPath = snapyrData["imageUrl"] as? String,
               let url = URL(string: urlPath) {
                // Notification image must be a url to a local (on-disk) file...
                // Fetch image from network and store in a temp file
                let destination = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(url.lastPathComponent)
                do {
                    let data = try Data(contentsOf: url)
                    try data.write(to: destination)
                    // empty string identifier lets system generate its own unique ID
                    let attachment = try UNNotificationAttachment(identifier: "", url: destination)
                    bestAttemptContent.attachments = [attachment]
                } catch {
                    // On failure, do nothing - notification will continue to process w/o image
                    print("Could not fetch notification image from URL")
                }
            }
            
            contentHandler(bestAttemptContent)
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // In the event that processing rich features takes longer than iOS allows, we'll continue to display the basic notification.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

}

Testing Push Notifications

Please note that by default, Snapyr push channels connect to the APNS production environment. To test a tethered device while developing in Xcode, you can configure your push channel in Snapyr to enable Sandbox mode. Be sure to disable Sandbox mode on the push channel when you are ready to release your app.

For local/development testing, you can also use a utility such as this push notification tester on Github.

You can use the following sample push notification payload for testing:

{
    "aps": {
        "alert": {
            "title": "Hello from Snapyr!",
            "body": "Take a look at this campaign."
        },
        "mutable-content": 1
    },
    "categoryId": "cat1",
    "deepLinkUrl": "http://www.google.com",
    "imageUrl": "https://developers.snapyr.com/assets/logo.png",
    "actionToken": "YjJjNjExZWUtMTkxMC00NzM2LWJhMDktOTJkOWMwNjdjMWY3OmRlZDBjODRkLTRmNDktNDFiMS1hYjk2LWQwYmFkZDdlZDYzYjowMGI2NmVkNy01ZWUyLTRlMzgtODRjMS01ZDNlY2ViNWUwOGY6OTc5MDI1Y2YtYmUyNy00NDNlLTg1NjEtMDJmYzc5YTVkYzdmOnB1Ymxpc2g6ODE1OWMyOTItMWJiMS00ZDE5LWI0Y2EtNmIzOWI4ZmM3YTE5OnBhdWwxNjp0YmQ6MTYzNjQ3Njk0MDphY3Rpb25Ub2tlbi04MTU5YzI5Mi0xYmIxLTRkMTktYjRjYS02YjM5YjhmYzdhMTkucGF1bDE2LjE2MzY0NzY5NDA=",
    "actionButtons": []
}