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.

  1. Add the following package dependency URL to your project by following the Apple documentation:
https://github.com/bryjai/grow-sdk-ios-spm
  1. Select Up to Next Major Version as Dependency Rule and make sure to set the current SDK version as the minimum version:
  2. Choose your main application target and validate:
  3. If you use Xcode 13 or lower, in the project settings, add the GrowSDK framework into Frameworks and Libraries for each application and extension target where you want to use the SDK.
  4. If you use Xcode 14, no additional configuration is needed

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.

Enable the Grow refresh task

This is important to allow the Grow SDK to execute tasks when the app is in background.

In the Info.plist file of your app, add the ai.bryj.grow.background.refresh string item to the Permited background task scheduler identifiers array (which should be added if not already present in your file):

Initializing the SDK

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>

To initialize the SDK, call the Grow static method start(configuration:options:) from your implementation of application(_:didFinishLaunchingWithOptions:) in the AppDelegate. The AppConfiguration required to initialize the SDK is provided by the AppConfigurationBuilder thanks the to build() method.

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

Initializing on the Application side, with a default Configuration

In the example below, an AppConfiguration is instantiated with the following mandatory information:

  • The apiKey retrieved from the platform in Admins → Your Project → Settings
  • The appGroup configured on your Xcode project in Project → Your App Target → Signing & Capabilities → App Groups.
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.

Initializing on the Application side, with a custom Configuration

The AppConfiguration describes to the SDK how it should behaves on the application side, by defining the following parameters:

ParameterTypeDefault ValueDescription
apiKeyStringThis mandatory parameter allows the SDK to authenticate with the platform. It must be retrieved from the platform in Admins → Your Project → Settings
appGroupStringThis mandatory parameter allows the SDK to communicate with its Notification Extension counterpart.
isVerboseEnabledBooleanFalseThis controls which type of message the SDK can print to the console. You can check SDK messages thanks to the Xcode console.
If this parameter is false, the SDK will only print Info, Error and Warning messages, which are general purpose messages with low level of detail.
If this parameter is true, the SDK will also print detailed Debug messages, additionally to Info, Error and Warning messages. Those Debug messages show SDK interaction with the platform, as well as internal SDK mechanism.
isAnalyticsEnabledByDefaultBooleanTrueThis defines whether the SDK will send send events and attributes to the platform.
It’s false by default, meaning events and attributes will not be sent to the platform, until the method Grow.Device.setAnalyticsEnabled(true) is called later in the app flow.
Having this parameter set to true means the SDK is allowed to send events and attributes to the platform since its very first initialization, until Grow.Device.setAnalyticsEnabled(false) is called later in the app flow.
universalLinkDomainsArray of StringsEmpty arrayThis must be the list of associated domains which are supported in your app, if your app can handle Universal Links.
Those domains are used to let the SDK opens into the app any Universal Link located in an in-app message.

In the example below, an AppConfiguration is instantiated with the necessary parameters to let the SDK behaves as following:

  • Events and attributes are allowed to be sent since the very first SDK initialization
  • Detailed Debug messages will be printed
  • Any Universal Link with the domains “www.example.com” and “example.com” and located in an in-app message will be opened into the host application
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    let configuration = Grow.AppConfigurationBuilder(apiKey: "YOUR_API_KEY", appGroup: "YOUR_APP_GROUP")
                            .setAnalyticsEnabled(true)
                            .setIsVerbose(true)
                            .setUniversalLinkDomains(["example.com", "www.example.com"])
                            .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"]
                                            setIsAnalyticsEnabledByDefault:true]
                                           setIsVerboseEnabled:YES]
                                          setUniversalLinkDomains:@[@"example.com", @"www.example.com"]]
                                          build];
    
    [Grow startWithConfiguration:configuration options:launchOptions];
    

    
    return YES;
}

Initialize on the Notification Service extension

In order 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 in 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 embeds it.

Open the auto-generated NotificationService class which extends UNNotificationServiceExtension and add the following code to it:

  1. Declare a new service property of type GrowNotificationService? which will store the Grow SDK Notification Service instance.
  2. In the method didReceive(_:withContentHandler:), create an ExtensionConfigurationBuilder instance by passing your App Group to the constructor, and call its build() method to generate an actual ExtensionConfiguration.
  3. Then call Grow.didReceive(_:forConfiguration:withContentHandler:) to retrieve the Grow SDK Notification Service instance and store it into the service property previously created. Make sure to pass to this method the request and contentHandler arguments from the caller method, as well as the ExtensionConfiguration created at step 2.
  4. In the method serviceExtensionTimeWillExpire(), Call service?.serviceExtensionTimeWillExpire().

Your NotificationService class should look like the following:

import UserNotifications
import GrowSDK

class NotificationService: UNNotificationServiceExtension {
    
    var service: GrowNotificationService?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        
        let configuration = Grow.ExtensionConfigurationBuilder(appGroup: "YOUR_APP_GROUP")
                                 .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]
                                                   initWithAppGroup:@"YOUR_APP_GROUP"]
                                                  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 with Debug Scanner

The Grow SDK can display a Debug Scanner screen providing information about its integration into your app. This allows you to troubleshoot potential integration issues.

To do so, on the the Grow platform, go to the Debug section, select your project, select your app and scan the QR code displayed in your browser:

If integration is OK, the Debug Scanner header will display only green checks and each information card will display their related value:

Verifying integration with console logs

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:@"YOUR_API_KEY"
                                             appGroup:@"YOUR_APP_GROUP"]
                                            setIsAnalyticsEnabledByDefault:true]
                                           setIsVerboseEnabled:YES]
                                          setUniversalLinkDomains:@[@"example.com", @"www.example.com"]]
                                          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.1.0
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];