1.推送流程
个推的 iOS 推送包括 2 个部分,APNs推送与应用内消息。
- 绿色部分是指通过苹果的APNs服务器进行推送,由开发者的应用通过APNs服务器向目标设备发送通知。
- 红色部分是指应用内推送,通过个推平台提供的SDK,在应用启动时与个推服务器建立长连接,使开发者可以通过个推服务器向应用内推送消息。这种方式性能和稳定性更强,是对APNs的一个重要补充。
简而言之,绿色部分是外部推送,红色部分是应用内推送。
APNs 推送
苹果官方提供的推送通知服务,个推中iOS的离线通知均使用该服务进行下发。
应用内消息(透传消息)
应用内推送即透传消息,个推只负责消息传递,不做任何处理,客户端在接收到透传消息后需要自己去处理消息的展示方式或后续动作。
2.SDK 集成与配置
2.1 创建个推应用
创建应用,生成 AppID、AppKey、AppSecret
2.2 CocoaPods 集成
在podfile里面增加
pod ‘GTSDK’
pod ‘GTExtensionSDK’
2.3 项目配置
-
开启Push Notification能力。找到应用Target设置中的Signing & Capabilities,点击左上角+添加。如果没有开启该开关,应用将获取不到DeviceToken:
-
开启Push Notification能力。找到应用Target设置中的Signing & Capabilities,点击左上角+添加。如果没有开启该开关,应用将获取不到DeviceToken:
Remote notifications:APNs静默推送权限 -
使用NotificationService,同样开启Access WiFi Information设置。
3.编写代码
- 在[AppDelegate didFinishLaunchingWithOptions]方法中调用个推sdk初始化方法,传入个推平台分配的 AppID、AppKey、AppSecret。同时,调用APNs注册方法,尝试获取APNs DeviceToken。示例代码如下:
/// 个推开发者网站中申请App时,注册的AppId、AppKey、AppSecret
#define kGtAppId @"iMahVVxurw6BNr7XSn9EF2"
#define kGtAppKey @"yIPfqwq6OMAPp6dkqgLpG5"
#define kGtAppSecret @"G0aBqAD6t79JfzTB6Z5lo5"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 通过个推平台分配的appId、 appKey 、appSecret 启动SDK,注:该方法需要在主线程中调用
[GeTuiSdk startSdkWithAppId:kGtAppId appKey:kGtAppKey appSecret:kGtAppSecret delegate:self launchingOptions:launchOptions];
// 注册远程通知
[GeTuiSdk registerRemoteNotification: (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)];
return YES;
}
- GeTuiSdkDelegate
**
* SDK登入成功返回clientId
*
* @param clientId 标识用户的clientId
* 说明:启动GeTuiSdk后,SDK会自动向个推服务器注册SDK,当成功注册时,SDK通知应用注册成功。
* 注意: 注册成功仅表示推送通道建立,如果appid/appkey/appSecret等验证不通过,依然无法接收到推送消息,请确保验证信息正确。
*/
- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
NSLog(@"\n>>>[GeTuiSdk RegisterClient]:%@\n\n", clientId);
if (clientId.length > 0) {
NSUserDefaults *u_def = [NSUserDefaults standardUserDefaults];
[u_def setValue:clientId forKey:@"clientId"];
[u_def synchronize];
}
}
/**
* SDK运行状态通知
*
* @param status 返回SDK运行状态
*/
- (void)GeTuiSDkDidNotifySdkState:(SdkStatus)status {
}
/**
* SDK遇到错误消息返回error
*
* @param error SDK内部发生错误,通知第三方,返回错误
*/
- (void)GeTuiSdkDidOccurError:(NSError *)error {
NSString *msg = [NSString stringWithFormat:@"[GeTuiSdk GeTuiSdkDidOccurError]:%@\n\n",error.localizedDescription];
NSLog(@"%@", msg);
}
- 通知回调
/// 通知展示(iOS10及以上版本)
/// @param center center
/// @param notification notification
/// @param completionHandler completionHandler
- (void)GeTuiSdkNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification * )notification
completionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
__API_AVAILABLE(macos(10.14), ios(10.0), watchos(3.0), tvos(10.0)) {
NSString *msg = [NSString stringWithFormat:@"[APNs] %@ \n%@", NSStringFromSelector(_cmd), notification.request.content.userInfo];
NSLog(@"%@", msg);
}
/// 收到通知信息
/// @param userInfo apns通知内容
/// @param center UNUserNotificationCenter(iOS10及以上版本)
/// @param response UNNotificationResponse(iOS10及以上版本)
/// @param completionHandler 用来在后台状态下进行操作(iOS10以下版本)
- (void)GeTuiSdkDidReceiveNotification:(NSDictionary *)userInfo
notificationCenter:(nullable UNUserNotificationCenter *)center
response:(nullable UNNotificationResponse *)response
fetchCompletionHandler:(nullable void (^)(UIBackgroundFetchResult))completionHandler {
NSString *msg = [NSString stringWithFormat:@"[APNs] %@ \n%@", NSStringFromSelector(_cmd), userInfo];
NSLog(@"%@", msg);
// [self handleRouteWithUserInfo:userInfo];
if (completionHandler) {
// [ 参考代码,开发者注意根据实际需求自行修改 ] 根据APP需要自行修改参数值
completionHandler(UIBackgroundFetchResultNoData);
}
}
/// 收到透传消息
/// @param userInfo 推送消息内容
/// @param fromGetui YES: 个推通道 NO:苹果apns通道
/// @param offLine 是否是离线消息,YES.是离线消息
/// @param appId 应用的appId
/// @param taskId 推送消息的任务id
/// @param msgId 推送消息的messageid
/// @param completionHandler 用来在后台状态下进行操作(通过苹果apns通道的消息 才有此参数值)
- (void)GeTuiSdkDidReceiveSlience:(NSDictionary *)userInfo
fromGetui:(BOOL)fromGetui
offLine:(BOOL)offLine
appId:(nullable NSString *)appId
taskId:(nullable NSString *)taskId
msgId:(nullable NSString *)msgId
fetchCompletionHandler:(nullable void (^)(UIBackgroundFetchResult))completionHandler {
NSString *msg = [NSString stringWithFormat:@"[APN] %@ \nReceive Slience: fromGetui:%@ appId:%@ offLine:%@ taskId:%@ msgId:%@ userInfo:%@ ", NSStringFromSelector(_cmd), fromGetui ? @"个推消息" : @"APNs消息", appId, offLine ? @"离线" : @"在线", taskId, msgId, userInfo];
NSLog(@"个推消息--->%@", msg);
[GeTuiSdk sendFeedbackMessage:90001 andTaskId:taskId andMsgId:msgId];
// if(completionHandler){
//震动模式
for (int i = 0; i < 3; i++) {
SystemSoundID shake = kSystemSoundID_Vibrate;
AudioServicesPlaySystemSound(shake);
}
NSString *payloadStr = userInfo[@"payload"];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; //标题
content.sound = [UNNotificationSound defaultSound];
content.body = payloadStr;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
if (@available(iOS 15.0, *)) {
content.interruptionLevel = UNNotificationInterruptionLevelTimeSensitive;//会使手机亮屏且会播放声音;可能会在免打扰模式(焦点模式)下展示
content.body = payloadStr;
}
#endif
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"dcx" content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
}];
// }
}
- UNUserNotificationCenterDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(macos(10.14), ios(10.0), watchos(3.0), tvos(10.0))
{
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(macos(10.14), ios(10.0), watchos(3.0)) API_UNAVAILABLE(tvos)
{
completionHandler();
}