推送通知实践2019

2019-04-15  本文已影响0人  勇往直前888

需求分析

版本兼容性

第三方服务

相对来说,极光推送会好用一点;比如,测试消息中,"mutable-content": "1", 这个值的添加,极光推送可以,但是友盟推送做不到。
下面的代码也是友盟封装过的函数。

关于设备号

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
    // NSData => NSString;去掉分隔符与空格
    NSString *deviceTokenString = [[[[deviceToken description] stringByReplacingOccurrencesOfString: @"<"withString: @""] stringByReplacingOccurrencesOfString: @">"withString: @""] stringByReplacingOccurrencesOfString: @" "withString: @""];

推送类型

/** 绑定一个别名至设备(含账户,和平台类型)
 @warning 添加Alias的先决条件是已经成功获取到device_token,否则失败(kUMessageErrorDependsErr)
 @param name 账户,例如email
 @param type 平台类型,参见本文件头部的`kUMessageAliasType...`,例如:kUMessageAliasTypeSina
 @param handle block返回数据,error为获取失败时的信息,responseObject为成功返回的数据
 */
+ (void)addAlias:(NSString * __nonnull)name type:(NSString * __nonnull)type response:(void (^__nonnull)(id __nullable responseObject,NSError * __nullable error))handle;

这次,我们用的是单播,收钱了,以用户号和设备号两个唯一标识,给指定用户推送收钱提醒消息。

关于注册:

/**
 友盟推送的注册接口

 @param launchOptions 系统的launchOptions启动消息参数用于处理用户通过消息打开应用相关信息。
 @param entity 友盟推送的注册类如果使用默认的注册,Entity设置为nil即可。如需其他的可选择其他参数,具体的参考demo或者文档。
 @param completionHandler iOS10授权后的回调。
 */
+ (void)registerForRemoteNotificationsWithLaunchOptions:(NSDictionary * __nullable)launchOptions Entity:(UMessageRegisterEntity * __nullable)entity completionHandler:(void (^ __nullable)(BOOL granted, NSError *_Nullable error))completionHandler;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}

一般情况下(NSDictionary * __nullable)launchOptions是空的。如果APP没开,用户收到推送消息之后,点击,可以打开APP,这个时候,推送信息就包含在这个(NSDictionary * __nullable)launchOptions中。

从执行的时间来说,一个相对合理的流程是:在启动的时候马上注册,这样收到苹果返回的deviceToken就相对比较早。先存本地,等用户登录成功之后,再将这个deviceToken上传自己的后台。多次上传也没关系,反正只要不解注册,所生成的deviceToken是相同的。

关于证书

Xcode直接给手机安装的是Debug版本,对应的后台是测试模式。如果后台切换到正式模式,需要采用Ad-Hoc的方式安装Release版本才能收到消息。

推送开关

/** 解除RemoteNotification的注册(关闭消息推送,实际调用:[[UIApplication sharedApplication] unregisterForRemoteNotifications])
 
 iOS10.0,iOS10.1两个版本存在系统bug,调用此方法后可能会导致无法再次打开推送
 */
+ (void)unregisterForRemoteNotifications;

消息接收

// iOS10新增:处理前台收到通知的代理方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler API_AVAILABLE(ios(10.0)) {
    
    // 语音播报消息内容
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [UMessage setAutoAlert:NO];
        //应用处于前台时的远程推送接受
        //必须加这句代码
        [UMessage didReceiveRemoteNotification:userInfo];
    } else {
        //应用处于前台时的本地推送接受
    }
    completionHandler(UNNotificationPresentationOptionSound|UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert);
}
// 推送
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
}

推荐的方式还是最低支持版本改为iOS10,上面的AppDelegate.m中的代理函数就需要出现了。

APP关闭,或者处于后台或者锁屏的时候,,能够收到推送消息,但是,对应的响应代码是不会执行的。就算开了后台执行能力也没有什么用。

点击响应

// iOS10新增:处理后台点击通知的代理方法
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)){
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        // 应用处于后台时的远程推送接受
        // 必须加这句代码
        [UMessage didReceiveRemoteNotification:userInfo];
    } else {
        //应用处于后台时的本地推送接受
    }
}

语音播报

#import <AVFoundation/AVFoundation.h>

// 说一句话
- (void)speakSentence:(NSString *)sentence {
    // 打开后台播报功能
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    // 文字转语音
    AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
    AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:sentence];
    utterance.rate = AVSpeechUtteranceDefaultSpeechRate;
    utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    [synthesizer speakUtterance:utterance];
}

第三的文字转语音,相对要好听一点;系统自带的声音比较机械,相对来说音质要差一点。

推送扩展

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // Modify the notification content here...
    
    // 播报声音
    NSString *body = self.bestAttemptContent.userInfo[@"aps"][@"alert"][@"body"];
    if (body != nil) {
        [self speakSentence:body];
    }
    
    // 转发通知
    self.contentHandler(self.bestAttemptContent);
}

- (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);
}

// 说一句话
- (void)speakSentence:(NSString *)sentence {
    // 打开后台播报功能
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    
    // 文字转语音
    AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
    AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:sentence];
    utterance.rate = AVSpeechUtteranceDefaultSpeechRate;
    utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    [synthesizer speakUtterance:utterance];
}
上一篇下一篇

猜你喜欢

热点阅读