iOS Features – Real-time Data Sync

Introduction

Certain use cases demand that the Geo-fences, Beacons, GEOLINE™, as well as the Actions and Conditions associated with them on the back-end, are synced to the mobile devices immediately. The Bluedot Point SDK for iOS can be optionally configured to receive push notifications to enable Real-time Data Sync. The present implementation supports integration through Google Firebase cloud messaging, however, future versions of the SDK will allow you to utilize any other push infrastructure, giving you the flexibility to connect your existing push integrations. This documentation will guide you through the integration processes and steps to activate Real-time Data Sync.

Integrate Firebase SDK into your project

Prerequisites

Before you begin, you need a few things set up in your environment:

  • Xcode 10.0 or later.
  • For Cloud Messaging:
    • A physical iOS device.
    • APNs certificate with Push Notifications enabled.
  • An Xcode project and its bundle identifier.
  • CocoaPods 1.5.0 or later.

Add Firebase to your app

To add Firebase to your app, you will need to create a Firebase project and a Firebase configuration file. This can be achieved with the following steps:

1. Create a Firebase project in the Firebase console. If you already have an existing Google project associated with your mobile app, you can import it by clicking Import Google Project , otherwise, click Create New Project.

2. Click Add Firebase to your iOS app and follow the setup steps. If you’re importing an existing Google project, this may happen automatically and you can just download the config file.

3. When prompted, enter your app’s bundle ID. It’s important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project.

4. At the end, you’ll download a GoogleService-Info.plist file. You can download this file again at any time.

5. If you haven’t done so already, copy this into your Xcode project root.

Add Firebase SDK

Firebase recommend using CocoaPods to install the libraries. You can install CocoaPods by following the installation instructions. Alternatively, the SDK frameworks can be downloaded as a zip file (~100MB) from here.

Integrate with CocoaPods

After installing the CocoaPods, you need create a Podfile in your Xcode project:

$ cd your-project directory
$ pod init

Then add the pods that you want to install.

# Uncomment the next line to define a global platform for your project
platform :ios, '10.0'

target 'BDRealTimeSyncSampleApp' do
 # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
 use_frameworks!

# Pods for BDRealTimeSyncSampleApp
 pod 'BluedotPointSDK'
 pod 'Firebase/Core'
 pod 'Firebase/Messaging'
end

install the pods to add the prerequisite libraries needed to get Firebase up and running in your iOS app, along with Firebase Analytics. Then, you can open the .xcworkspace file to see the project in Xcode.

$ pod install
$ open your-project.xcworkspace

 

Upload your APNs certificate

If you don’t have an APNs certificate yet, see Provisioning APNs SSL Certificates.

1. Inside your project in the Firebase console, select the gear icon, select Project Settings, and then select the Cloud Messaging tab.

2. Select the Upload Certificate button for your development certificate, your production certificate, or both. At least one is required.

3. For each certificate, select the .p12 file, and provide the password, if any. Make sure the bundle ID for this certificate matches the bundle ID of your app. Select Save.

Initialize Firebase in your app

You’ll need to add Firebase initialization code to your application. Import the Firebase module and configure a shared instance as shown:

1. Import the Firebase module:

@import Firebase;
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
@import UserNotifications; //Required for user notifications for iOS 10
#endif

2. Configure a FIRApp shared instance in application:didFinishLaunchingWithOptions: method

// Use Firebase library to configure APIs
[FIRApp configure]; 

3. Either at startup, or at the desired point in your application flow, register your app for remote notifications. Call registerForRemoteNotifications as shown:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) { UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; } else { // iOS 10 or later #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions: authOptions completionHandler: ^(BOOL granted, NSError * _Nullable error) {
    }];
 
    // For iOS 10 display notification (sent via APNS)
    [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
    // For iOS 10 data message (sent via FCM)
    [[FIRMessaging messaging] setRemoteMessageDelegate:self];
    #endif
}
 
[[UIApplication sharedApplication] registerForRemoteNotifications];
image

Notes: For devices running iOS 10 and above, you must assign your delegate object to the UNUserNotificationCenter object to receive display notifications, and the FIRMessaging object to receive data messages, before your app finishes launching. For example, in an iOS app, you must assign it in the applicationWillFinishLaunching: or applicationDidFinishLaunching: method.

4. By default, the FCM SDK generates a registration token for the client app instance on initial startup of your app. If you want to target single devices, or create device groups for FCM, you’ll need to access this token. When you need to retrieve the current token, call [[FIRInstanceID instanceID] token]. This method returns null if the token has not yet been generated.

NSString *refreshedToken = [[FIRInstanceID instanceID] token];

5. You can access the token’s updated value by adding an observer that listens to kFIRInstanceIDTokenRefreshNotification then retrieve the token from the observer’s selector. kFIRInstanceIDTokenRefreshNotification fires when tokens are generated, so calling[[FIRInstanceID instanceID] token]in its context ensures that you are accessing a current, available registration token. In this example, tokenRefreshNotification is the selector used to handle the callback:

// Add an observer that listens to kFIRInstanceIDTokenRefreshNotification and pass the token to selector tokenRefreshNotification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tokenRefreshNotification:) name:kFIRInstanceIDTokenRefreshNotification object:nil];
...
 
- (void)tokenRefreshNotification:(NSNotification *)notification {
    // Note that this callback will be fired everytime a new token is generated, including the first
    // time. So if you need to retrieve the token as soon as it is available this is where that
    // should be done.
    NSString *refreshedToken = [[FIRInstanceID instanceID] token];
    NSLog(@"InstanceID token: %@", refreshedToken);
 
    // Connect to FCM since connection may have failed when attempted before having a token.
    [self connectToFcm];
 
    // TODO: If necessary send token to application server.
}

6. To receive or send messages through FCM (not just the APNs interface), you’ll need to connect to the FCM service. Connect when your application becomes active and whenever a new registration token is available. Once your app is connected, FCM ignores subsequent attempts to connect.

- (void)connectToFcm {
  [[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
    if (error != nil) {
      NSLog(@"Unable to connect to FCM. %@", error);
    } else {
      NSLog(@"Connected to FCM.");
    }
  }];
}

7. If you have disabled method swizzling, you’ll need to explicitly map your APNs token to the FCM registration token. Override the methods didRegisterForRemoteNotificationsWithDeviceToken to retrieve the APNs token, and then call setAPNSToken. Also, make sure that the value of type is correctly set: FIRInstanceIDAPNSTokenTypeSandbox for the sandbox environment, orFIRInstanceIDAPNSTokenTypeProd for the production environment.

// With "FirebaseAppDelegateProxyEnabled": NO
- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
             [FIRInstanceID instanceID] setAPNSToken:deviceToken
                                                type:FIRInstanceIDAPNSTokenTypeSandbox];
}
image

Notes: The FCM API performs method swizzling in two key areas: mapping your APNs token to the FCM registration token and capturing analytics data during downstream message callback handling. Developers who prefer not to use swizzling can disable it by adding the flagFirebaseAppDelegateProxyEnabled in the app’s Info.plist file and setting it to NO (boolean value).

9. If you need to deactivate Analytics collection permanently in a version of your app, setFIREBASE_ANALYTICS_COLLECTION_DEACTIVATED to YES in your app’s Info.plist file. SettingFIREBASE_ANALYTICS_COLLECTION_DEACTIVATED to YES takes priority over any values forFIREBASE_ANALYTICS_COLLECTION_ENABLED in your app’s Info.plist as well as any values set withsetAnalyticsCollectionEnabled.

Connect Bluedot with Firebase

To receive Real-time Push Notification, you need to connect Point SDK with Firebase Service by uploading Firebase Server key to Point Access web interface and subscribe the topic with Bluedot App API Key.

Uploading Server key from Firebase

Firebase Server key can be retrieved from Cloud Messaging tab by selecting Project Setting inside your project in the Firebase console.

Then copy the Server key and put into Firebase API Key in your Bluedot Application details from Point Access web interface.

Subscribe the topic using Bluedot App API Key

To make sure that push notification will be delivered to your applications which is using specific Bluedot Application. Your client app needs to subscribe the topic with Bluedot App API Key. The FIRMessaging class handles topic messaging functionality. To subscribe to a topic, call subscribeToTopic:topic from your application’s main thread (FCM is not thread-safe).

Also, your client needs to first register your app with both APNs and FCM to ensure that it can receive notifications. That involves a network call, which means you can’t subscribe to topics when your app first launches. Instead, we would recommend putting that code into your application:didRegisterUserNotificationSettings handler.

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [[FIRMessaging messaging] subscribeToTopic:@"/topics/YOUR_BLUEDOT_APP_API_KEY"];
    ...
}
image

Notes: This makes an asynchronous request to the FCM backend and subscribes the client to the given topic. If the subscription request fails initially, FCM retries until it can subscribe to the topic successfully.

Bluedot Push Interface

When your client app has received the Real-time Push Notification, you need to pass the userInfo from the notification as a parameter to the method notifyPushUpdateWithData: from BDLocationManager:

- (void)notifyPushUpdateWithData: (NSDictionary *)data;

Put the method in UNUserNotificationCenterDelegate userNotificationCenter:willPresentNotification:withCompletionHandler: to handle notifications received when the client app is in the foreground. The message is a UNNotificationobject. Implement FIRMessagingDelegate applicationReceivedRemoteMessage: to handle all data messages that are sent to the client. The message is a FIRMessagingRemoteMessage object.

// Receive displayed notifications
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSDictionary *userInfo = notification.request.content.userInfo;
    [BDLocationManager.instance notifyPushUpdateWithData:userInfo];
    ...
}
 
// Receive data message
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
    [BDLocationManager.instance notifyPushUpdateWithData:[remoteMessage appData]];
    ...
}
#endif
image

Notes: Point SDK will only utilize data of push notification sent with unique identifier confirming whether it is a Bluedot data, and will ignore any other data received which does not contain Bluedot’s unique identifier.

Created by Bluedot DevOps on June 19, 2018

Start the discussion