iOS 本地推送(Local Push)

1、前言

推送是我们平时开发中常用的一种机制,无论iOS还是Android系统都有推送,推送可以让不在前台运行的app,告知用户app内部发生的事情,可以提高app的打开次数,增加日活。
iOS中的推送分为
1.本地推送通知(Local Notification)
2.远程推送通知(Remote Notification)
我们在平时的开发中,使用远程推送可能比较多,远程推送依赖于服务器,需要联网才能收到,本地推送无需联网,添加好定时器即可在指定时间发送推送,平时使用场景多是闹钟,提醒等。
本片文章我们主要讲解本地推送

2、本地推送(Local Push)

  • 无需联网即可推送
  • 不需要创建推送证书

3、push交互(示例基于iOS8.0及以上)

  • 注册通知,获取用户授权
// 在AppDelegate.m中
// iOS10.0 需要导入
#import 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self registerAPN];
    return YES;
}
    // 注册通知
- (void)registerAPN {

    if (@available(iOS 10.0, *)) { // iOS10 以上
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            
        }];
    } else {// iOS8.0 以上
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
    }
}
  • 添加通知
- (void)addLocalNotice {
    if (@available(iOS 10.0, *)) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
        // 标题
        content.title = @"测试标题";
        content.subtitle = @"测试通知副标题";
        // 内容
        content.body = @"测试通知的具体内容";
        // 声音
       // 默认声音
     //    content.sound = [UNNotificationSound defaultSound];
     // 添加自定义声音
       content.sound = [UNNotificationSound soundNamed:@"Alert_ActivityGoalAttained_Salient_Haptic.caf"];
        // 角标 (我这里测试的角标无效,暂时没找到原因)
        content.badge = @1;
        // 多少秒后发送,可以将固定的日期转化为时间
        NSTimeInterval time = [[NSDate dateWithTimeIntervalSinceNow:10] timeIntervalSinceNow];
//        NSTimeInterval time = 10;
        // repeats,是否重复,如果重复的话时间必须大于60s,要不会报错
        UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time repeats:NO];
        
        /*
        //如果想重复可以使用这个,按日期
        // 周一早上 8:00 上班
        NSDateComponents *components = [[NSDateComponents alloc] init];
        // 注意,weekday默认是从周日开始
        components.weekday = 2;
        components.hour = 8;
        UNCalendarNotificationTrigger *calendarTrigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];
        */
        // 添加通知的标识符,可以用于移除,更新等操作
        NSString *identifier = @"noticeId";
        UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
        
        [center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
            NSLog(@"成功添加推送");
        }];
    }else {
        UILocalNotification *notif = [[UILocalNotification alloc] init];
        // 发出推送的日期
        notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
        // 推送的内容
        notif.alertBody = @"你已经10秒没出现了";
        // 可以添加特定信息
        notif.userInfo = @{@"noticeId":@"00001"};
        // 角标
        notif.applicationIconBadgeNumber = 1;
        // 提示音
        notif.soundName = UILocalNotificationDefaultSoundName;
        // 每周循环提醒
        notif.repeatInterval = NSCalendarUnitWeekOfYear;
        
        [[UIApplication sharedApplication] scheduleLocalNotification:notif];
    }
}
  • 移除通知
// 移除某一个指定的通知
- (void)removeOneNotificationWithID:(NSString *)noticeId {
    if (@available(iOS 10.0, *)) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center getPendingNotificationRequestsWithCompletionHandler:^(NSArray * _Nonnull requests) {
            for (UNNotificationRequest *req in requests){
                NSLog(@"存在的ID:%@\n",req.identifier);
            }
            NSLog(@"移除currentID:%@",noticeId);
        }];
        
        [center removePendingNotificationRequestsWithIdentifiers:@[noticeId]];
    }else {
        NSArray *array=[[UIApplication sharedApplication] scheduledLocalNotifications];
        for (UILocalNotification *localNotification in array){
            NSDictionary *userInfo = localNotification.userInfo;
            NSString *obj = [userInfo objectForKey:@"noticeId"];
            if ([obj isEqualToString:noticeId]) {
                [[UIApplication sharedApplication] cancelLocalNotification:localNotification];
            }
        }
    }
}

// 移除所有通知
- (void)removeAllNotification {
    if (@available(iOS 10.0, *)) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center removeAllPendingNotificationRequests];
    }else {
        [[UIApplication sharedApplication] cancelAllLocalNotifications];
    }
}
  • 检查授权情况
- (void)checkUserNotificationEnable { // 判断用户是否允许接收通知
    if (@available(iOS 10.0, *)) {
        __block BOOL isOn = NO;
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            if (settings.notificationCenterSetting == UNNotificationSettingEnabled) {
                isOn = YES;
                NSLog(@"打开了通知");
            }else {
                isOn = NO;
                NSLog(@"关闭了通知");
               [self showAlertView];
            }
        }];
    }else {
        if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone){
            NSLog(@"关闭了通知");
            [self showAlertView];
        }else {
            NSLog(@"打开了通知");
        }
    }
}

- (void)showAlertView {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"通知" message:@"未获得通知权限,请前去设置" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
    [alert addAction:[UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
         [self goToAppSystemSetting];
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}

// 如果用户关闭了接收通知功能,该方法可以跳转到APP设置页面进行修改
- (void)goToAppSystemSetting {
    dispatch_async(dispatch_get_main_queue(), ^{
        UIApplication *application = [UIApplication sharedApplication];
        NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        if ([application canOpenURL:url]) {
            if (@available(iOS 10.0, *)) {
                if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
                    [application openURL:url options:@{} completionHandler:nil];
                }
            }else {
                [application openURL:url];
            }
        }
    });
}
参数参考
//下面是iOS 8.0的,iOS10.0及以上类似,具体使用可查找
fireDate:启动时间
timeZone:启动时间参考的时区
repeatInterval:重复推送时间(NSCalendarUnit类型),0代表不重复
repeatCalendar:重复推送时间(NSCalendar类型)
alertBody:通知内容
alertAction:解锁滑动时的事件
alertLaunchImage:启动图片,设置此字段点击通知时会显示该图片
alertTitle:通知标题,适用iOS8.2之后
applicationIconBadgeNumber:收到通知时App icon的角标
soundName:推送是带的声音提醒,设置默认的字段为UILocalNotificationDefaultSoundName
userInfo:发送通知时附加的内容
category:此属性和注册通知类型时有关联,(有兴趣的同学自己了解,不详细叙述)适用iOS8.0之后

region:带有定位的推送相关属性,具体使用见下面【带有定位的本地推送】适用iOS8.0之后
regionTriggersOnce:带有定位的推送相关属性,具体使用见下面【带有定位的本地推送】适用iOS8.0之后

  • 通知示例


    iOS 本地推送(Local Push)_第1张图片
    image.png

4、总结

本文主要介绍了本地通知的用法,将iOS8.0和10.0以上都进行了区分,具体的使用还需要大家根据具体情况而定,希望对大家有所帮助。
最后,附上Demo->>>>>传送门

5、参考

  • iOS10推送必看UNNotificationAttachment以及UNTimeIntervalNotificationTrigger
  • iOS开发,本地推送的使用
  • iOS系统与其他提示音汇总

你可能感兴趣的:(iOS 本地推送(Local Push))