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
- Select Up to Next Major Version as Dependency Rule and make sure to set the current SDK version as the minimum version:
- Choose your main application target and validate:
- 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.
- 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:
- Push Notifications
- Background Modes
- Select options Background fetch and Remote notifications.
- App Group
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
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:
- Go to the
info
tab of the project targets. - At the bottom you select the subsection called “URL Types”.
- Click the
+
sign at the bottom. - Add the bundle ID of your app in both
identifier
andURL 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.
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;
}
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:
Parameter | Type | Default Value | Description |
apiKey | String | This mandatory parameter allows the SDK to authenticate with the platform. It must be retrieved from the platform in Admins → Your Project → Settings | |
appGroup | String | This mandatory parameter allows the SDK to communicate with its Notification Extension counterpart. | |
isVerboseEnabled | Boolean | False | This 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. |
isAnalyticsEnabledByDefault | Boolean | True | This 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. |
universalLinkDomains | Array of Strings | Empty array | This 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:
- Declare a new
service
property of typeGrowNotificationService?
which will store the Grow SDK Notification Service instance. - In the method
didReceive(_:withContentHandler:)
, create anExtensionConfigurationBuilder
instance by passing your App Group to the constructor, and call itsbuild()
method to generate an actualExtensionConfiguration
. - Then call
Grow.didReceive(_:forConfiguration:withContentHandler:)
to retrieve the Grow SDK Notification Service instance and store it into theservice
property previously created. Make sure to pass to this method therequest
andcontentHandler
arguments from the caller method, as well as theExtensionConfiguration
created at step 2. - In the method
serviceExtensionTimeWillExpire()
, Callservice?.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
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
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.
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.
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
Grow.Device.requestNotificationAuthorization()
[Grow.Device requestNotificationAuthorization];
Request Provisional Notifications Authorization
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
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
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.
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
let allowed = true/false
Grow.Privacy.setTrackingAllowed(allowed)
bool allowed = true/false;
[Grow.Privacy setTrackingAllowed: allowed];