天天看點

iOS設定工作日 本地通知提醒(周一到周五重複通知)

需求:

1 每周周一到周五的九點半,通過本地通知提醒簽到;

2 如果使用者當天九點半之前已經簽到,不再提醒;

3 如果使用者設定不提醒,則永不提醒

實作:

1 關于本地通知移步這裡

2 實作代碼

static NSNotificationName const _Nullable kCheckinNotification = @"CheckinNotification";
static NSString *const _Nullable kCheckinNotificationSwitchKey  = @"kCheckinNotificationSwitchKey";

/**  設定簽到通知*/
- (void)resetCheckinNotifications{

    // 使用者首次使用 預設開啟通知(相當于NSUserDefaults)
    if ([NSUtil getValueForKey:kCheckinNotificationSwitchKey] == nil) {
        [NSUtil saveValue:@(YES) forKey:kCheckinNotificationSwitchKey];
    }

    // 如果使用者關閉通知,直接傳回
    if([[NSUtil getValueForKey:kCheckinNotificationSwitchKey] isEqual: @(NO)]) return;

    // 取消以前的通知
    [self cancelAllNotification];

    // weekday 1:周日  2:周一, 3:周二 4:周三 5:周四 6:周五 7:周六
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *dateComps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday fromDate:[NSDate date]];
    NSDate *zeroDate = [calendar dateFromComponents:dateComps] ;
    NSDate *notifyDate = [zeroDate dateByAddingTimeInterval:9.5*60*60]; // 每天9:30分通知

    // 未來一周 建立5個通知:星期一到星期五 (過濾掉周末 并按周重複)
    for (int i=0;i<7;i++) {

        // 從明天開始
        NSInteger notifyWeekday = [dateComps weekday]+i+1;

        // 如果是明天到下周了,矯正weekday
        if(notifyWeekday >= 8){
            notifyWeekday = notifyWeekday-7;
        }
        // 明天是周六或周日 過濾掉
        if(notifyWeekday == 7 || notifyWeekday == 1) continue;

        // 計算未來通知的時間
        NSDate *date= [notifyDate dateByAddingTimeInterval:(i+1)*60*60*24];
        // 隻是一個時間的格式化,将日期作為通知的identifier
        NSString *identifier = [NSUtil stringWithDate:date format:@"yyyy-MM-dd"];

        if (@available(iOS 10.0, *)) {
            // weekday 2:周一, 3:周二 4:周三 5:周四 6:周五
            UNNotificationRequest *request = [self createNotificationRequestWithWeekday:notifyWeekday identifier:identifier];
            // 把通知加到UNUserNotificationCenter, 到指定觸發點會被觸發
            [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
        }
        else{
            UILocalNotification *notification = [self createLocalNotificationWithDate:date identifier:identifier];
            [kApplication scheduleLocalNotification:notification];
        }
    }

}

/**  取消一個特定的通知*/
- (void)cancelNotificationWithIdentifier:(NSString *)identifier{
    if (@available(iOS 10.0, *)) {
        [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[identifier]];
    }
    else{

        // 擷取目前所有的本地通知
        NSArray *notificaitons = [[UIApplication sharedApplication] scheduledLocalNotifications];
        if (!notificaitons || notificaitons.count <= 0) { return; }
        for (UILocalNotification *notify in notificaitons) {
            if ([[notify.userInfo objectForKey:@"identifier"] isEqualToString:identifier]) {
                [[UIApplication sharedApplication] cancelLocalNotification:notify];
                break;
            }
        }
    }

}
- (void)cancelAllNotification{
    if (@available(iOS 10.0, *)) {
        [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
        [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
    }
    else{
         [[UIApplication sharedApplication] cancelAllLocalNotifications];
    }
}

/**  取消已經推過的通知*/
- (void)removeAllDeliveredNotifications __IOS_AVAILABLE(10.0){
    if (@available(iOS 10.0, *)) {
        [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
    }
}



#pragma mark   -  私有方法

/**  設定指定時間通知,每周重複*/
- (UILocalNotification *)createLocalNotificationWithDate:(NSDate *)date identifier:(NSString *)identifier{

    UILocalNotification *localNotification = [[UILocalNotification alloc] init];

    // 1.設定觸發時間(如果要立即觸發,無需設定)
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    localNotification.fireDate = date;
    localNotification.repeatInterval = NSCalendarUnitWeekday;

    // 2.設定通知标題
    localNotification.alertBody = self.title.length ? self.title:@"簽到通知";
    localNotification.alertAction = self.content.length ? self.content:@"同學,今天簽到沒?千萬不要忘了哦!";
    // localNotification.applicationIconBadgeNumber = ++kApplication.applicationIconBadgeNumber;

    // 3.設定通知的 傳遞的userInfo
    localNotification.userInfo = @{@"kLocalNotificationID":kCheckinNotification,@"identifier":identifier};

    return localNotification;
}


/**  每個星期的星期幾 9點30通知*/
- (UNNotificationRequest *)createNotificationRequestWithWeekday:(NSInteger)weekday identifier:(NSString *)identifier {

    // 1.建立通知内容
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.sound = [UNNotificationSound defaultSound];
    content.title = self.title.length ? self.title:@"簽到提醒";
    content.body = self.content.length ? self.content:@"同學,今天簽到沒?千萬不要忘了哦!";
    //content.badge = @(++kApplication.applicationIconBadgeNumber); // 不顯示角标
    content.userInfo = @{@"kLocalNotificationID":kCheckinNotification,@"identifier":identifier};

    // 2.觸發模式 9點30 每周重複 ()
    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
    dateComponents.hour = 9;  // 九點
    dateComponents.minute = 30;
    dateComponents.weekday = weekday;
    UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];

    // 4.設定UNNotificationRequest
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];

    return request;
}
@end
           

3 使用

首次使用調用一次resetCheckinNotifications 即可

在簽到成功的方法裡判斷如果簽到的時間在今天九點半以前,調用一次resetCheckinNotifications(目的取消今天的,設定以後的通知)

注意 不能直接拿當天的日期作為identifier去取消通知(通知中心裡保留的identifier是設定通知時的那一周的日期)

4 需要再AppDelegate裡面,注冊通知,并處理接收通知的回調

5 不足:未過濾調節假日,是以節假日還會提醒

如果有什麼不對的地方,或者有什麼更好的實作方法,歡迎評論區留言指正

繼續閱讀