iOS Guide

Integration Guide

Click here to see the latest version in the iOS SDK Changelog

Requirements

Requires Xcode 12.5 or above.


Installing the SDK

Install using Swift Package Manager

This is the recommended way to install our SDK, this allows you to easily upgrade versions.

Add the following package dependency URL to your project by following the Apple documentation:

https://github.com/bryjai/grow-sdk-ios-spm

Install manually

Having access to the GrowSDK.xcframework you can integrate the SDK manually. To do that you just need to drag and drop this file into your Xcode project. There is no specific place you need to drop, but if you have the Frameworks group you can drop there. When prompted with the Choose options for adding these files make sure you mark Copy items if needed and select your application and extension targets. If you have several application targets and want to use the SDK on them check those targets as well.

For the application, target make sure Embed & Sign is selected for the GrowSDK.xcframework.

And for the extension make sure Do Not Embed is selected for the GrowSDK.xcframework.

Define capabilities

In order to make the SDK fully functional, it requires the developer to configure capabilities on the Application target and as well on the Extension target. The required capabilities are:

Caution: The App Group name needs to be the same on both Application and Extension targets.

To learn more about capabilities please check Apple documentation.

Enable device registration

Registering devices enables users of the Bryj platform to test their campaigns and check data collection. Unlike Android, you need to declare the URL scheme on your app on iOS to benefit from this feature.

To allow the user to retrieve the device ID to enable Grow debug features, declare a URL Scheme in the info tab of your Xcode project using the bundleId of your app as URL Scheme:

  1. Go to the info tab of the project targets.
  2. At the bottom you select the subsection called “URL Types”.
  3. Click the + sign at the bottom.
  4. Add the bundle ID of your app in both identifier and URL Schemes fields.

Initializing the SDK

Initialize on the Application

To configure the SDK, it is required an API Key provided by the platform and the App Group configured on your Xcode project. The SDK will not provide “Push+Landing” campaigns to your application without the App Group.

In your AppDelegate class file, import the GrowSDK framework.

import GrowSDK
#import <GrowSDK/GrowSDK-Swift.h>

Still in this AppDelegate, find the method application(_:didFinishLaunchingWithOptions:) and, on it,
create an AppConfigurationBuilder instance from the Grow framework. This instance will allow you to generate through the build() method the required AppConfiguration to be passed in the static method start(_:options:) of the main class Grow. This static method also requires the launchOptions.

The initialization of the SDK should be done before any other SDK, mainly if others SDKs handle crash reporting.

In the example below, a AppConfigurationBuilder is instantiated with the mandatory apiKey provided by the platform, and the mandatory appGroup configured by the developer on Xcode:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let configuration = Grow.AppConfigurationBuilder(apiKey: "YOUR_API_KEY", appGroup: "YOUR_APP_GROUP")
                             .build()
    Grow.start(configuration: configuration, options: launchOptions)
    // ...
    return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    id <AppConfiguration> _configuration = [[[AppConfigurationBuilder alloc]
                                             initWithApiKey:@"YOUR_API_KEY"
                                             appGroup:@"YOUR_APP_GROUP"]
                                            build];
    
    [Grow startWithConfiguration:_configuration options:launchOptions];
    
    // ...
    
    return YES;
}
To ensure our Customers comply with local data regulations. The SDK is by default opt-out analytics.
This means a minimal set of data will be sent to GROW until the end-users provides consent to be tracked. Please refer to the dedicated Analytics section in the Usage Guide to enable analytics.

Initialize on the Notification Service extension

To handle Grow Push campaigns, you must add a Notification Service extension to your app.

For this Extension Target make sure you have the GrowSDK included on the Frameworks and Libraries. If you didn’t use Swift Package Manager to install the SDK you need to select Do Not Embed on that option, since your application already embed it.

From the auto-generated files open the main Notification Service class that extends from UNNotificationServiceExtension and find the method didReceive(_:withContentHandler:). Inside this method create a ExtensionConfigurationBuilder instance from the GrowSDK framework passing mandatory fields apiKeyappGroup, and appBundleIdentifier. This instance will allow you to generate through the build() method the required ExtensionConfiguration to be passed in the static method didReceive(_:forConfiguration:withContentHandler:) of the main class Grow. This static method will return a GrowNotificationService object that you will need to save a reference to be able to forward the serviceExtensionTimeWillExpire() from Apple in case it times out.

Your extension class must look like one of the following depending if you choose Swift or Objective-C:

import UserNotifications
import GrowSDK
class NotificationService: UNNotificationServiceExtension {
    var service: GrowNotificationService?
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {     
        let configuration = Grow.ExtensionConfigurationBuilder(apiKey: "YOUR_API_KEY",
                                                              appGroup: "YOUR_APP_GROUP",
                                                   appBundleIdentifier: "YOUR_APP_BUNDLE_IDENTIFIER")
                                 .build()           
        service = Grow.didReceive(request, forConfiguration: configuration, withContentHandler: contentHandler)
    }
    override func serviceExtensionTimeWillExpire() {
        service?.serviceExtensionTimeWillExpire()
    }
}
#import <GrowSDK/GrowSDK-Swift.h>

@interface NotificationService ()
@property (nonatomic, strong) GrowNotificationService *service;
@end

@implementation NotificationService
    
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {

    id <ExtensionConfiguration> configuration = [[[ExtensionConfigurationBuilder alloc]
                                                   initWithApiKey:@"YOUR_API_KEY"
                                                   appGroup:@"YOUR_APP_GROUP"
                                                   appBundleIdentifier:@"YOUR_APP_BUNDLE_IDENTIFIER"]
                                                  build];
    
    self.service = [Grow didReceive:request forConfiguration:configuration withContentHandler:contentHandler];
}

- (void)serviceExtensionTimeWillExpire {
    [self.service serviceExtensionTimeWillExpire];
}
@end
If you need to implement the didReceive(_:withContentHandler:) method on your Notification Service extension, you must ensure to forward the call before your code.

Verifying integration

To check the SDK is properly integrated and configured in your app, you can enable the Verbose mode at SDK initialization and look at the console logs while your app is running from Xcode with your device connected to your computer.

Enabling analytics

For reporting activity logs from the tagging plan (User Identifier, Attributes & Events), analytics must be enabled in the SDK.
By default, analytics are disabled, and can be turned on by changing the analytics state of the SDK.

This to enable analytics, please refer to this paragraph

In the console logs you will be able to check:

  • Whether configuration is OK
  • Whether push integration is OK

In the following snippets, we will consider the bundle id is com.company.myapp and the api key is UKoJbzWq5Fz5hA

Enabling verbose mode

Set isVerboseEnabled to true in on the Configuration when initialising the SDK:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    let configuration = Grow.AppConfigurationBuilder(apiKey: "UKoJbzWq5Fz5hA", appGroup: "group.com.company.myapp")
                            .setIsVerboseEnabled(true)
                            .build()
    Grow.start(configuration: configuration, options: launchOptions)
    
    // ...
    
    return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    id <AppConfiguration> configuration = [[[[AppConfigurationBuilder alloc]
                                             initWithApiKey:@"UKoJbzWq5Fz5hA"
                                             appGroup:@"group.com.company.myapp"]
                                             setIsVerboseEnabled:YES]
                                            build];
    
    [Grow startWithConfiguration:configuration options:launchOptions];
    
    // ...
    
    return YES;
}

Checking configuration

When the app is started, meaning it was not installed or completely closed/killed before opening, the following logs should be printed in the console:

-----------------------------------------------------
Grow SDK v1.0.2
Bundle Identifier: com.company.myapp
Device id: 19193855-9771-4A10-8531-BF848AB17A04
-----------------------------------------------------
[Grow.AppConfiguration]
API Key: UKoJbzWq5Fz5hA
Is Verbose Enabled: true
Universal Link Domains: []
Is Analytics Enabled By Default: false
App Group: group.com.company.myapp
-----------------------------------------------------

Then look for the api/configuration request response, it should be {"domain":"valet.bryj.ai"}:

Request POST /api/configuration - Response code 200 - Response content {"domain":"valet.bryj.ai"}

This means the bundle id and the api key are known by the platform and the SDK has properly established communication with the server.

Checking push integration

To verify the push integration is OK, look for the api/deviceInfo request content, it should contain the pushToken field filled with a value:

Request POST https://valet-data.valet.bryj.ai/api/deviceInfo
{"trackingAllowed":0,"timeZone":7200,"pushToken":"4f39ceba6b96d8d29bbb77478d5fc0bb811efd32e85731b8ddc903455d35c818","manufacturer":"Apple","timeZoneName":"Europe\/Paris","lang":"eng","type":"phone","analyticsEnabled":0,"model":"iPhone10,6","pushType":1,"osVersion":"15.4.1","notificationsEnabled":0}

This means the push token has been sent to the server and that the platform will be able to send push to this device as soon as the device id will be ingested.

Integration troubleshooting

1. No data in the GROW UI

If you notice your some dashboard cards related to app activity are not populated despite the fact you made some sessions:

  • Double check you are testing the correct app
  • Verify the device is opt-in analytics (Usage Guide – Analytics): an opt-out analytics will not send behavioral data

2. Reception of Test push OK but I do not receive campaigns

Test pushs are both sent to APNS through Production and Sandbox whereas “real” campaigns sent from GROW solely use APNS Production.

Verify your app is built in release mode to ensure campaign reception.

3. Missing App Group

If you get the message “An app group must be set…” in the console, this means the SDK has been initialised without an app group defined on the SDK Configuration. To solve this, make sure to pass a non-nil string for the SDK Configuration app group parameter

4. Invalid App Group

If you get the message “Invalid app group.…” in the console, this means the app group identifier used at the SDK initialization is not recognized by the iOS framework. To solve this, make sure the provisioning profile used for your app target and notification service target contains the App Group entitlement and has the right app group identifier defined.

5. No push token

If there is no pushToken field in the api/deviceInfo request, as specified in the push integration verification section, this means there is a missing configuration on your project, or that there is a conflict with another library preventing the Grow SDK from retrieving the iOS token.

Please check that:

  • You have set and configured all the required capabilities on your application and extension targets
  • If you use another library that has push notification or analytics features (like Firebase), make sure the Grow SDK is the first library to be initialized in the AppDelegate’s application(_:didFinishLaunchingWithOptions:) method.

6. Request not Allowed

If you get, the “Request not allowed” error message in the console, this means the server has refused the SDK request at some point.

This can be for several reasons:

  • The app bundle id and the API key used in the SDK Configuration are not known by the platform. This message comes together with another message “either apiKey or applicationId doesn’t match an existing app on the Grow platform” which is printed only once by the SDK when it tries to retrieve the Server Configuration just after SDK is initialized. The SDK will retry to retrieve the Server Configuration from 4 hours after last retrieval attempt.
    To solve this, go to the Admins section on the platform, select your project and check that:
    • The bundle id is listed
    • The api key is the right one
    • Fix the problem and re-install the app to not have to wait for the 4 hours delay
  • The app requests limit has been reached. The SDK will retry to send requests from 24 hours after the first refused request.
  • The app has been revoked on the platform. The SDK will never retry to send any requests.

Advanced – Usage guide

Device

These methods allow you to identify users and manage notification and tracking consent

From the Device interface you have access to:

  • User identifier
  • Device identifier
  • Analytics enabled
  • Open Notification Settings If Needed Get Notifications Allowed
  • Request Notifications Authorization (iOS only)
  • Request Provisional Notifications Authorization (iOS only)

Identify Users

The following methods allow you to retrieve or value an identifier.

The Device ID is generated by GROW. It is not editable.

Retrieving User Identifier

let userId = Grow.Device.userId
NSString* userId = Grow.Device.userId;

Updating User Identifier

Grow.Device.userId = "new_user_id"
Grow.Device.userId = @"new_user_id";

Retrieving Device Identifier

let deviceId = Grow.Device.deviceId 
NSString* deviceId = Grow.Device.deviceId;

Analytics

The following methods allow you to manage user analytics by GROW SDK.

For reporting activity logs from the tagging plan (User Identifier, Attributes & Events), analytics must be enabled in the SDK.

By default, analytics are disabled and can be turned on by changing the analytics state of the SDK

Retrieving Analytics Enabled Status

let analyticsEnabled = Grow.Device.analyticsEnabled
bool analyticsEnabled = Grow.Device.analyticsEnabled; 

Updating Analytics Status

let enabled = true/false
Grow.Device.analyticsEnabled = enabled
bool enabled = true/false;
Grow.Device.analyticsEnabled = enabled;

Notifications Permissions

The following methods allow you to manage notifications settings according to iOS specificities.

Open Notification Settings If Needed

[Grow.Device openNotificationSettingsIfNeeded];
[Grow.Device openNotificationSettingsIfNeeded];

Get Notifications Allowed

Grow.Device.getNotificationsAllowed({ notificationsAllowed in
  print("Grow.Device NotificationsAllowed: \(notificationsAllowed)")
})
[Grow.Device getNotificationsAllowed:^(BOOL notificationsAllowed){
   NSLog(@"Grow.Device NotificationsAllowed: %d", notificationsAllowed);
}];

Request Notifications Authorization

Request Notifications Authorization is available for iOS only!
Grow.Device.requestNotificationAuthorization() 
[Grow.Device requestNotificationAuthorization];

Request Provisional Notifications Authorization

Request Provisional Notifications Authorization is available for iOS only!
Grow.Device.requestProvisionalNotificationAuthorization()
[Grow.Device requestProvisionalNotificationAuthorization];

Events

These methods are dedicated to the implementation of the tagging plan. They allow you to define events to track the activity of your users

These methods only will work with users who are “opt-in analytics”

From the Events interface, you have access to:

  • Custom events
  • Location events

Send a Simple Custom event

let name = "event_name"
Grow.Events.Custom.create(name).send()
NSString* name = @"event_name";
[[Grow.Events.Custom create:name] send];

Send a Custom Event with a Parameter

let name = "event_name"
let value = "Parameter value"
let key = "a_key"

Grow.Events.Custom.create(name)
                  .putValue(value, forKey: key)
                  .send()
NSString* name = @"event_name";
NSString* value = @"Parameter value";
NSString* key = @"a_key";

[[[Grow.Events.Custom create:name]
   putValue:value forKey:key]
   send];

Send a Location Event

If you wish, you can log the GPS coordinates of your users if they have their GPS enabled and the application is authorized to use these coordinates.
let location = CLLocation(latitude: 0.1, longitude: 0.1)
Grow.Events.Location.send(location)
CLLocation* location = [[CLLocation alloc] initWithLatitude:0.1 longitude:0.1];
[Grow.Events.Location send:location];

Attributes

These methods are dedicated to the implementation of the tagging plan. They allow you to define the status of a user based on its activitys.

These methods will only work with users who are “opt-in analytics”.
Attributes require a defined user identifier.

From the Attributes interface, you have access to:

  • String attributes
  • Number attributes
  • Boolean attributes
  • Date attributes

String Attributes

Setting a String Attribute

let value = "Attribute value"
let key = "a_key"
Grow.Attributes.setString(value, forKey:key)
NSString* value = @"Attribute value";
NSString* key = @"a_key";
[Grow.Attributes setString:value forKey:key];

Removing a String Attribute

let key = "a_key"
Grow.Attributes.setString(nil, forKey:key)
NSString* key = @"a_key";
[Grow.Attributes setString:nil forKey:key];

Number Attributes

Setting a Number Attribute

let value = NSNumber(value: 10.0)
let key = "a_key"
Grow.Attributes.setNumber(value, forKey:key)
NSNumber* value = @10;
NSString* key = @"a_key";
[Grow.Attributes setNumber:value forKey:key];

Removing a Number Attribute

let key = "a_key"
Grow.Attributes.setNumber(nil, forKey:key)
NSString* key = @"a_key";
[Grow.Attributes setNumber:nil forKey:key];

Boolean Attributes

Setting a Boolean Attribute

let value = true
let key = "a_key"
Grow.Attributes.setBoolean(value, forKey:key)
NSNumber* value = @TRUE;
NSString* key = @"a_key";
[Grow.Attributes setBoolean:value forKey:key];

Removing a Boolean Attribute

let key = "a_key"
Grow.Attributes.setBoolean(nil, forKey:key)
NSString* key = @"a_key";
[Grow.Attributes setBoolean:nil forKey:key];

Date Attributes

Setting a Date Attribute

let value = Date()
let key = "a_key"
Grow.Attributes.setDate(value, forKey:key)
NSDate* value = [NSDate date];
NSString* key = @"a_key";
[Grow.Attributes setDate:value forKey:key];

Removing a Date Attribute

let key = "a_key"
Grow.Attributes.setDate(nil, forKey:key)
NSString* key = @"a_key";
[Grow.Attributes setDate:nil forKey:key];

Campaigns

The following methods allow you to pause and resume the display of in-apps in specific paths of your application.

Pausing Campaign Display

Grow.Device.pauseInAppDisplaying()
[Grow.Device pauseInAppDisplaying];

Resuming Campaign Display

Grow.Device.resumeInAppDisplaying()
[Grow.Device resumeInAppDisplaying];

Privacy

These methods allow you to manage the collection and deletion of your users’ data.

From the Privacy interface, you have access to:

  • Request to Collect Data
  • Request to Erase Data
  • Request to Remove Account
  • Set Tracking Allowed

Request to Collect Data

Grow.Privacy.requestToCollectData()
[Grow.Privacy requestToCollectData];

Request to Erase Data

Grow.Privacy.requestToEraseData()
[Grow.Privacy requestToEraseData];

Request to Remove Account

Grow.Privacy.requestToRemoveAccount()
[Grow.Privacy requestToRemoveAccount];

Set Tracking Allowed

The purpose of this method is to track the status of the device related to the Apple tracking transparency and the related consent the user provided.
let allowed = true/false
Grow.Privacy.setTrackingAllowed(allowed)
bool allowed = true/false;
[Grow.Privacy setTrackingAllowed: allowed];