All Products
Search
Document Center

Mobile Platform as a Service:iOS

Last Updated:Jan 19, 2024

This guide introduces how to integrate MPS to iOS client. You can integrate MPS to iOS client based on native project with CocoaPods.

Note

Since June 28, 2020, mPaaS has stopped support for the baseline 10.1.32. Please use 10.1.68 or 10.1.60 instead. For how to upgrade the baseline from version 10.1.32 to 10.1.68 or 10.1.60, see mPaaS 10.1.68 upgrade guide or mPaaS 10.1.60 upgrade guide.

Prerequisites

You have integrated your project to mPaaS. For more information, refer to Integrate based on native framework and using Cocoapods.

Procedure

To use MPS, you should complete the following steps.

  1. Use CocoaPods plugin to add the MPS SDK.

    1. In the Podfile file, use mPaaS_pod "mPaaS_Push" to add dependency.

    2. Execute pod install to complete integrating the SDK.

  2. Configure the project.

    Enable the following functions in the TARGETS directory of your project:

    • Capabilities > Push Notificationspush-ca

    • Capabilities > Background Modes > Remote notificationspush-back

  3. Use the SDK. In the case of using CocoaPods to access the iOS client based on an existing project, you need to complete the following operations.

    1. (Optional) Register device token.

      The message push SDK will automatically request the registration of deviceToken when the application is started. Generally, you do not need to request the registration of deviceToken. But in special cases (such as when there is privacy control at startup, when all network requests are blocked), you need to trigger the registration of deviceToken again after the control and authorization. The sample code is as follows:

      - (void)registerRemoteNotification
      {
          // Push notification registration
          if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {// 10.0+
              UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
              center.delegate = self;
              [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
      
                      [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert|UNAuthorizationOptionSound|UNAuthorizationOptionBadge)
                                            completionHandler:^(BOOL granted, NSError * _Nullable error) {
                          // Enable or disable features based on authorization.
                          if (granted) {
                              dispatch_async(dispatch_get_main_queue(), ^{
                                  [[UIApplication sharedApplication] registerForRemoteNotifications];
                              });
                          }
                      }];
      
              }];
          } else {// 8.0,9.0
              UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge                                                                                         |UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil];
              [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
              [[UIApplication sharedApplication] registerForRemoteNotifications];
          }
      }
    2. Obtain the device token and bind it with user ID.

      The message push SDK provided by mPaaS encapsulates the logic of registering with the APNs server. After the program starts, the Push SDK automatically registers with the APNs server. You can obtain the deviceToken issued by APNs in the callback method of successful registration, and then call the interface method of PushService to report the binding userId to the mobile push core.

      // import <PushService/PushService.h>
      - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
      {
          [[PushService sharedService] setDeviceToken:deviceToken];
          [[PushService sharedService] pushBindWithUserId:@"your userid(to be replaced)" completion:^(NSException *error) {
          }];
      
      }

      The push SDK also provides the API - (void)pushUnBindWithUserId:(NSString *)userId completion:(void (^)(NSException *error))completion; for unbinding the device token from the user ID of the app. For example, you can call the unbind API after the user switches to another account.

    3. Receive push messages.

      After the client receives the pushed message, if the user clicks to view it, the system will start the corresponding application. The logic processing after receiving the push message can be done in the callback method of AppDelegate.

      • In the system versions earlier than iOS 10, the methods of processing notification bar messages or silent messages are as follows:

         // Cold start for push messages in system versions earlier than iOS 10
          - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
          NSDictionary *userInfo = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
          if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 10.0) {
          // Cold start for push messages in system versions earlier than iOS 10
          }
        
          return YES;
          }
        
          // When the app runs in the foreground, adopt the method of processing common push messages; when the app runs in the background or foreground, adopt the method of processing silent messages ; when the app version is earlier than iOS 10, adopt the method of processing notification bar messages
          -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler 
          {
          // Process received messages
          }
      • On iOS 10 and above, you need to implement the following delegate methods to listen for notification bar messages:

          // Register UNUserNotificationCenter delegate 
          if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 10.0) {
                  UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
                  center.delegate = self;
            }
        
           // Receive remote push messages when the app runs in the foreground
          - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
          {
              NSDictionary *userInfo = notification.request.content.userInfo;
        
              if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
                  // Receive remote push messages when the app runs in the foreground
        
              } else {
                  // Receive local push messages when the app runs in the foreground
        
              }
              completionHandler(UNNotificationPresentationOptionNone);
          }
        
          // Receive remote push messages when the app runs in the background or uses cold start mode
          - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler
          {
              NSDictionary *userInfo = response.notification.request.content.userInfo;
        
              if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
                  // Receive remote push messages when the app runs in the background or uses cold start mode
        
              } else {
                  // Receive local push messages when the app runs in the foreground
        
              }
              completionHandler();
        
          }
    4. Calculate message open rate.

      In order to count the open rate of messages on the client side, you need to call the pushOpenLogReport interface of PushService (available in versions 10.1.32 and above) to report the message open event when the app message is opened by the user. After the event is reported, you can view the statistics of the message open rate on the Message Push > Overview page in the mPaaS console.

      /**
       * Enable the API for reporting push messages so that the message open rate can be calculated.
       * @param  userInfo userInfo of a message
       * @return
       */
      - (void)pushOpenLogReport:(NSDictionary *)userInfo;
  4. Configure a push certificate.

    To push messages through the MPS console of mPaaS, you need to configure an APNs push certificate in the console. This certificate must match the signature on the client. Otherwise, the client cannot receive push messages.

    For more information about the configuration, see Configure an iOS push certificate.

Follow-up steps

  • After an APNs certificate is configured on the MPS console of mPaaS, messages can be pushed to applications in device dimension. MPS pushes messages to clients through Apple APNs. For more information, see Push process for Apple devices and Android devices outside China.

  • After user IDs are reported and the server binds them with device tokens, messages can be pushed to applications in user dimension.

Code sample

Click here to download the code sample.

Live Activity message push

iOS introduces a new feature in version 16.1: Live Activity. This feature can display real-time activities on the locked screen, helping users learn the progress of various activities in real time from the locked screen. In the main project, you can use the ActivityKit framework to start, update, and end the real-time activities. Among them, updating and ending real-time activities can also be achieved through using remote push. In the widget extension, you can use SwiftUI and WidgetKit to create the live activity interface. Among them, the live activity remote push update function does not support .p12 certificate, so users need to configure .p8 certificate.

Multiple live activities can be opened at the same time in the same project, and different live activities have different tokens.

Access client

Configure the project which support Live Activity

  1. Add a key-value pair in the Info.plist file of the main project. The key is NSSupportsLiveActivities and the value is YES.image

  2. Create a new Widget Extension. If it already exists in the project, you can skip this step.imageimage

Access client by code

  1. Create model.

    Create a new swift file in the main project code and define ActivityAttributes and Activity.ContentState in it. The following code is sample code, please write it according to actual business.

    import SwiftUI
    import ActivityKit
    
    struct PizzaDeliveryAttributes: ActivityAttributes {
        public typealias PizzaDeliveryStatus = ContentState
      
        public struct ContentState: Codable, Hashable {
            var driverName: String
            var estimatedDeliveryTime: ClosedRange<Date>
            
            init(driverName: String, estimatedDeliveryTime: ClosedRange<Date>) {
                self.driverName = driverName
                self.estimatedDeliveryTime = estimatedDeliveryTime
            }
            init(from decoder: Decoder) throws {
                let container: KeyedDecodingContainer<PizzaDeliveryAttributes.ContentState.CodingKeys> = try decoder.container(keyedBy: PizzaDeliveryAttributes.ContentState.CodingKeys.self)
                self.driverName = try container.decode(String.self, forKey: PizzaDeliveryAttributes.ContentState.CodingKeys.driverName)
                if let deliveryTime = try? container.decode(TimeInterval.self, forKey: PizzaDeliveryAttributes.ContentState.CodingKeys.estimatedDeliveryTime) {
                    self.estimatedDeliveryTime = Date()...Date().addingTimeInterval(deliveryTime * 60)
                } else if let deliveryTime = try? container.decode(String.self, forKey: PizzaDeliveryAttributes.ContentState.CodingKeys.estimatedDeliveryTime) {
                    self.estimatedDeliveryTime = Date()...Date().addingTimeInterval(TimeInterval.init(deliveryTime)! * 60)
                } else {
                    self.estimatedDeliveryTime = try container.decode(ClosedRange<Date>.self, forKey: PizzaDeliveryAttributes.ContentState.CodingKeys.estimatedDeliveryTime)
                }
            }
        }
      
        var numberOfPizzas: Int
        var totalAmount: String
    }
    
    • Both the main project target and Activity must be selected.

    • Received push messages are processed by the system and cannot be intercepted by developers.

    • ContentState contains data that can be dynamically updated. When pushing Live Activity notifications, the dynamically updated parameter names and types must correspond to those configured in ContentState.

    • If some data needs to be processed, you need to override the decoder method of ActivityAttributes.ContentState.

  2. Create interface.

    Create live, active interfaces in Widget Extensions. Creates the Widget and returns an Activity Configuration. Please write the specific UI according to your own business.

    image

  3. Use WidgetBundle.

    If the target App supports both widgets and live activities, use a WidgetBundle.

    import WidgetKit
    import SwiftUI
    
    @main
    structIslandBundle: WidgetBundle {
    varbody: someWidget {
    Island()
    IslandLiveActivity()
    }
    }
  4. Turn on the live activity.

    func startDeliveryPizza() {
        let pizzaDeliveryAttributes = PizzaDeliveryAttributes(numberOfPizzas: 1, totalAmount:"$99")
        let initialContentState = PizzaDeliveryAttributes.PizzaDeliveryStatus(driverName: "TIM", estimatedDeliveryTime: Date()...Date().addingTimeInterval(15 * 60))
        do {
            let deliveryActivity = try Activity<PizzaDeliveryAttributes>.request(
                attributes: pizzaDeliveryAttributes,
                contentState: initialContentState,
                pushType: .token)
        } catch (let error) {
            print("Error requesting pizza delivery Live Activity \(error.localizedDescription)")
        }
    }
  5. Submit Token.

    After the live activity is successfully turned on, the push Token of the live activity returned by the system is obtained through the pushTokenUpdates method. Call PushService's liveActivityBindWithActivityId:pushToken:filter:completion: method to submit. When submitting the Token, the identifier of the live activity needs to be submitted together. This identifier is needed when pushing live activities, and the server confirms the push target based on this identifier. Please customize the identity of this live activity. Different live activities have different ids (if they are same, it will cause push problems). For the same live activity, do not change the id when the Token is updated.

    Note

    ActivityKit is a swift language framework and does not support direct OC calls. When using the framework API, please call it in the swift file. Since MPPushSDK is an OC language, when swift calls OC, a bridge file needs to be created. And import #import <MPPushSDK/MPPushSDK.h> in the bridge file.

    let liveactivityId = UserDefaults.standard.string(forKey: "pushTokenUpdates_id") ?? "defloutliveactivityId"
    Task {
        for await tokenData in deliveryActivity.pushTokenUpdates {
            let newToken = tokenData.map { String(format: "%02x", $0) }.joined()       
            PushService.shared().liveActivityBind(withActivityId: liveactivityId, pushToken: newToken, filter: .call) { excpt in
                guard let excpt = excpt else {
                    ///Submitted successfully
                    return
                }
                if "callRepeat" == excpt.reason {
                    ///Repeated call, please ignore
                    print("pushTokenUpdates_id-Repeated calls")
                } else {
                    ///Submit failed
                }
            }
        }
    }

    After submitting successfully, the updates can be pushed by using the identification of live activities.

    Note

    Since the iPhone's pushTokenUpdates will be called twice at the same time, that is, in the scenario of multiple live activities, the previous live activity pushTokenUpdates will be reawakened when a new live activity is created, so the SDK provides a filtering function, controlled by the parameter filter:

    • When filter is MPPushServiceLiveActivityFilterAbandon, the SDK will automatically discard repeated calls without giving a callback.

    • When filter is MPPushServiceLiveActivityFilterCall, the SDK will automatically filter out this request and give a failure callback (callRepeat). At this time, error.reason is @"callRepeat", please ignore it.

    • When filter is MPPushServiceLiveActivityFilterReRefuse, no filtering is performed inside the SDK. When the same activityId and pushToken are called repeatedly, if the submitting fails, the client's re-submitting will not be considered the same call.

    The definition of MPPushServiceLiveActivityFilterType is as follows:

    typedef NS_ENUM(NSInteger, MPPushServiceLiveActivityFilterType){
        MPPushServiceLiveActivityFilterAbandon,//Abandon it directly without any callback
        MPPushServiceLiveActivityFilterCall,//Filter out this request and give a callback for failure(callRepeat)
        MPPushServiceLiveActivityFilterRefuse//No filtering
    };