Prerequisites
Minimal version of iOS
The current version of the FollowAnalytics SDK works with iOS version 9.0 and above.
Before you start to integrate the SDK into your app, you need to register your app and generate its API key on the FollowAnalytics platform, by following the instructions here.
Getting Started
In this section, you will find the basic steps to integrate the SDK into your app:
- Installing the SDK in your project from CocoaPods
- Installing the SDK in your project with Switft Package Manager
- Initializing the SDK using your API key
- Setting up push notifications
Once the integration is finished, we highly recommend you test the setup. Then, you can start tagging events and saving attributes in your app.
Installation from CocoaPods
Starting with CocoaPods
The best way to install the SDK is with CocoaPods. This will allow you to easily update the SDK when new versions are released. If you have not installed CocoaPods yet, you may refer to this site, where you can install Cocoapods.
Before you start, be sure to have a Podfile. You could create one by writing pod init
in your terminal in your project. To open your Podfile, you could find it in your Workspace, or by writing open -a Xcode Podfile
in the terminal.
-
Add
pod 'FollowAnalytics','~> 6.9.0'
in the Podfile (see screenshot below) -
Run
pod repo update
from the command line. This will enable CocoaPods to detect the latest available version of FollowAnalytics. -
Run
pod install
Now FollowAnalytics is successfully installed.
Use the .xcworkspace file
To open your project with Xcode, use the .xcworkspace file generated by CocoaPods.
Installation from Swift Package Manager
Starting with Swift Package Manager
Swift Package Manager is the Apple tool for native implementation of Swift dependencies. To learn more about this you may refer to the official documentation.
| Package Link: https://github.com/followanalytics/FollowAnalytics-SDK-iOS-SPM
-
Head over to your project in Xcode and Click File -> Swift Packages -> Add Package Dependency.
-
From the wizard enter the package link and proceed.
-
Select the pretended version or select master to keep up with the latest versions and complete.
-
Select your project target to the FollowAnalytics framework and select your Notification Extension to the FANotificationExtension framework.
-
After complete the dependencies should exist on the left menu of your project.
Manual installation
Cocoapods is the preferred method
Even though you can install the SDK manually, cocoapods is the preferred method, since it will take care of much of the work and ensure your SDK is easily updated.
Setting up FollowAnalytics SDK on Xcode 12.3 and greater
-
Copy the FollowAnalytics.framework into your project directory. If you want to use it from a different directory you also need to update the
Framework Search Paths
from theBuild Settings
with that directory. -
Go to your Xcode project’s
General
settings of your target, drag and drop the FollowAnalytics.framework in theFrameworks, Libraries, and Embedded Content
section. Make sureDo Not Embed
is set for the FollowAnalytics.framework. -
From the
Build Settings
tap on the + button and selectAdd User-Defined Setting
. Name the setting asFA_SDK_PATH
and indicate the finder path where the FollowAnalytics.framework exist. E.g. if you have the framework inside a folder namedFrameworks
on the project root use$SRCROOT/Frameworks
. -
Create a new
Run Script Phase
in your app’s targetBuild Phases
and paste the following snippet in the script text field:bash "${FA_SDK_PATH}/FollowAnalytics.framework/embed-frameworks.sh"
This step is required to work around an App Store submission bug when archiving universal binaries and to work around the linker about multi architecrture configurations.
Setting up FollowAnalytics SDK on Xcode 12.2 and below
-
Copy the FollowAnalytics.framework into your project directory. If you want to use it from a different directory you also need to update the
Framework Search Paths
from theBuild Settings
with that directory. -
Go to your Xcode project’s
General
settings of your target, drag and drop the FollowAnalytics.framework in theFrameworks, Libraries, and Embedded Content
section. -
Create a new
Run Script Phase
in your app’s targetBuild Phases
and paste the following snippet in the script text field:bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/FollowAnalytics.framework/strip-frameworks.sh"
This step is required to work around an App Store submission bug when archiving universal binaries.
Initialize the SDK with your API key
Prerequisites: Generate your API key
If you haven't already, you can generate the API of your app by following the instructions here.
-
Import the FollowAnalytics framework in your AppDelegate.
-
Inside your
UIApplicationDelegate
implementation, create a configuration object and set the required fields -
Just below the configuration object, start the SDK
Your code should look like this:
#import <FollowAnalytics/FollowAnalytics.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
// ....
// as early as possible
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
config.apiKey = @"YOUR API KEY";
#if DEBUG
config.apiMode = FollowAnalyticsAPIModeDev;
#else
config.apiMode = FollowAnalyticsAPIModeProd;
#endif
}];
[FollowAnalytics startWithConfiguration:configuration startupOptions:launchOptions];
//....
}
// ..
@end
import FollowAnalytics
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// ....
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.apiKey = "YOUR API KEY"
#if DEBUG
config.apiMode = .dev
#else
config.apiMode = .prod
#endif
}
FollowAnalytics.start(with: configuration, startupOptions: launchOptions)
// ....
}
}
You can configure the SDK with all the available parameters which you can find here.
Setting up push notifications
To set up push notification, you will need to perform the following steps:
- Generate and import a p12 push certificate or a p8 authentication key to the FollowAnalytics platform.
- Add push notification capabilities to your XCode project.
- Call the notification authorisation request method from your code to prompt the user to allow your app to send notifications.
- Eventually, to validate your app, you will need to enable device registration for sending the device ID to the platform, so you can use the device observer.
We recommend to use p8 authentication key
We strongly recommend using a p8 authentication key as it is valid for all the apps added to your Apple developer account and doesn't have an expiration date. While a p12 certificate is only valid for a unique app and must be renewed each year to continue sending push notifications to your app.
Generate and import a p12 push certificate
-
If you don't have a Certificate Signing Request yet, create one by following instructions here.
-
Go to your Apple developer account in the Certificates, Identifiers & Profiles page.
-
Click on the Identifiers tab.
-
If you already have an app Identifier (App ID), click on your App ID, otherwise click on the + button and create a new App ID.
-
In the list of Capabilities, check the Push Notifications box and click on Save.
-
Click on the Certificates tab.
-
Click on the + button to add a new certificate.
-
Select Apple Push Notification service SSL (Sandbox & Production) and click on Continue.
-
Select your App ID in the list and click on Continue.
-
In the file picker, select the previously created Certificate Signing Request from your disk and click on Continue.
-
Click on Download to retrieve the .cer certificate file.
-
Double-click the downloaded certificate, this should open the Keychain Access app.
-
Locate the certificate in Keychain Access under Certificates, right-click on it, select Export Apple Push Services:… and save it as a .p12 file.
-
Enter a password for your certificate.
-
Go to the Administration page of your app on the FollowAnalytics platform.
-
Add the exported .p12 file and click on Proceed.
-
Enter the certificate password and click on Proceed.
Do not forget to ensure your provisioning profile has the Push Notifications service enabled by expanding it from the list in your developer portal.
Generate and import a p8 authentication key
-
Go to your Apple developer account in the Certificates, Identifiers & Profiles page.
-
Click on the Keys tab.
-
Click on the + button to add a new Key.
-
Enter a name in the Key Name field.
-
Check the Apple Push Notification service (APNs)
-
Click on Continue and then on Register.
-
Click on Download to retrieve the .p8 file. Note that once downloaded, you will not be able to download the p8 file again.
-
Get back to the Keys list and click on the Identifiers tab.
-
If you already have an app Identifier (App ID), click on your App ID, otherwise click on the + button and create a new App ID.
-
In the list of Capabilities, check the Push Notifications box and and click on Save.
-
Go to the Administration page of your app on the FollowAnalytics platform.
-
Add the downloaded .p8 file and click on Proceed.
-
Enter your Key ID and Issuer Key. Your Key ID can be found from the Keys tab of the Certificates, Identifiers & Profiles page in the Apple developer account. Your Issuer Key is your team ID, it can be found from the Membership page in the Apple developer account.
Do not forget to ensure your provisioning profile has the Push Notifications service enabled by expanding it from the list in your developer portal.
Push notification capabilities
In the Capabilities tab of your Xcode Project:
-
Enable Push Notifications by setting the switch to ON.
-
Enable the
Remote notifications
capability in the Background Modes:This will ensure that FollowAnalytics can detect uninstalls and send Silent Push Notifications.
Enable quiet notifications
Since iOS 12, Apple introduced a way to receive non-interruptive notifications before the user grants notification authorization. These are notification delivered quietly (no sound, no banner) and that are only displayed in the Notification Center.
You can allow your app to receive quiet notifications from FollowAnalytics as soon as it's installed on the user's device. To do so, just call requestProvisionalNotificationAuthorization
in the didFinishLaunchingWithOptions
method of your app delegate, after the SDK initialization call.
+ (void)requestProvisionalNotificationAuthorization;
static func requestProvisionalNotificationAuthorization()
Prompt the user to allow notifications
Later in the user experience, you can ask the user to provide its authorization for notifications. You can do this by calling the requestNotificationAuthorisation
method at some point:
+ (void)requestNotificationAuthorization;
static func requestNotificationAuthorisation()
If you don't call and user hasn't allowed notifications, your app will only be able to receive silent notifications.
Enable device registration
Registering devices on iOS
Registering devices is enables users of the FollowAnalytics platform to test their campaigns. Unlike Android, you need to declare the URL scheme on your app on iOS so the users can use this feature.
To allow the user to retrieve the device ID for testing from the platform, 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
Once configured, your FollowAnalytics device ID can be obtained by opening the following URI: YourURLScheme://followanalytics.com/deviceId
, with YourURLScheme as the application bundle ID.
Now, users can add devices to the FollowAnalytics platform without knowing the device ID. From the platform, they will send an email a link that will open the app and allow them to register the device.
Setting up keychain access group
Keychain is a secure storage suitable for short bits of sensitive information and by default, the data saved in one application can not be read in other applications. To share the Device ID
across applications of the same publisher it is required to specify a keychain group name. To configure it, you will need to perform the following steps:
Enable keychain sharing
- In XCode project settings, select your app target and from the
Signing & Capabilities
tab click+Capability
; - From the popup find and select the
Keychain Sharing
option; - Back on the capabilities list of the application add the group name to be used, e.g.
keychain.group.name.example
.
Setup the group name in the SDK
Set the configuration field .keychainGroupName
with the respective publisher Team ID
and Group Name
joined but a .
.
To know your Team ID
:
- Login to your Apple developer account (https://developer.apple.com/account);
- Select Membership from the left panel;
- Find the Team ID value from the Membership Information list.
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
// ...
// Replacing the YOUR_TEAM_ID with the respective value.
config.keychainGroupName = @"YOUR_TEAM_ID.keychain.group.name.example";
// ...
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
// ...
// Replacing the YOUR_TEAM_ID with the respective value.
config.keychainGroupName = "YOUR_TEAM_ID.keychain.group.name.example"
// ...
}
FollowAnalytics.start(with: configuration, startupOptions: launchOptions)
Analytics
To enrich User Analytics on the platform, FollowAnalytics SDK allows you to:
- Log your users events, errors and locations.
- Set attributes for your users.
Logs and attributes can also be used to target specific audiences when creating campaigns on the platform. You can find more information about the difference between logs and attributes here.
Our CSM team can help you creating relevant logs in your app. You can also find our recommendations here.
Logs and attributes are ignored by the platform is some conditions
When FollowAnalyticsConfiguration.apiMode
is set to Dev
, the platform completely ignores data received by the SDK. As a result, data is not included in User Analytics and not usable in Audience targeting, but you can still see them in the Device Observer.
The SDK will automatically set apiMode
to Dev
in the following conditions:
- The SDK is started with
FollowAnalyticsConfiguration.isVerbose
set totrue
. - Your app is running in a simulator.
Be careful to have FollowAnalyticsConfiguration.isVerbose
set to false
for your app release, otherwise all your app data will be ignored by the platform.
Logging Events and Errors
You can log Events and Errors in your app by calling the following methods:
+ (void)logEvent:(nonnull NSString*)name details:(nullable id)details;
+ (void)logError:(nonnull NSString*)name details:(nullable id)details;
static func logEvent(name: String, details: Any?)
static func logError(name: String, details: Any?)
Those methods print the log description in the console and also print an information about the log validity.
Use name
as a unique identifier for your log. Use details
to pass specific context to your log.
If details
exceeds 60KB it will be considered as invalid. Additionally, to be valid, details
must be one of the following:
- A
nil
value - A
String
- A
Dictionary
representing a valid flat JSON object (i.e. that doesn't contain any nested Dictionary or Array field).
Passing any invalid details
to those methods will:
- Print an error in the console
- Ignore the
details
argument and send the log with nodetails
The following code shows an example of how you can log the viewing and the purchasing of a product:
[FollowAnalytics logEvent:@"Product view" details:@"RF1672"];
NSDictionary *details = @{@"reference": @"RF1672",
@"payment_mode" : @"credit_card",
@"color" : @"red"};
[FollowAnalytics logEvent:@"Product purchased" details:details];
FollowAnalytics.logEvent("Product view", details: "RF1672")
let details = ["reference": "RF1672",
"payment_mode": "credit_card",
"color": "red"]
FollowAnalytics.logEvent("Product purchased", details: details)
Logging Locations
There are two ways for logging locations:
+ (void)logLocationWithLatitude:(double)latitude longitude:(double)longitude;
+ (void)logLocation:(nonnull CLLocation*)location;
static func logLocation(withLatitude: Double, longitude: Double)
static func logLocation(location: CLLocation)
Those methods print the log description in the console and also print an information about the log validity:
- if the location distance from the last logged location is less than 100 meters, the log will be ignored.
- if the location time interval from the last logged location is less that 1 hour, the log will be ignored.
One way to use the logLocation
method, is to implement the didUpdateLocations
method of the CLLocationManagerDelegate
to log the last location update. FollowAnalytics SDK will take care of ignoring a location log if this location is too close from the last one:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
FollowAnalytics.logLocation(location)
}
}
Last known location logs
If you don't request location updates, and you don't send location logs you can still have location logged thanks to the configuration option lastKnownLocationEnabled
.
Enabling this option, by setting FollowAnalyticsConfiguration.lastKnownLocationEnabled
to true
, will allow the SDK to send a location logs whenever a new session is created and a valid location is available.
The SDK is started by default with FollowAnalyticsConfiguration.lastKnownLocationEnabled
set to false
.
User Attributes
A user can be defined by setting its identifier. This identifier is a string that you provide to the SDK to uniquely identify a user of your app. It can be an e-mail address, an identifier from your own backend (for instance a primary key), a phone number, or anything else that could allow you to uniquely identify a user.
Attributes (like first name, date of birth...) can be associated to a user if it's defined. Attributes are associated to the device when no user is defined.
When a user is defined, a user profile is created server-side and can be shared across apps.
You can set predefined as well as custom attributes.
Define a user
To define a user, set its user ID:
FollowAnalytics.setUserId("UniqueIdentifier")
To remove a user (for example in case of a sign out), just pass nil
to setUserId
:
FollowAnalytics.setUserId(nil)
Predefined attributes
To set predefined attributes, you can call the following methods on the userAttributes
property provided by the SDK:
- (void)setFirstName:(nullable NSString*)firstName;
- (void)setLastName:(nullable NSString*)lastName;
- (void)setEmail:(nullable NSString*)email;
- (void)setDateOfBirth:(nullable NSDate*)dateOfBirth;
- (void)setGender:(FollowAnalyticsGender)gender;
- (void)setCountry:(nullable NSString*)country;
- (void)setCity:(nullable NSString*)city;
- (void)setRegion:(nullable NSString*)region;
- (void)setProfilePictureUrl:(nullable NSString*)profilePictureUrl;
func setFirstName(firstName : String?)
func setLastName(lastName: String?)
func setEmail(email : String?)
func setDateOfBirth(dateOfBirth : Date?)
func setGender(gender : FollowAnalyticsGender)
func setCountry(country : String?)
func setCity(region : String?)
func setRegion(city : String?)
func setProfilePictureUrl(profilePictureUrl : String?)
For instance, to set user Joe's city to "Paris", you would proceed as follows:
[FollowAnalytics.userAttributes setFirstName:@"Joe"];
[FollowAnalytics.userAttributes setCity:@"Paris"];
FollowAnalytics.userAttributes.setFirstName("Joe")
FollowAnalytics.userAttributes.setCity("Paris")
Custom attributes
In addition to predefined attributes, you can set your own custom attributes.
Always double check your custom attribute types
When a value for an unknown attribute is received by the server, the attribute is declared with the type of that first value.
If you change the type of an attribute in the SDK, values might be refused server-side. Ensure the attribute types match. This could be done by comparing with the ones you have in the Profile Data tab in the Administration page on FollowAnalytics platform.
Set a custom attribute
To set custom attributes, you can call the following methods on the userAttributes
property provided by the SDK:
- (void)setInteger:(NSInteger)integerValue forKey:(nonnull NSString*)key;
- (void)setDouble:(double)doubleValue forKey:(nonnull NSString*)key;
- (void)setString:(nonnull NSString*)string forKey:(nonnull NSString*)key;
- (void)setBoolean:(bool)boolean forKey:(nonnull NSString*)key;
- (void)setDate:(nonnull NSDate*)date forKey:(nonnull NSString*)key;
- (void)setDateTime:(nonnull NSDate*)dateTime forKey:(nonnull NSString*)key;
- (void)clear:(nonnull NSString*)key;
- (void)add:(nonnull NSSet<NSString*>*)values toSet:(nonnull NSString*)key;
- (void)remove:(nonnull NSSet<NSString*>*)values toSet:(nonnull NSString*)key;
- (void)clearSet:(nonnull NSString*)key;
func setInteger(integerValue: Int, forKey: String)
func setDouble(doubleValue : Double, forKey: String)
func setString(string: String, forKey: String)
func setBoolean(boolean: Bool, forKey: String)
func setDate(date: Date, forKey: String)
func setDateTime(dateTime: Date, forKey: String)
func clear(key: String)
func add(values: Set<String>, toSet: String)
func remove(values: Set<String>, toSet: String)
func clearSet(key: String)
For example, to set the user's job:
[FollowAnalytics.userAttributes setString:@"Taxi driver" forKey:@"job"];
FollowAnalytics.userAttributes.setString("Taxi driver", forKey:"job")
Delete a custom attribute value
You can delete the value of an attribute using its key. For instance, to delete the user's job:
[FollowAnalytics.userAttributes clear:@"job"];
FollowAnalytics.userAttributes.clear("job")
Set of Attributes
You can add or remove an item to or from a set of attributes.
To add an item to a set:
NSSet *set = [NSSet setWithObjects:@"apple", @"strawberry", @"lemon", nil];
[FollowAnalytics.userAttributes add:set toSet:@"fruits"]; // Adds "apple", "strawberry" and "lemon" to set "fruits".
FollowAnalytics.userAttributes.add(["apple", "strawberry", "lemon"], toSet:"fruits") // Adds "apple", "strawberry" and "lemon" to set "fruits".
To remove an item from a set:
NSSet *set = [NSSet setWithObjects:@"lemon", nil];
[FollowAnalytics.userAttributes remove:set toSet:@"fruits"]; // Removes "lemon" from set "fruits".
FollowAnalytics.userAttributes.remove(["lemon"], toSet:"fruits") // Removes "lemon" from set "fruits".
To clear a set:
[FollowAnalytics.userAttributes clearSet:@"fruits"]; // Removes all items from set "fruits".
FollowAnalytics.userAttributes.clearSet("fruits") // Removes all items from set "fruits".
Opt-in Analytics
FollowAnalytics SDK opt-in analytics state define whether to send logs and attributes to the platform. Opt-in analytics is true
by default, meaning logs and attributes will be sent to FollowAnalytics platform.
You can set it to false
at SDK initialization by setting the optInAnalyticsDefault
parameter to false
in the FollowAnalyticsConfiguration object passed to the initialization method. This is only used to set the default opt-in value at the first launch of the app.
This opt-in analytics value can be changed at runtime and it will be persisted for all future launch of the app.
To change opt-in analytics state at runtime, use the setOptInAnalytics
method:
+ (void)setOptInAnalytics:(BOOL)state;
static func setOptIn(state: Bool)
This value is persisted in memory and the opt-in analytics state is changed for all subsequent launch of your application, meaning optInAnalyticsDefault
is ignored.
To retrieve the current opt-in analytics state, use the getOptInAnalytics
method:
+ (BOOL)getOptInAnalytics;
static func Bool getOptInAnalytics()
GDPR
You can record when the user expresses his demand to access or delete his personal data by calling one of the following methods:
[FollowAnalytics.GDPR requestToAccessMyData]
[FollowAnalytics.GDPR requestToDeleteMyData]
FollowAnalytics.gdpr.requestToAccessMyData()
FollowAnalytics.gdpr.requestToDeleteMyData()
The SDK will record all requests and send them to FollowAnalytics servers as soon as network conditions allow it. The SDK remembers pending requests between app restarts.
Campaigns
From the FollowAnalytics platform, you can create:
- Push campaigns, that will display messages as notifications, whether your app is opened or not;
- In-App campaigns, that will display messages inside your app, when it's opened.
The SDK take care of displaying campaigns, and provide you ways to customize and interact with messages received from the platform. In this section you will see how to:
- Add rich notifications and badge management capabilities to your app thanks to FANotificationExtension
- Handle link opening (website URLs, app links, and deep links) with the implementation of the shouldOpenURL callback
- Implement custom behavior on notification tap or reception thanks to the onNotificationTapped and onNotificationReceived callbacks
- Implement custom behavior on native In-App's buttons tap thanks to the onNativeInAppButtonTapped callback
Notification Service Extension Framework
Rich notifications are notifications with embedded rich media (images, GIFs, videos). When defining a Push campaign on the platform, you can add a rich media to the notification.
A badge is the number displayed on the icon of the app, indicating to the user that the app has new information. On the platform, you can set by how much the badge is to be increased or decreased at the notification reception on the user's device. This is defined as the badge increment in the Campaign Editor.
The SDK allows your app to receive rich notifications and to manage badges thanks to the FANotificationExtension
notification service extension framework. In this section, we will see how to install and use this extension framework by:
- Adding a Notification Service Extension target
- Installing from CocoaPods or manually
- Setting an App Group for both app and extension targets
- Configuring the SDK to work with the extension
- Implementing the extension
- Managing badges
Notification Service Extension and iOS version
FANotificationExtension
is only available on iOS 10.0 and above. If a user has a device with iOS version under 10.0, he will receive rich notifications but not be able to see the rich media included. Also he will not able to see your app icon's badge change done through the extension framework.
Add the Notification Service Extension target
To make your app able to receive rich notifications & badge incrementation, follow these steps:
-
In your XCode project, add a new target.
-
Select Notification Service Extension, give it a name, let's say Notification Service, and confirm. Then when prompted, activate the scheme.
-
Set the app as the Executable of the extension:
- Choose the extension
- Click
Edit Scheme
- Select app in executable field
Install FANotificationExtension from CocoaPods
If you want to use Cocoapods to manage your external dependencies, simply add the following line to your Podfile only in the extension target:
pod 'FANotificationExtension', '1.0.3', :source => 'https://github.com/followanalytics/fa-pod-spec.git'
If you don't have a podfile yet, open a console and do a pod init
in your project directory.
Then, you only need to update your Cocoapods dependencies:
pod install
Install FANotificationExtension manually
If you want to manually integrate the .framework
, extract the FollowAnalytics SDK archive and copy the FANotificationExtension.framework
into your project directory.
On Xcode 12.3 and greater
-
Go to your Xcode project’s
General
settings of your extension target, drag and drop the FANotificationExtension.framework in theFrameworks, Libraries, and Embedded Content
section. Make sure Do Not Embed is set for the FANotificationExtension.framework. -
From the
Build Settings
tap on the + button and selectAdd User-Defined Setting
. Name the setting asFA_SDK_PATH
and indicate the finder path where the FANotificationExtension.framework exist. E.g. if you have the framework inside a folder namedFrameworks
on the project root use$SRCROOT/Frameworks
. -
Create a new
Run Script Phase
in your app’s extension targetBuild Phases
and paste the following snippet in the script text field:bash "${FA_SDK_PATH}/FANotificationExtension.framework/embed-frameworks.sh"
This step is required to work around an App Store submission bug when archiving universal binaries and to work around the linker about multi architecrture configurations.
On Xcode 12.2 and below
-
Select the target of your main app, in
Build Phases
- Press the + button, and select
New Copy File Phase
. - Change the destination to
Frameworks
. - Click in
add other
. - Add the
FANotificationExtension.framework
file that you previously copied into your project directory. - Uncheck
Copy items if needed
box.
- Press the + button, and select
-
Still in the
Build Phases
create a newRun Script Phase
in your app’s extension targetBuild Phases
and paste the following snippet in the script text field:bash "PATH_TO_YOUR_PROJECT_DIRECTORY/FANotificationExtension.framework/strip-frameworks.sh"
This step is required to work around an App Store submission bug when archiving universal binaries.
-
In
Build Settings
->Framework Search Paths
entry, add the path to where theFANotificationExtension.framework
is located (actually your project directory).
Set an App Group for both app and extension targets
-
Before all, an App Group must be created.
- Go to the
apple developer
portal. - Choose the
identifier
tab. - Choose the
App Groups
filed from the list.
- Tap
+
to create a newApp Group
- Create your
App Group
and clickContinue
- Switch to the
App ID
of the app. - Add
App Groups
capability
- Select the new
App Group
recently created.
- Go to the
-
Then, the
app group
must be added to theAppId
of app and extension - Finally, the
app group
capability must be activated inXcode
for both app and extension
Update your provisioning profiles
Make sure to re-download all the provisioning profiles for application and notification service extension targets.
Configuring the SDK to work with the extension
First, make sure you have set the proper App Group for the app target:
The appGroup
parameter should be specified in the configuration init of the SDK:
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
...
config.appGroup = @"group.your.identifier";
};
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
...
config.appGroup = "group.your.identifier"
}
Implement the Notification Service Extension
First, make sure you have set the proper App Group for the extension target:
Copy and paste the following implementation in the NotificationService
file of the extension you created
#import “NotificationService.h”
#import <FANotificationExtension/FANotificationExtension.h>
@interface NotificationService ()
@property(nonatomic, strong) void (^contentHandler)(UNNotificationContent* contentToDeliver);
@property(nonatomic, strong) UNMutableNotificationContent* bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest*)request
withContentHandler:(void (^)(UNNotificationContent* _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
[FANotificationService
getFAContentIfNeededWithRequest:request
bestContent:self.bestAttemptContent
appGroup:@"group.your.identifier"
completion:^(UNMutableNotificationContent* _Nullable newContent) {
NSLog(@"NotificationService: %@", request);
// Modify the notification content here...
self.contentHandler(newContent);
}];
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content,
//otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
@end
import UserNotifications
import FANotificationExtension
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent,
let contentHandler = self.contentHandler {
// Modify the notification content here...
FANotificationService.getFAContentIfNeeded(with: request,
bestContent: bestAttemptContent,
appGroup: "group.your.identifier") {
(newContent) in
if let newC = newContent {
contentHandler(newC)
}
}
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Badge Management
Prerequisites
To use this feature, make sure you have installed and configured FANotificationExtension properly. More information here
Badges are the numbers displayed on the icon of the app, indicating to the user that the app has new information. Our service offers you two ways to update this value. The first one through the campaign editor on our platform and the second one using our SDK methods.
Using our platform, when creating a Push Campaign, it's possible to set a badge increment so that the SDK updates the badge number at push reception.
Using our SDK you can set, increment or get the badge number through the following methods respectively:
[FABadge setBadge:INTEGER]; // Set the value of the icon badge number
[FABadge updateBadgeBy:INTEGER]; // Update the value of the icon badge number
[FABadge badge]; // Get the value of the icon badge number
FABadge.setBadge(Int) // Set the value of the icon badge number
FABadge.updateBadgeBy(Int) // Update the value of the icon badge number
FABadge.badge // Get the value of the icon badge number
Prefer to use FABadge instead of UIKit
Even though you can update the badge number programmatically using the Apple UIKit applicationIconBadgeNumber
, it is required to use our FABadge public methods to keep incrementing correctly the badge number on future push receptions.
Geofencing triggers and location conditions
On the platform, when creating a campaign with contextual delivery, there are two ways to use locations:
-
By defining a Geofencing Event trigger condition in the Contextual Delivery page of the campaign editor. The campaign will be displayed according to the type of geofence (entering or leaving area), the coordinates and the radius of the defined region. For Geofencing Events to work, it's required that your app requests the Always location authorization and that the user accepts it. Additionally, to allow the geofencing event to be triggered while your app is in background or force-quit, you must add the Location updates mode to the Background Modes capabilities of your project.
-
By adding a Location Condition to a Session Events or Tagged Events trigger in the Contextual Delivery page of the campaign editor. To check the location condition, the SDK will use the last known location of your device, if this one is not older that 2H. If you want to increase the accuracy of this location condition, your app can explicitly request location updates through the CLLocationManager. Additionally, to allow location updates in the background, you must add the Location updates mode to the Background Modes capabilities of your project, and you must set
allowsBackgroundLocationUpdates
totrue
the CLLocationManager.
Logging locations has no effect on geofencing and location conditions
Logging locations through the logLocation
method will send location events to the FollowAnalytics platform so you can use locations while targeting specific audiences. This has no effect on the Geofencing Events nor Location Condition features of contextual campaigns.
Implement custom behavior on URL opening
From the FollowAnalytics platform, you can add URLs (website links or custom URL schemes) to your Push or In-App campaigns. By default, those links will be opened by the SDK, unless the shouldOpenURL
callback is defined on the FollowAnalyticsConfiguration provided at SDK initialization. This callback allows you to implement your own URL opening logic. Use the return value of this callback to allow the SDK to actually open the URL or not:
-
If the return value is
true
the SDK will open the URL. In this case, if the URL is a Universal Link to your own website, it will not be opened into your app. -
If the return value is
false
the SDK will not open the URL. In this case, it's your responsibility to implement the opening of the URL. For instance, you can returnfalse
if you implemented code to open Universal Links in your app like in this example.
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
config.shouldOpenURL =
^BOOL(NSURL* _Nonnull url) {
// YOUR BEHAVIOR
// Returning `YES` tells the SDK to open the URL.
return YES;
}
};
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.shouldOpenURL = { (url) in
// YOUR BEHAVIOR
// Returning `true` tells the SDK to open the URL.
return true
}
}
Implement shouldOpenURL to handle Universal Links
Universal Links allow your app to be opened to handle links that point to your website. Due to the behavior of the open(_:options:completionHandler:) method, FollowAnalytics SDK will not open those links in your app, but in the browser. See this article from Apple documentation for more details.
In order to open those Universal Links in your app, you must implement the shouldOpenURL
callback to forward the url to your application by calling the application(_:continue:restorationHandler:) callback:
config.shouldOpenURL = ^BOOL(NSURL* _Nonnull url) {
BOOL urlHasBeenHandled = NO;
// We only want to hanlde Universal Links
// (i.e. http links that point to your own website).
if ([url.absoluteString hasPrefix:@"http"]
&& [url.host isEqualToString:@"YOUR_WEBSITE_DOMAIN"]) {
NSUserActivity* userActivity =
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
userActivity.webpageURL = url;
urlHasBeenHandled = [self application:UIApplication.sharedApplication
continueUserActivity:userActivity
restorationHandler:^(NSArray<id<UIUserActivityRestoring>> *
_Nullable restorableObjects) { }];
}
// If the url has been handled by the application,
// we don't want FA SDK to open the url.
return !urlHasBeenHandled;
};
config.shouldOpenURL = { (url) in
var urlHasBeenHandled = false
// We only want to hanlde Universal Links
// (i.e. http links that point to your own website).
if url.absoluteString.hasPrefix("http")
&& url.host == "YOUR_WEBSITE_DOMAIN" {
let userActivity = NSUserActivity(activityType:
NSUserActivityTypeBrowsingWeb)
userActivity.webpageURL = url
urlHasBeenHandled = self.application(UIApplication.shared,
continue: userActivity,
restorationHandler: { _ in })
}
// If the url has been handled by the application,
// we don't want FA SDK to open the url.
return !urlHasBeenHandled
}
Make sure your implementation of application(_:continue:restorationHandler:)
returns false
when your app is not able to handle the provided url:
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:
(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
return NO;
}
if (/* Check if userActivity.webpageURL should open screen 1 */) {
// Present screen 1 ViewController
return YES;
}
else if (/* Check if userActivity.webpageURL should open screen 2 */) {
// Present screen 2 ViewController
return YES;
}
return NO;
}
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb else { return false }
if /* Check if userActivity.webpageURL should open screen 1 */ {
// Present screen 1 ViewController
return true
}
else /* Check if userActivity.webpageURL should open screen 2 */ {
// Present screen 2 ViewController
return true
}
return false
}
Opt-in Notifications
The FollowAnalytics SDK opt-in notifications status defines whether your app will receive notifications from your Push campaigns. Opt-in notifications is true
by default, meaning notifications from your Push campaigns will be received by your app. This status is independent from the iOS notification authorization, which is also needed by your app to display notifications.
Thanks to this opt-in notifications status, you can implement a UI in your app to allow to choose whether to receive notifications, without the need to go to the iOS notification authorization settings. Note that the opt-in notifications status will have no effect if the iOS notification authorization is not allowed, and in this case, your app will not receive notifications from your Push campaigns, whatever the opt-in notifications status. To have the iOS notification authorisation allowed, use the requestNotificationAuthorization method or the requestProvisinalNotificationAuthorization method.
To update your app UI to reflect the current opt-in notifications status, use the getOptInNotifications
method:
+ (BOOL)getOptInNotifications;
static func Bool getOptInNotifications()
To update the current opt-in notifications status upon UI change, use the setOptInNotifications
method:
+ (void)setOptInNotifications:(BOOL)state;
static func setOptInNotifications(state: Bool)
Handling transistion from opt-out to opt-in notifications
Just calling setOptInNotifications(true)
after the user interacts with your app UI to opts-in for notifications could be insufficient if the iOS system notification authorization is not allowed. For this reason, we recommend to implement the following flow after the user opts-in for notifications in your app:
- Check the return value of
FollowAnalytics.getPushNotificationsRegistrationStatus()
which istrue
only if the iOS system notification authorization is allowed AND the SDK opt-in notifications status istrue
. - If
false
, display a message and button to invite your user to enable the iOS system notification authorization. - Call
FollowAnalytics.openNotificationSettingsEventually()
when the user taps the button. The method will take care of either displaying the notification authorization request alert, or directing to the iOS app settings screen. This will allow the user to enable notifications.
Another possibility is to bypass the first two steps and only implement the last one.
It's possible to set the opt-in notifications status to false
at the SDK initialization by setting the optInNotificationsDefault
parameter to false
in the FollowAnalyticsConfiguration object passed to the initialization method. This is only used to set the default opt-in value at the first launch of the app. Note that calling the setOptInNotifications
will persist the opt-in notifications status for all subsequent launch of your application, meaning optInNotificationsDefault
will be ignored.
Interactive Notifications
An Interactive Notification is a notification containing custom action buttons that the user can access by revealing the notification:
When tapped, an action button will:
- Close the notification.
- Eventually launch your application in the foreground, if you specified it explicitly when creating the action (See details below). Otherwise your app is not opened.
- Execute the custom behavior you implemented for the notification tap.
To create a campaign with Interactive Notifications:
-
On the platform, create a Push Campaign and define a Category in the Interactive Notification section of the campaign editor. For our example, let's set this field to
"NewContent"
. -
In your app, define the action names you want for your notification, we will call them
actionIdentifiers
. Those identifiers will be displayed as is on the platform in the Push Opened stats:
NSString* const ActionIdentifierView = @"View";
NSString* const ActionIdentifierDelete = @"Delete";
NSString* const ActionIdentifierRemind = @"Remind me tomorrow";
let ActionIdentifierView = "View"
let ActionIdentifierDelete = "Delete"
let ActionIdentifierRemind = "Remind me tomorrow"
- In the
application(_:didFinishLaunchingWithOptions:)
method of your app delegate, create the derised actions, add them to the"NewContent"
category and register this category to the current UNUsernotificationCenter:
if (@available(iOS 10.0, *)) {
UNNotificationAction *viewAction = [UNNotificationAction
actionWithIdentifier:ActionIdentifierView
title:NSLocalizedString(ActionIdentifierView, nil)
options:UNNotificationActionOptionForeground];
UNNotificationAction *deleteAction = [UNNotificationAction
actionWithIdentifier:ActionIdentifierDelete
title:NSLocalizedString(ActionIdentifierDelete, nil)
options:UNNotificationActionOptionDestructive];
UNNotificationAction *remindAction = [UNNotificationAction
actionWithIdentifier:ActionIdentifierRemind
title:NSLocalizedString(ActionIdentifierRemind, nil)
options:UNNotificationActionOptionForeground];
// The UNNotificationCategoryOptionCustomDismissAction option allows to
// call the onNotificationTapped callback when the notiifcation is dismissed
UNNotificationCategory *newContentCategory = [UNNotificationCategory
categoryWithIdentifier:@"NewContent"
actions:@[viewAction, deleteAction, remindAction]
intentIdentifiers:@[]
options:UNNotificationCategoryOptionCustomDismissAction];
[[UNUserNotificationCenter currentNotificationCenter]
setNotificationCategories:[NSSet setWithObject:newContentCategory]];
}
if #available(iOS 10.0, *) {
let viewAction = UNNotificationAction(identifier: ActionIdentifierView,
title: NSLocalizedString(ActionIdentifierView,
comment: ""),
options: .foreground)
let deleteAction = UNNotificationAction(identifier: ActionIdentifierDelete,
title: NSLocalizedString(ActionIdentifierDelete,
comment: ""),
options: .destructive)
let remindAction = UNNotificationAction(identifier: ActionIdentifierRemind,
title: NSLocalizedString(ActionIdentifierRemind,
comment: ""),
options: .foreground)
// The customDismissAction option allows to call the onNotificationTapped
// callback when the notiifcation is dismissed
let newContentCategory =
UNNotificationCategory(identifier: "NewContent",
actions: [viewAction, deleteAction, remindAction],
intentIdentifiers: [],
options: .customDismissAction)
UNUserNotificationCenter.current().setNotificationCategories([newContentCategory])
}
Note that the notification action title is a localized version of the actionIdentifier
, while the platform displays the actionIdentifier
as is in the Push Opened stats.
Implement custom notification sound
When creating a Push Campaign, the editor lets you set a custom sound for the notification:
To configure a custom sound:
- Add a custom sound file to your app's main bundle or make your app store it in the
Library/Sounds
folder of your app's container directory. See more details about file location and format in Apple documentation. - Enter the complete custom sound filename in the "Custom Sound" field of the campaign editor.
Implement custom behavior on notification tap
You can implement a custom behavior when the user taps on a notification by implementing the onNotificationTapped
callback in FollowAnalyticsConfiguration. This allows you to perform specific actions when a notification is tapped:
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
config.onNotificationTapped =
^(FANotificationInfo* _Nonnull notificationInfo, NSString* _Nonnull actionIdentifier) {
if ([actionIdentifier isEqualToString:FANotificationDefaultActionIdentifier]) {
// Your behavior for a tap on the notification body
} else if ([actionIdentifier isEqualToString:FANotificationDismissActionIdentifier]) {
// Your behavior when the notification is dismissed (only for Interactive Notification)
} else if ([actionIdentifier isEqualToString:ActionIdentifierView]) {
// Your behavior for a tap on the "View" action button
} else if ([actionIdentifier isEqualToString:ActionIdentifierDelete]) {
// Your behavior for a tap on the "Delete" action button
} else if ([actionIdentifier isEqualToString:ActionIdentifierRemind]) {
// Your behavior for a tap on the "Remind me tomorrow" action button
}
}
};
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.onNotificationTapped = { (notificationInfo, actionIdentifier) in
switch (actionIdentifier) {
case FANotificationDefaultActionIdentifier:
// Your behavior for a tap on the notification body
case FANotificationDismissActionIdentifier:
// Your behavior when the notification is dismissed (only for Interactive Notification)
case ActionIdentifierView:
// Your behavior for a tap on the "View" action button
case ActionIdentifierDelete:
// Your behavior for a tap on the "Delete" action button
case ActionIdentifierRemind:
// Your behavior for a tap on the "Remind me later" action button
default:
// Do nothing
}
}
}
Add background fetch capability
For your app to be woken-up to execute your implementation of onNotificationTapped
when your app is in background, you must activate the Background Fetch
capability in the Background Modes
. This will be the case when the user tap a category notification button that does not open the app.
The SDK passes some Push campaign information to your app through this callback thanks to the notificationInfo
argument, while the actionIdentifier
argument provides information about which notification button has been tapped:
notificationInfo.messageId
is aString
containing the FollowAnalytics message identifier. It can be used to retrieve the associatedFAMessage
by callingFollowAnalytics.push.get(notificationInfo.messageId)
.notificationInfo.isSilent
is aBoolean
telling if the notification is silent or not. InonNotificationTapped
, this property is alwaysfalse
.notificationInfo.parameters
is an optionalDictionary
containing the key/value pairs defined in the campaign editor.notificationInfo.url
is an optionalURL
containing App Link value defined in the campaign editor.actionIdentifier
is aString
containing the identifier for the tap action. It can be either :FANotificationDefaultActionIdentifier
when the user tapped on a regular notification, or on the body of an Interactive Notification.FANotificationDismissActionIdentifier
when the user dismissed an Interactive Notification.- Your custom action identifier when the user tapped on a custom button of an Interactive Notification.
Implement custom behavior on Push reception
You can implement a custom behavior when the device receives a message from a Push campaign that contains custom parameters (i.e. at least one key/value pair). This can be used to fetch data from your server if a particular custom parameter is defined in the Push message. To do so, implement the onNotificationReceived
callback in FollowAnalyticsConfiguration:
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
config.onNotificationReceived = ^(FANotificationInfo * _Nonnull notificationInfo){
// YOUR BEHAVIOR
}
};
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.onNotificationReceived = { (notificationInfo) in
// YOUR BEHAVIOR
}
}
Add background fetch capability
For your app to be woken-up to execute your implementation of onNotificationReceived
when your app is in background, you must activate the Background Fetch
capability in the Background Modes
. Note that your code implemented in in this callback must not take more that 30s to execute. Otherwise the callback execution will be stopped by iOS. As a consequence, when using this callback to fetch data, make sure data size not too big compared to the data connection speed of your users.
Implement only synchronous calls
The SDK executes your onNotificationReceived
code in a background thread and expects that the whole callback implementation is synchronous. Any asynchronous call is not guaranteed to finish before the end of the callback execution and then will be terminated at the time the callback execution is finished. Make sure that your implementation follows those rules, to ensure proper runtime execution:
- All statements are synchronous calls.
- No call to any API that should be called on the main thread.
The SDK passes some Push campaign information to your app through this callback thanks to the notificationInfo
argument:
notificationInfo.messageId
is aString
containing the FollowAnalytics message identifier. It can be used to retrieve the associatedFAMessage
by callingFollowAnalytics.push.get(notificationInfo.messageId)
.notificationInfo.isSilent
is aBoolean
telling if the notification is silent or not.notificationInfo.parameters
is an optionalDictionary
containing the key/value pairs defined in the campaign editor. InonNotificationReceived
, this property is always set with at least one key/value pair.notificationInfo.url
is an optionalURL
containing App Link value defined in the campaign editor.
Implement custom behavior on Native Alert button tap
You can implement a custom behavior when the user taps on a Native Alert* button by implementing the onNativeInAppButtonTapped
callback in the FollowAnalyticsConfiguration. This allows you to perform specific actions when a native alert button is tapped:
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration* _Nonnull config) {
config.onNativeInAppButtonTapped =
^(FACustomButtonInfo* _Nonnull buttonInfo) {
// YOUR BEHAVIOR
}
};
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.onNativeInAppButtonTapped = { (buttonInfo) in
// YOUR BEHAVIOR
}
}
The SDK passes some Native Alert campaign information to your app through this callback thanks to the buttonInfo
argument:
buttonInfo.campaignId
is aString
containing the FollowAnalytics campaign identifier.buttonInfo.parameters
is an optionalDictionary
containing the key/value pairs defined in the campaign editor.buttonInfo.url
is an optionalURL
containing App Link value defined in the campaign editor.
Controlling In-App campaigns
To pause and resume campaigns, add the following methods in you code at the location you wish the pause and resume to take effect:
[FollowAnalytics.inApp pauseCampaignDisplay]
[FollowAnalytics.inApp resumeCampaignDisplay]
FollowAnalytics.inApp.pauseCampaignDisplay()
FollowAnalytics.inApp.resumeCampaignDisplay()
Create safe spaces for you in-app messages
Rather than pause everywhere you have an important screen or process, you can pause right at the initialization of the SDK and resume in the areas you think it is safe for in-app campaigns to be displayed.
Archiving messages
FollowAnalytics SDK allows you to store campaigns's messages received by your app. This makes them available for custom usage, like building an inbox feature. All campaigns displayed by a device can be archived locally and accessed from the developer's code, formatted as a FAMessage
object. In order to configure your campaign storage, you have to set the following FollowAnalyticsConfiguration properties at SDK initialization:
@property(nonatomic, readonly, assign) BOOL archivePushMessages;
@property(nonatomic, readonly, assign) BOOL archiveInAppMessages;
open var archivePushMessages: Bool { get }
open var archiveInAppMessages: Bool { get }
In FollowAnalyticsInApp
and FollowAnalyticsPush
protocols you will find all necessary methods to manage all FAMessage
objects that are archived. They are implemented by FollowAnalytics.inApp
and FollowAnalytics.push
- The methods are the following
- (nonnull NSArray<FAMessage*>*)getAll;
- (nullable FAMessage*)get:(nonnull NSString*)identifier;
- (void)markAsRead:(nonnull NSArray<NSString*>*)identifiers;
- (void)markAsUnread:(nonnull NSArray<NSString*>*)identifiers;
- (void)deleteIdentifiers:(nonnull NSArray<NSString*>*)identifiers;
func getAll() -> [FAMessage]
func get(identifier : String) -> FAMessage
func markAsRead(identifiers : [String])
func markAsUnread(identifiers : [String])
func deleteIdentifiers(identifiers : [String])
Here is a description of some of the FAMessage
attributes:
Property | Type | Description |
---|---|---|
isRead |
boolean | Indicates if the message has been read not not. False at message reception. Only modifiable by the InBoxManager. |
isPush |
boolean | true if message comes from a Push campaign, false if it comes from a In-App campaign. |
isInApp |
boolean | true if message comes from a In-App campaign, false` if it comes from a Push campaign. |
isSilent |
boolean | true if message comes from a Push campaign with the "Silent" option enabled (silent push), false otherwise. |
identifier |
string | FollowAnalytics message identifier. |
dateReceived |
date | If message comes from a Push campaign, this is the date at which the message is received on the device. If message comes from an In-App campaign, this is the start date of the campaign. |
notificationId |
string | If message comes from a Push campaign, this is the UNNotificationRequest unique identifier (iOS >= 10.0), otherwise it's nil . |
title |
string | Text provided in the platform's "Title" field of the Push campaign editor. |
subtitle |
string | Text provided in the platform's "Subtitle" field of the Push campaign editor. |
body |
string | Text provided in the platform's "Content" field of the Push campaign editor. |
url |
string | Url provided in the platform's "URL" field of In-App Custom Web Page campaign editor. If the message comes from a Push campaign, this is the url of the Rich Media. |
deepLinkUrl |
string | Url provided in the platform's "App Link" field of the Push campaign editor. |
params |
dictionary | Key/Value pairs provided in the Push campaign editor. |
Web Views
If your app contains web views, you can use FollowAnalytics SDK from within your HTML/JS code. This is possible thanks to the FAWKWebViewJSBridge
.
Using FAWKWebViewJSBridge
-
Adopt the
WKUIDelegate
protocol in your object of choice, typically aUIViewController
.@interface ViewController <WKUIDelegate>
class ViewController: UIViewController, WKUIDelegate {
-
At the initialization of the hosting view controller, keep a strong reference to a
FAWKWebViewJSBridge
instance:@property(nonatomic, nullable) FAWKWebViewJSBridge* webViewJSBridge; // ... self.webViewJSBridge = [[FAWKWebViewJSBridge alloc] init];
var webViewJSBridge: FAWKWebViewJSBridge? // ... self.webViewJSBridge = FAWKWebViewJSBridge()
-
Add the
FAWKWebViewJSBridge
instance to theWKWebViewConfiguration
instance, pass this configuration to theWKWebView
and set yourUIViewController
as the web view delegate:WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; [self.webViewJSBridge addToConfiguration:configuration]; WKWebView* webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; webView.UIDelegate = self;
let configuration = WKWebViewConfiguration() self.webViewJSBridge?.add(to: configuration) let webView = WKWebView.init(frame: self.view.frame, configuration: configuration) webView.uiDelegate = self
-
Implement the following delegate method:
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler { if([prompt hasPrefix:@"FollowAnalytics"]) { [self.webViewJSBridge webView:webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:frame completionHandler:completionHandler]; return; } }
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { if prompt.hasPrefix("FollowAnalytics") { self.webView(webView, runJavaScriptTextInputPanelWithPrompt: prompt, defaultText: defaultText, initiatedByFrame: frame, completionHandler: completionHandler return } }
FollowAnalytics SDK JS interface
Here are the SDK methods you can call from the JavaScript code:
-
Environment information and actions:
FollowAnalytics.getUserId(); FollowAnalytics.setUserId("aUserId"); FollowAnalytics.getSDKPlatform(); FollowAnalytics.getSDKVersion(); FollowAnalytics.getDeviceId(); FollowAnalytics.setOptInNotifications(false); FollowAnalytics.getOptInNotifications(); // Returns the string "true" if the opt-in notifications status is true, "false" otherwhise. FollowAnalytics.requestNotificationAuthorization(); // To request Notification authorization permissions. FollowAnalytics.requestProvisionalNotificationAuthorization(); // To request provisional Notification authorization. FollowAnalytics.isRegisteredForPushNotifications() // Get the Push campaigns registration status. Will return "true" only if the notification authorization is allowed AND the SDK opt-in notifications status is true. Otherwise, will return "false". FollowAnalytics.openNotificationSettingsEventually(); FollowAnalytics.setData("key", "value"); // To save and persist string data. FollowAnalytics.getData("key"); // To retrieve a previously saved string data from its key.
-
Logging events/errors/locations:
FollowAnalytics.logEvent("anEventName"); FollowAnalytics.logEvent("anEventName", 1); FollowAnalytics.logEvent("anEventName", "anEventDetail"); FollowAnalytics.logEvent('anEventName', {'anEventKey':'anEventValue'}) FollowAnalytics.logError("anErrorName"); FollowAnalytics.logError("anErrorName", 1); FollowAnalytics.logError("anErrorName", "anErrorDetail"); FollowAnalytics.logError("anErrorName", {'anEventKey':'anEventValue'}) FollowAnalytics.logLocation(48.8410646, 2.3210844);
-
User attributes:
FollowAnalytics.UserAttributes.setFirstName("aFirstName"); FollowAnalytics.UserAttributes.setLastName("aLastName"); FollowAnalytics.UserAttributes.setEmail("something@domain.com"); FollowAnalytics.UserAttributes.setDateOfBirth(new Date("1998-08-01")); FollowAnalytics.UserAttributes.setGender(FollowAnalytics.Gender.MALE); // Can be MALE, FEMALE or OTHER FollowAnalytics.UserAttributes.setCountry("France"); FollowAnalytics.UserAttributes.setCity("Paris"); FollowAnalytics.UserAttributes.setRegion("Île-de-France"); FollowAnalytics.UserAttributes.setProfilePictureUrl("https://picture_url"); FollowAnalytics.UserAttributes.setNumber("aKey", 10.5); FollowAnalytics.UserAttributes.setDateTime("aKey", Date.now()); FollowAnalytics.UserAttributes.setDate("aKey", Date.now()); FollowAnalytics.UserAttributes.setString("aKey", "aString"); FollowAnalytics.UserAttributes.setBoolean("aKey", true); FollowAnalytics.UserAttributes.addToSet("aSetKey", "aSetElement"); FollowAnalytics.UserAttributes.removeFromSet("aSetKey", "aSetElement"); FollowAnalytics.UserAttributes.clear("aKey"); FollowAnalytics.UserAttributes.clearSet("aSetKey");
-
InApp campaigns archiving:
FollowAnalytics.InApp.markAsRead(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/]); FollowAnalytics.InApp.markAsUnread(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/]); FollowAnalytics.InApp.delete(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/]); FollowAnalytics.InApp.get("aCampaignId"); // Returns an campaign Message json object as a String FollowAnalytics.InApp.getAll(); // Returns an array of campaign Message json object as a String
-
Push campaigns archiving:
FollowAnalytics.Push.markAsRead(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/); FollowAnalytics.Push.markAsUnread(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/]); FollowAnalytics.Push.delete(['campaignId1', 'campaignId2'/*,..., 'campaignIdN'*/]); FollowAnalytics.Push.get("aCampaignId"); // Returns an campaign Message json object as a String FollowAnalytics.Push.getAll(); // Returns an array of campaign Message json object as a String
-
Badge:
FollowAnalytics.Badge.set(1); // To update the app icon badge when Notifications are authorized with with badge. FollowAnalytics.Badge.updateBy(1); // To increment the value of the app icon badge when Notifications are authorized with with badge.
Disabling Swizzling
By default, the SDK swizzles methods from your UIApplicationDelegate
, your UNUserNotificationCenterDelegate
, and from your UISceneDelegate
if your project is configured with it. Along with the swizzled UISceneDelegate
methods our SDK observes the scene lifecycle notifications. This is an automatic process that allows the SDK to receive the necessary system calls seamlessly and behave accordingly without additional configurations and calls from the developer.
But in some situations, you could have the need to disable this feature. For example due to a legacy framework for some incompatibility with the swizzled methods.
In these cases we allow the developer to disable the Swizzling. To that, include the swizzlingEnabled
options in the configuration as follows:
FollowAnalyticsConfiguration* configuration = [FollowAnalyticsConfiguration
configurationWith:^(FollowAnalyticsConfiguration * _Nonnull config) {
config.swizzlingEnabled = NO;
}];
let configuration = FollowAnalyticsConfiguration.init { (config) in
config.swizzlingEnabled = false
}
Required Methods
By disabling the swizzling the SDK requires the developer to forward the following methods without exception. This is mandatory to ensure the SDK works as expected. Not doing so may cause unexpected side-effects.
The required UIApplicationDelegate
methods are:
-
didRegisterForRemoteNotificationsWithDeviceToken
:Forwarding this method the SDK will be able to send the device token to the server for Push Notifications delivery.
- (void) application:(UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*) deviceToken { [FollowAnalytics didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; }
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { FollowAnalytics.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken) }
-
applicationDidEnterBackground
:Forward this method if your projects don't implement the UISceneDelegate protocol. Forwarding this method the SDK will be able to calculate session duration, handle app badge number and detect campaign triggers.
- (void) applicationDidEnterBackground:(UIApplication*_Nonnull) application { [FollowAnalytics applicationDidEnterBackground:application]; }
func applicationDidEnterBackground(_ application: UIApplication) { FollowAnalytics.applicationDidEnterBackground(application) }
-
applicationWillEnterForeground
:Forward this method if your projects don't implement the UISceneDelegate protocol. Forwarding this method the SDK will be able to synchronize campaigns, detect campaign triggers and present queued triggered campaigns.
- (void) applicationWillEnterForeground:(UIApplication*_Nonnull) application { [FollowAnalytics applicationWillEnterForeground:application]; }
func applicationWillEnterForeground(_ application: UIApplication) { FollowAnalytics.applicationWillEnterForeground(application) }
-
applicationDidBecomeActive
:Forward this method if your projects don't implement the UISceneDelegate protocol. Forwarding this method the SDK will be able to calculate sessions durations and detect campaign triggers.
- (void) applicationDidBecomeActive:(UIApplication*_Nonnull) application { [FollowAnalytics applicationDidBecomeActive:application]; }
func applicationDidBecomeActive(_ application: UIApplication) { FollowAnalytics.applicationDidBecomeActive(application) }
-
applicationWillTerminate
:Forwarding this method the SDK will be able to calculate sessions durations and handle app badge number.
- (void) applicationWillTerminate:(UIApplication*_Nonnull) application { [FollowAnalytics applicationWillTerminate:application]; }
func applicationWillTerminate(_ application: UIApplication) { FollowAnalytics.applicationWillTerminate(application) }
-
applicationDidReceiveMemoryWarning
:Forwarding this method the SDK will be able to send statistics information.
- (void) applicationDidReceiveMemoryWarning:(UIApplication*_Nonnull) application { [FollowAnalytics applicationDidReceiveMemoryWarning:application]; }
func applicationDidReceiveMemoryWarning(_ application: UIApplication) { FollowAnalytics.applicationDidReceiveMemoryWarning(application) }
-
didReceiveRemoteNotification
:Forwarding this method the SDK will be able to handle Push Notifications and In-App campaigns.
- (void) application:(UIApplication*_Nonnull) application didReceiveRemoteNotification:(NSDictionary*_Nullable) userInfo { [FollowAnalytics application:application didReceiveRemoteNotification:userInfo]; }
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) { FollowAnalytics.application(application, didReceiveRemoteNotification: userInfo) }
-
handleActionWithIdentifierForRemoteNotification
:Forwarding this method the SDK will be able to handle Push Notifications and In-App campaigns.
- (void) application:(UIApplication*_Nonnull) application handleActionWithIdentifier:(NSString*_Nullable) identifier forRemoteNotification:(NSDictionary*_Nonnull) userInfo completionHandler:(void (^_Nullable)(void)) completionHandler { [FollowAnalytics application:application handleActionWithIdentifier:identifier forRemoteNotification:userInfo completionHandler:completionHandler]; }
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [AnyHashable: Any], completionHandler: @escaping () -> Void) { FollowAnalytics.application(application, handleActionWithIdentifier: identifier, forRemoteNotification: userInfo, completionHandler: completionHandler) }
-
handleActionWithIdentifierForLocalNotification
:Forwarding this method the SDK will be able to handle Notifications and In-App campaigns.
- (void) application:(UIApplication*_Nonnull) application handleActionWithIdentifier:(NSString*_Nullable) identifier forLocalNotification:(UILocalNotification*_Nonnull) notification completionHandler:(void (^_Nullable)(void)) completionHandler { [FollowAnalytics application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler]; }
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) { FollowAnalytics.application(application, handleActionWithIdentifier: identifier, for: notification, completionHandler: completionHandler) }
-
handleOpenURL
:If your application support iOS version less than 9.0.
Forwarding this method will allow the application to present an alert providing the current device status if the URL is related to this SDK.
- (BOOL) application:(UIApplication*_Nonnull) application handleOpenURL:(NSURL*_Nonnull) url { return [FollowAnalytics application:application handleOpenURL:url]; }
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool { return FollowAnalytics.application(application, open: url, options: options) }
-
openURLSourceApplication
:If your application support iOS version less than 9.0.
Forwarding this method will allow the application to present an alert providing the current device status if the URL is related to this SDK.
- (BOOL) application:(UIApplication*_Nonnull) application openURL:(NSURL*_Nonnull) url sourceApplication:(NSString*_Nullable) sourceApplication annotation:(id _Nonnull) annotation { return [FollowAnalytics application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; }
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { return FollowAnalytics.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation) }
-
openURLOptions
:Forwarding this method will allow the application to present an alert providing the current device status if the URL is related to this SDK.
- (BOOL) application:(UIApplication*_Nonnull) application handleOpenURL:(NSURL*_Nonnull) url { return [FollowAnalytics application:application handleOpenURL:url]; }
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool { return FollowAnalytics.application(application, open: url, options: options) }
-
didReceiveLocalNotification
:Forwarding this method the SDK will be able to handle In-App campaigns.
- (void) application:(UIApplication*_Nonnull) application didReceiveLocalNotification:(UILocalNotification*_Nonnull) notification { [FollowAnalytics application:application didReceiveLocalNotification:notification]; }
func application(_ application: UIApplication, didReceive notification: UILocalNotification) { FollowAnalytics.application(application, didReceive: notification) }
-
performFetchWithCompletionHandler
:Forwarding this method the SDK will be able to close sessions and fetch contents.
- (void) application:(UIApplication*_Nonnull) application performFetchWithCompletionHandler:(void (^_Nullable)(UIBackgroundFetchResult)) completionHandler { [FollowAnalytics application:application performFetchWithCompletionHandler:completionHandler]; }
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { FollowAnalytics.application(application, performFetchWithCompletionHandler: completionHandler) }
-
didReceiveRemoteNotificationFetchCompletionHandler
:Forwarding this method the SDK will be able to synchronize campaigns, handle the badge icon and detect campaign triggers.
- (void) application:(UIApplication*_Nonnull) application didReceiveRemoteNotification:(NSDictionary*_Nonnull) userInfo fetchCompletionHandler:(void (^_Nonnull)(UIBackgroundFetchResult)) completionHandler { [FollowAnalytics application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; }
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { FollowAnalytics.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) }
-
handleEventsForBackgroundURLSession
:Forwarding this method the SDK will be able to synchronize campaigns, handle the badge icon and detect campaign triggers.
- (void) application:(UIApplication*_Nonnull) application handleEventsForBackgroundURLSession:(NSString*_Nonnull) identifier completionHandler:(void (^_Nullable)(void)) completionHandler { [FollowAnalytics application:application handleEventsForBackgroundURLSession:identifier completionHandler:completionHandler]; }
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { FollowAnalytics.application(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler) }
The required UNUserNotificationCenterDelegate
methods are:
-
didReceiveNotificationResponse
:Forwarding this method the SDK will be able to handle Push Notifications and In-App campaigns.
- (void) userNotificationCenter:(UNUserNotificationCenter*) center didReceiveNotificationResponse:(UNNotificationResponse*) response withCompletionHandler:(void (^)(void)) completionHandler { [FollowAnalytics userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; }
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { FollowAnalytics.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) }
-
willPresentNotification
:Forwarding this method the SDK will be able to handle Push Notifications and In-App campaigns.
- (void) userNotificationCenter:(UNUserNotificationCenter*) center willPresentNotification:(UNNotification*) notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions)) completionHandler { [FollowAnalytics userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler]; }
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { FollowAnalytics.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler) }
And if your project implements the UISceneDelegate the required methods to forward are:
-
willConnectToSession:
:+ (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { [FollowAnalytics scene:scene willConnectToSession:session options:connectionOptions]; }
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { FollowAnalytics.scene(scene, willConnectTo: session, options: connectionOptions) }
-
sceneDidEnterBackground:
:- (void)sceneDidEnterBackground:(UIScene *)scene { [FollowAnalytics sceneDidEnterBackground:scene]; }
func sceneDidEnterBackground(_ scene: UIScene) { FollowAnalytics.sceneDidEnterBackground(scene) }
-
sceneWillEnterForeground:
:- (void)sceneWillEnterForeground:(UIScene *)scene { [FollowAnalytics sceneWillEnterForeground:scene]; }
func sceneWillEnterForeground(_ scene: UIScene) { FollowAnalytics.sceneWillEnterForeground(scene) }
-
sceneDidBecomeActive:
:- (void)sceneDidBecomeActive:(UIScene *)scene { [FollowAnalytics sceneDidBecomeActive:scene]; }
func sceneDidBecomeActive(_ scene: UIScene) { FollowAnalytics.sceneDidBecomeActive(scene) }
-
openURLContexts:
:- (void) scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts { [FollowAnalytics scene:scene openURLContexts:URLContexts]; }
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { FollowAnalytics.scene(scene, openURLContexts: URLContexts) }
Configuration
To customize the SDK behavior, you must define your desired SDK parameters by setting the related properties values on the FollowAnalyticsConfiguration
object passed to the SDK initialization method:
Parameter | Type | Default Value | Description |
---|---|---|---|
apiKey |
string | - | Your app api key. You can find it on the FollowAnalytics platform in the Administration section. |
appGroup |
string | - | An app group identifier to link the extension target to the app. |
isVerbose |
boolean | false | true to see internal logs made by the SDK in the console. Note that setting isVerbose to true will automatically set apiMode to .dev . So make sure to set isVerbose to false for production build. More information in the Analytics section. |
apiMode |
enum | .prod | .dev or .prod for Swift, FollowAnalyticsAPIModeDev or FollowAnalyticsAPIModeProd for Objective-C. In Dev apiMode, logs, attributes and crashes sent by the SDK will be ignored by the platform, but you still can see them in the Device Observer. More information in the Analytics section. |
optInAnalyticsDefault |
boolean | true | true to make the user opt-in analytics by default. More information in the Opt-in Analytics section. |
optInNotificationsDefault |
boolean | true | true to make the user opt-in notifications by default. More information in the Opt-in Notifications section. |
crashReportingEnabled |
boolean | true | true to enable FollowAnalytics crash reporting. |
isDataWalletEnabled |
boolean | false | true to enable DataWallet. |
dataWalletDefaultPolicyPath |
string | - | To define the path of your dataWallet policy . |
onDataWalletPolicyChange |
callback | - | Called when a new significant version of dataWallet policy is available. |
archivePushMessages |
boolean | false | true to archive Push campaigns messages. More information in the Archiving messages section. |
archiveInAppMessages |
boolean | false | true to archive In-App campaigns messages. More information in the Archiving messages section. |
maxBackgroundTimeWithinSession |
int | 120 | To determine the lifetime of a session when in background (between 15 and 3600). |
onNotificationTapped |
callback | - | Called when user taps on a notification. |
onNotificationReceived |
callback | - | Called when device receives a message from a Push campaign that contains custom parameters (i.e. at least one key/value pair). |
onNativeInAppButtonTapped |
callback | - | Called when user taps on a custom button of a Native Alert In-App campaign. |
shouldOpenURL |
callback | true | Called when user taps on a URL (website links or custom URL schemes) from a Push or In-App campaigns. This callback returns a boolean value indicating to the SDK if it should call open(_:options:completionHandler:) or not. More information in the Implement custom behavior on URL opening section. |
swizzlingEnabled |
boolean | true | false to disable the Swizzling process. More information in the Disabling swizzling section. |
lastKnownLocationEnabled |
boolean | false | true to enable the logging of the last known location when the session starts. |
Updating from older versions
Updating from 6.8 to 6.9
- Before v6.9.0, if the
apiMode
was not explicitly defined in theConfiguration
, the SDK was automatically changing it based on theisVerbose
value. From v6.9.0 the SDK will no longer change theapiMode
automatically on real device and we recommend that you set it explicitly in your code, based on the XcodeDEBUG
flag like this:
#if DEBUG
cfg.apiMode = FollowAnalyticsAPIModeDev;
#else
cfg.apiMode = FollowAnalyticsAPIModeProd;
#endif
#if DEBUG
cfg.apiMode = FollowAnalyticsAPIMode.dev
#else
cfg.apiMode = FollowAnalyticsAPIMode.prod
#endif
Updating from 6.4 to 6.5
- Now, by default, the last known location is no longer logged when a session starts. If you want to enable this feature you must set the configuration parameter
lastKnownLocationEnabled
totrue
from theFollowAnalyticsConfiguration
object passed to the SDK initialization.
Updating from 6.4.0 to 6.4.1
- The
automaticallyOpenNotificationURL
Configuration parameter is now replaced by theshouldOpenURL
callback. If you hadautomaticallyOpenNotificationURL
set tofalse
, or if you want to handle Universal Links to your own website, consider implementingshouldOpenURL
. It allows you to define the behavior when an URL is about to be opened by the SDK. More information in the Implement custom behavior on URL opening section. - Calling
FABage.enable()
is no longer necessary because now badges are always enabled. More information in the badge management section.
Updating from 6.3 to 6.4
- Consider calling
requestProvisionalNotificationAuthorization()
at app launch, to allow your app to receive quiet notifications from FollowAnalytics platform. - Replace your call to
requestNotificationCenterDefaultAuthorisation()
byrequestNotificationAuthorization()
, and consider calling this method in the right place in your user journey. - Update your implementation of
onNotificationTapped
according to its new signature. Now it take a non-nullnotificationInfo
object and a non-nullactionIdentifier
string. Theurl
andparams
you usually got in the previous signature are now accessible through thenotificationInfo
object. More information in the onNotificationTapped section. - From 6.4.0, by default, your implementation of
onNotificationTapped
no longer needs to open the received url, indeed the url is automatically opened by the SDK whenautomaticallyOpenURL
is set totrue
in the SDK configuration. See Handling links section for more details. - Update your implementation of
onNotificationReceived
according to its new signature. Now it takes a non-nullnotificationInfo
object. Make sure to make your implementation following the required rules defined in the onNotificationReceived section. - Implement
onNativeInAppButtonTapped
to handle the tap on Native Alert custom buttons. More information in the onNativeInAppButtonTapped section. - Note that
onOpenURL
,onIncomingCustomCampaign
andonIncomingDeepLink
callbacks are no longer available. Make sure to migrate your code logic to adopt the new callbacks. - Now calling
enableGeofencing()
in no longer needed, geofencing works out of the box as soon as your app get the "Always" location authorization. - Prior to 6.4.0, for apps that had the location authorization and that was calling
enableGeofencing()
, the SDK was requesting periodic location updates internally and was sending locations logs to the FollowAnalytics platform. Since 6.4.0, it's the responsibility of the developer to send location logs to the platform by using the newlogLocation()
methods, as explained in the Logging Locations section.
Updating from 6.2 to 6.3
If your app implements onIncomingDeepLink
and onOpenURL
callbacks:
- Move your current implementation of
onIncomingDeepLink
toonNotificationReceived
and make necessary changes - Add
onNotificationTapped
andonNotificationReceived
callbacks - Move your current implementation of
onOpenURL
toonNotificationTapped
and make necessary changes. You you want to open theurl
passed as argument to this callback, you will have to add your own code to do so.
Updating from 6.1 to 6.2
- Replace
debug
byisVerbose
in FollowAnalyticsConfiguration
Updating to 6.0
- Replace all undefined methods with corresponding methods defined by the new FollowAnalytics interfaces
- For manual integration, do not forward anymore delegate methods to FollowAnalytics. We automatically intercept the invocations when needed.
- Remove
UserNotifications.framework
andMobileCoreServices.framework
from all your targets.
Updating from 5.3 to 5.4
- Change imports from
<FollowApps/...>
to<FollowAnalytics/...>
- Previous versions of opt-out via settings bundle are deprecated and completely removed starting with version 6 of the SDK. While still available, a warning shall be sent to log about the deprecated use. The new 5.4 opt-out feature must be used for RGPD compliance.
- if using change strip framework to the new
${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/FollowAnalytics.framework/strip-frameworks.sh
Updating from 5.2 to 5.3
- In your Podfile replace
pod FollowApps
bypod FollowAnalytics
Updating from 5.0 to 5.1
-
Replace this method:
+ (BOOL)configureWithId:(nonnull NSString *)FAId debugStateOn:(BOOL)isDebug options:(nonnull NSDictionary *)options;
by
+ (BOOL)configureWithId:(nonnull NSString *)FAId sharedAppGroup:(nullable NSString * )appGroup automatise:(BOOL)automatise debugStateOn:(BOOL)isDebug options:(nullable NSDictionary *)options;
-
If you used the badge management, you have to specify your appGroup shared between the app and the notification service extension.
-
If you use geofencing in your app. You have to call this method :
+ (void)enableGeofencing;
Updating from 4 to 5.0.0
To use version 5.0.0+ of the iOS SDK:
- Link these additional Frameworks in the Settings of your targets:
UserNotifications.framework
.MobileCoreServices.framework
.libz.tbd
.
- PassKit is not required anymore. If you don't use it you can remove it.
-
Replace these deprecated methods:
+ (void)addCustomUserAttributeSet:(NSSet *)attributeSet forKey:(NSString *)key + (BOOL)removeCustomUserAttribute:(NSString *)attribute fromSetWithKey:(NSString *)key //Remove one element from the specify set.
by:
+ (BOOL)addCustomUserAttribute:(NSString *)attribute toSetWithKey:(NSString *)key //Add only one string element into the specify set + (BOOL)removeCustomUserAttributeSet:(NSSet *)set fromSetWithKey:(NSString *)key // remove a set of string element from a specify set
Updating from 3.* to 4.*
The migration is seamless. However, please refer to the section around user attributes to learn how to feed user profiles using the SDK.
Updating from 2.* to 3.0.0
To use version 3.0.0+ of the iOS SDK:
- Link an additional Framework in the Settings of your targets:
libsqlite3.dylib
. -
In your
AppDelegate.m
file, replace this deprecated method:- (void)followAppsShouldHandleParameters:(NSDictionary *)openingParameters
with:
- (void)followAppsShouldHandleParameters:(NSDictionary *)customParameters actionIdentifier:(NSString *)actionIdentifier actionTitle:(NSString *)actionTitle completionHandler:(void (^)())completionHandler
These new parameters are provided only when running on iOS 8 and later. They are the interactive notification parameters that you would want to get to know which action was performed on a FollowAnalytics notification.
Nothing else changes. Please refer to the rest of the documentation to discover what the newer versions of the SDK now allow.