Ver Fonte

ios local notification

leon há 1 ano atrás
pai
commit
c7ebebc9a8

+ 2 - 0
ios/AppDelegate.h

@@ -8,5 +8,7 @@
 
 @property (nonatomic, strong) UIWindow *window;
 @property (nonatomic, strong) NativeBridge *nativeBridge;
+@property (nonatomic, strong) NSTimer *timer;
+@property (nonatomic, assign) BOOL rnLoaded;
 
 @end

+ 100 - 9
ios/AppDelegate.mm

@@ -24,6 +24,7 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
   RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
   std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
   facebook::react::ContextContainer::Shared _contextContainer;
+  
 }
 @end
 #endif
@@ -35,6 +36,7 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
 //  [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenNotificationSettingsURLString]];
 //  NSString *url = UIApplicationOpenNotificationSettingsURLString;
   // APNS
+  self.rnLoaded = NO;
   NSDate *date = [NSDate date];
   //zone为当前时区信息  在我的程序中打印的是@"Asia/Shanghai"
   NSTimeZone *zone = [NSTimeZone systemTimeZone];
@@ -80,15 +82,31 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
   [self.window makeKeyAndVisible];
   [super application:application didFinishLaunchingWithOptions:launchOptions];
   
-  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-  [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
-  NSDate *date1 = [dateFormatter dateFromString:@"2024-05-30 22:00:00"];
-  [self scheduleCalendarNotificationWithTitle:@"你好" body:@"推送" date:date1 repeats:YES identifier:@"push1"];
-  [self demo];
+//  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+//  [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+//  NSDate *date1 = [dateFormatter dateFromString:@"2024-05-30 22:00:00"];
+//  [self scheduleCalendarNotificationWithTitle:@"你好" body:@"推送" date:date1 repeats:YES identifier:@"push1"];
+//  [self demo];
 //  [self registerForPushNotifications];
+  
+  [NSTimer scheduledTimerWithTimeInterval:15.0
+                                       target:self
+                                     selector:@selector(timerFired:)
+                                     userInfo:nil
+                                      repeats:NO];
   return YES;
 }
 
+- (void)timerFired:(NSTimer *)timer {
+    // 定时器触发后执行的代码
+    NSLog(@"Timer fired!");
+  
+//  [self.nativeBridge.bridge.eventDispatcher sendAppEventWithName:@"notificationReceive" body:@{
+//    @"title":@"hello",
+//    @"value":@"world"
+//  }];
+}
+
 - (void)registerForPushNotifications {
     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
     [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
@@ -124,7 +142,7 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
 {
 //  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
-#if DEBUG
+#if DEBUGaaaa
   return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
 #else
   return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
@@ -226,10 +244,85 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
     [[RCTJPushEventQueue sharedInstance]._localNotificationQueue insertObject:userInfo atIndex:0];
     [[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_OPENED_EVENT object:userInfo];
   }
+  self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(postNotificationData:) userInfo:response repeats:YES];
+//  NSString *categoryIdentifier = response.notification.request.content.categoryIdentifier;
+//  [self.nativeBridge.bridge.eventDispatcher sendAppEventWithName:@"notificationReceive" body:@{@"category_id":categoryIdentifier,@"action_id":response.actionIdentifier}];
+  
+  // 处理用户交互
+//      if ([response.actionIdentifier isEqualToString:@"ALLOW_ACTION"]) {
+//          // 用户点击了"允许"按钮,发起网络请求
+//        NSLog(@"User allow the request");
+//        
+////        [self.nativeBridge.bridge.eventDispatcher sendAppEventWithName:@"notificationReceive" body:@{@"name":@"1",@"value":@"2"}];
+//        
+////          [self makeNetworkRequest];
+//      } else if ([response.actionIdentifier isEqualToString:@"DENY_ACTION"]) {
+//          // 用户点击了"拒绝"按钮
+//          NSLog(@"User denied the request");
+////        [self makeNetworkRequest];
+//      } else if ([response.actionIdentifier isEqualToString:@"START_TIMER_NOW"]){
+//        if ([categoryIdentifier isEqualToString:@"REMINDER_FS_START_FAST"]){
+//          
+//        }
+//        else if ([categoryIdentifier isEqualToString:@"REMINDER_FS_START_SLEEP"]){
+//          
+//        }
+//      } else if ([response.actionIdentifier isEqualToString:@"PICK_EARLIER_START"]){
+//        if ([categoryIdentifier isEqualToString:@"REMINDER_FS_START_FAST"]){
+//          
+//        }
+//        else if ([categoryIdentifier isEqualToString:@"REMINDER_FS_START_SLEEP"]){
+//          
+//        }
+//      }
+//      else if ([response.actionIdentifier isEqualToString:@"END_TIMER_NOW"]){
+//        
+//      }
+//      else if ([response.actionIdentifier isEqualToString:@"PICK_EARLIER_END"]){
+//        
+//      }
+//      else if ([response.actionIdentifier isEqualToString:@"SKIP"]){
+//        
+//      }
   // 系统要求执行这个方法
   completionHandler();
 }
 
+- (void)postNotificationData:(NSTimer *)timerInfo{
+  
+  
+  if (self.rnLoaded){
+    UNNotificationResponse *response = timerInfo.userInfo;
+    [self.timer invalidate];
+    self.timer = nil;
+    
+    
+    NSString *categoryIdentifier = response.notification.request.content.categoryIdentifier;
+    [self.nativeBridge.bridge.eventDispatcher sendAppEventWithName:@"notificationReceive" body:@{@"category_id":categoryIdentifier,@"action_id":response.actionIdentifier}];
+  }
+  else {
+    
+  }
+}
+
+- (void)makeNetworkRequest{
+  //https://api.fast.dev.liveplus.fun/api/static-resource-urls
+  NSURL *url = [NSURL URLWithString:@"https://api.fast.dev.liveplus.fun/api/static-resource-urls"];
+      NSURLRequest *request = [NSURLRequest requestWithURL:url];
+      
+      NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
+          if (error) {
+              NSLog(@"Error: %@", error.localizedDescription);
+          } else {
+              // 处理返回的数据
+              NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+              NSLog(@"Response: %@", json);
+          }
+      }];
+      
+      [dataTask resume];
+}
+
 //自定义消息
 - (void)networkDidReceiveMessage:(NSNotification *)notification {
   NSDictionary * userInfo = [notification userInfo];
@@ -250,9 +343,7 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
   UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
 
   // 3. 创建 notification request
-  UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"DailyReminder"
-                                                                        content:content
-                                                                        trigger:trigger];
+  UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"DailyReminder" content:content trigger:trigger];
 
   // 4. 添加 notification request 到通知中心
   UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

+ 250 - 51
ios/NativeBridge.m

@@ -20,6 +20,16 @@
 
 RCT_EXPORT_MODULE()
 
+- (instancetype)init {
+  self = [super init];
+  if (self) {
+    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
+    appDelegate.nativeBridge = self;
+    // 在这里进行初始化操作
+  }
+  return self;
+}
+
 -(NSArray<NSString *>*)supportedEvents
 {
   return @[@"receive"];
@@ -27,31 +37,38 @@ RCT_EXPORT_MODULE()
   
 }
 
+RCT_EXPORT_METHOD(rnPageLoaded){
+  dispatch_async(dispatch_get_main_queue(), ^{
+    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
+    appDelegate.rnLoaded = YES;
+  });
+}
+
 RCT_EXPORT_METHOD(getNotificationAuthStatus){
   dispatch_async(dispatch_get_main_queue(), ^{
     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
     [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
-        UNAuthorizationStatus status = settings.authorizationStatus;
-        
-        switch (status) {
-            case UNAuthorizationStatusAuthorized:
-                NSLog(@"用户已授权通知权限");
-            [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"authorized"];
-                break;
-                
-            case UNAuthorizationStatusDenied:
-                NSLog(@"用户已拒绝通知权限");
-            [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"denied"];
-                break;
-                
-            case UNAuthorizationStatusNotDetermined:
-                NSLog(@"通知权限未确定");
-            [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"not_determined"];
-                break;
-                
-            default:
-                break;
-        }
+      UNAuthorizationStatus status = settings.authorizationStatus;
+      
+      switch (status) {
+        case UNAuthorizationStatusAuthorized:
+          NSLog(@"用户已授权通知权限");
+          [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"authorized"];
+          break;
+          
+        case UNAuthorizationStatusDenied:
+          NSLog(@"用户已拒绝通知权限");
+          [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"denied"];
+          break;
+          
+        case UNAuthorizationStatusNotDetermined:
+          NSLog(@"通知权限未确定");
+          [self.bridge.eventDispatcher sendAppEventWithName:@"notificationResult" body:@"not_determined"];
+          break;
+          
+        default:
+          break;
+      }
     }];
   });
 }
@@ -61,59 +78,241 @@ RCT_EXPORT_METHOD(authNotification){
   dispatch_async(dispatch_get_main_queue(), ^{
     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
     [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
-        if (granted) {
-          [self.bridge.eventDispatcher sendAppEventWithName:@"operateNotificationResult" body:@"authorized"];
-            dispatch_async(dispatch_get_main_queue(), ^{
-                [[UIApplication sharedApplication] registerForRemoteNotifications];
-            });
-        } else {
-            // 用户拒绝通知或发生错误
-          [self.bridge.eventDispatcher sendAppEventWithName:@"operateNotificationResult" body:@"denied"];
-        }
+      if (granted) {
+        [self.bridge.eventDispatcher sendAppEventWithName:@"operateNotificationResult" body:@"authorized"];
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [[UIApplication sharedApplication] registerForRemoteNotifications];
+        });
+      } else {
+        // 用户拒绝通知或发生错误
+        [self.bridge.eventDispatcher sendAppEventWithName:@"operateNotificationResult" body:@"denied"];
+      }
     }];
   });
 }
 
 RCT_EXPORT_METHOD(addLocalPush:(NSString *)title
                   withBody:(NSString *)body
-                  withTime:(NSString *)time){
+                  withTime:(NSString *)time
+                  withDetail:(id)detail){
   dispatch_async(dispatch_get_main_queue(), ^{
-    // 1. 设置 notification 内容
-    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
+    //设置通知内容
+    UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc] init];
     content.title = title;
     content.body = body;
-    content.sound = [UNNotificationSound defaultSound];
     
-    // 按冒号分割字符串为数组
-    NSArray *timeArray = [time componentsSeparatedByString:@":"];
-
-    // 从数组中取出时分秒的值
+    NSString *category_id = detail[@"category_id"];
+    NSString *message_id = detail[@"id"];
+    NSString *mode = detail[@"mode"];
+    
+    NSArray *actions;
+    if ([category_id isEqualToString:@"REMINDER_FS_START_FAST"]||[category_id isEqualToString:@"REMINDER_FS_START_SLEEP"]){
+      //消息的处理按钮
+      UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"START_TIMER_NOW" title:@"Start timer now with 1-tap" options:UNNotificationActionOptionForeground];
+      
+      UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"PICK_EARLIER_START" title:@"Pick an earlier start" options:UNNotificationActionOptionForeground];
+      
+      UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"SKIP" title:@"Skip" options:UNNotificationActionOptionAuthenticationRequired];
+      
+      actions = @[action1,action2,action3];
+    }
+    else if([category_id isEqualToString:@"REMINDER_FS_END_FAST"]||[category_id isEqualToString:@"REMINDER_FS_END_SLEEP"]){
+      //消息的处理按钮
+      UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"END_TIMER_NOW" title:@"End timer now with 1-tap" options:UNNotificationActionOptionForeground];
+      
+      UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"PICK_EARLIER_END" title:@"Pick an earlier end" options:UNNotificationActionOptionForeground];
+      
+      UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"Skip" title:@"SKIP" options:UNNotificationActionOptionAuthenticationRequired];
+      
+      actions = @[action1,action2,action3];
+    }
+    
+    
+    
+    UNNotificationCategory *categroy = [UNNotificationCategory categoryWithIdentifier:category_id actions:actions intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
+    
+    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:categroy]];
+    content.categoryIdentifier = category_id;
+    
+    //设置推送的触发机制
+    NSArray *timeArray = [@"19:07:00" componentsSeparatedByString:@":"];
     NSInteger hour = [[timeArray objectAtIndex:0] integerValue];
     NSInteger minute = [[timeArray objectAtIndex:1] integerValue];
     NSInteger second = [[timeArray objectAtIndex:2] integerValue];
-
+    
     // 2. 设置触发条件 - 每天 9:00 AM
     NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
     dateComponents.hour = hour;
     dateComponents.minute = minute;
+    dateComponents.second = second;
     UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
-
-    // 3. 创建 notification request
-    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"DailyReminder"
-                                                                          content:content
-                                                                          trigger:trigger];
-
-    // 4. 添加 notification request 到通知中心
-    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
-    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
-        if (error != nil) {
-            NSLog(@"Error adding notification request: %@", error);
-        }
+    
+    
+    NSString * identifier = @"notification_onlytextid";
+    UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
+    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
+      
     }];
+    
+    //    // 1. 设置 notification 内容
+    //    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
+    //    content.title = title;
+    //    content.body = body;
+    //    content.sound = [UNNotificationSound defaultSound];
+    //
+    //    // 按冒号分割字符串为数组
+    //    NSArray *timeArray = [@"10:51:00" componentsSeparatedByString:@":"];
+    //
+    //    // 从数组中取出时分秒的值
+    //    NSInteger hour = [[timeArray objectAtIndex:0] integerValue];
+    //    NSInteger minute = [[timeArray objectAtIndex:1] integerValue];
+    //    NSInteger second = [[timeArray objectAtIndex:2] integerValue];
+    //
+    //    // 2. 设置触发条件 - 每天 9:00 AM
+    //    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
+    //    dateComponents.hour = hour;
+    //    dateComponents.minute = minute;
+    //    dateComponents.second = second;
+    //    UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
+    //
+    //    // 3. 创建 notification request
+    //    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"DailyReminder" content:content trigger:trigger];
+    //
+    //    // 4. 添加ations
+    //    // 创建允许按钮动作
+    //        UNNotificationAction *allowAction = [UNNotificationAction actionWithIdentifier:@"ALLOW_ACTION" title:@"Allow" options:UNNotificationActionOptionForeground];
+    //
+    //        // 创建拒绝按钮动作
+    //        UNNotificationAction *denyAction = [UNNotificationAction actionWithIdentifier:@"DENY_ACTION" title:@"Deny" options:UNNotificationActionOptionDestructive];
+    //
+    //        // 创建动作集合
+    //    UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"NOTIFICATION_CATEGORY" actions:@[allowAction, denyAction] intentIdentifiers:@[@"ALLOW_ACTION",@"DENY_ACTION"] options:UNNotificationCategoryOptionCustomDismissAction];
+    //
+    //    // 5. 添加 notification request 到通知中心
+    //    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+    //    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:category]];
+    //
+    //    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
+    //        if (error != nil) {
+    //            NSLog(@"Error adding notification request: %@", error);
+    //        }
+    //    }];
   });
 }
 
 
+//RCT_EXPORT_METHOD(addLocalPush:(NSString *)title
+//                  withBody:(NSString *)body
+//                  withTime:(NSString *)time
+//                  withDetail:(id)detail){
+//  dispatch_async(dispatch_get_main_queue(), ^{
+//    //设置通知内容
+//    UNMutableNotificationContent * content = [[UNMutableNotificationContent alloc] init];
+//    content.title = title;
+//    content.body = body;
+//    //        content.subtitle = @"推送的子标题";
+//    //        content.badge = [NSNumber numberWithInteger:0];// 红标
+//    //        content.sound = [UNNotificationSound defaultSound];
+//    //[UNNotificationSound soundNamed:@""]; 自定义推送声音
+//
+//    //        //给通知添加本地图片或者视频,写法同下
+//    //        NSString *path = [[NSBundle mainBundle] pathForResource:@"rank2" ofType:@"png"];
+//    //        NSError *error = nil;
+//    //        /*
+//    //         UNNotificationAttachment是指可以包含音频,图像或视频内容。使用本地通知时,可以在通知创建时,将附件加入即可。对于远程通知,则必须实现使用UNNotificationServiceExtension类通知服务扩展。
+//    //         */
+//    //        UNNotificationAttachment *img_attachment = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
+//    //        if (error) {
+//    //            NSLog(@"%@", error);
+//    //        }
+//    //        content.attachments = @[img_attachment];//默认只显示第一个
+//    //        content.launchImageName = @"launch2";
+//
+//    //消息的处理按钮
+//    UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"START_TIMER_NOW" title:@"START_TIMER_NOW" options:UNNotificationActionOptionForeground];
+//
+//    UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"PICK_EARLIER_START" title:@"PICK_EARLIER_START" options:UNNotificationActionOptionForeground];
+//
+//    UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"SKIP" title:@"SKIP" options:UNNotificationActionOptionAuthenticationRequired];
+//
+//    UNNotificationCategory *categroy = [UNNotificationCategory categoryWithIdentifier:@"REMINDER_FS_START_FAST" actions:@[action1,action2,action3] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
+//
+//    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:categroy]];
+//    content.categoryIdentifier = @"REMINDER_FS_START_FAST";
+//
+//    //设置推送的触发机制
+//    UNTimeIntervalNotificationTrigger * trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
+//
+//    //日历形式,
+//    //    NSDateComponents * dateComp = [[NSDateComponents alloc] init];
+//    //    dateComp.weekday = 2;//周一,默认第一天是周日
+//    //    dateComp.month = 12;//月份,您可以在这里设置具体的时分秒
+//    //    dateComp.hour = 10;//小时
+//    //    dateComp.minute = 14;//分钟
+//    //    UNCalendarNotificationTrigger * calendarTrigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComp repeats:YES];
+//
+//    //地理位置推送.没实际应用过
+//    //    CLLocationCoordinate2D  location ;
+//    //    location.latitude = 123;
+//    //    location.longitude = 111;
+//    //
+//    //    CLCircularRegion * region = [[CLCircularRegion alloc] initWithCenter:location radius:100.0 identifier:@"regionid"];
+//    //
+//    //    UNLocationNotificationTrigger * locationTrigger = [UNLocationNotificationTrigger triggerWithRegion:region repeats:YES];
+//
+//    NSString * identifier = @"notification_onlytextid";
+//    UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
+//    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
+//
+//    }];
+//
+//    //    // 1. 设置 notification 内容
+//    //    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
+//    //    content.title = title;
+//    //    content.body = body;
+//    //    content.sound = [UNNotificationSound defaultSound];
+//    //
+//    //    // 按冒号分割字符串为数组
+//    //    NSArray *timeArray = [@"10:51:00" componentsSeparatedByString:@":"];
+//    //
+//    //    // 从数组中取出时分秒的值
+//    //    NSInteger hour = [[timeArray objectAtIndex:0] integerValue];
+//    //    NSInteger minute = [[timeArray objectAtIndex:1] integerValue];
+//    //    NSInteger second = [[timeArray objectAtIndex:2] integerValue];
+//    //
+//    //    // 2. 设置触发条件 - 每天 9:00 AM
+//    //    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
+//    //    dateComponents.hour = hour;
+//    //    dateComponents.minute = minute;
+//    //    dateComponents.second = second;
+//    //    UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
+//    //
+//    //    // 3. 创建 notification request
+//    //    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"DailyReminder" content:content trigger:trigger];
+//    //
+//    //    // 4. 添加ations
+//    //    // 创建允许按钮动作
+//    //        UNNotificationAction *allowAction = [UNNotificationAction actionWithIdentifier:@"ALLOW_ACTION" title:@"Allow" options:UNNotificationActionOptionForeground];
+//    //
+//    //        // 创建拒绝按钮动作
+//    //        UNNotificationAction *denyAction = [UNNotificationAction actionWithIdentifier:@"DENY_ACTION" title:@"Deny" options:UNNotificationActionOptionDestructive];
+//    //
+//    //        // 创建动作集合
+//    //    UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"NOTIFICATION_CATEGORY" actions:@[allowAction, denyAction] intentIdentifiers:@[@"ALLOW_ACTION",@"DENY_ACTION"] options:UNNotificationCategoryOptionCustomDismissAction];
+//    //
+//    //    // 5. 添加 notification request 到通知中心
+//    //    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+//    //    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:category]];
+//    //
+//    //    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
+//    //        if (error != nil) {
+//    //            NSLog(@"Error adding notification request: %@", error);
+//    //        }
+//    //    }];
+//  });
+//}
+
+
 @end
 
 

+ 1 - 1
ios/hola.xcodeproj/project.pbxproj

@@ -661,7 +661,7 @@
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				EXCLUDED_ARCHS = "";
-				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
+				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
ios/main.jsbundle


+ 9 - 0
src/context/locales/en.js

@@ -195,6 +195,15 @@ export default {
             }
             
         },
+        notification:{
+            action_title:{
+                start_timer_now: 'Start timer now with 1-tap',
+                pick_earlier_start: 'Pick an earlier start',
+                skip: 'Skip',
+                end_timer_now: 'End timer now with 1-tap',
+                pick_earlier_end: 'Pick an earlier end',
+            }
+        },
         common: {
             prompt: 'Prompt',
             action_sheet_cancel: 'Cancel',

+ 12 - 3
src/context/locales/zh.js

@@ -190,13 +190,22 @@ export default {
                 cancel: 'Achieve New Fasting Streak'
             },
             lost_reason: {
-                fast_streak_lost:'since you lost your fasting streak on {{date}}',
-                sleep_streak_lost:'since you lost your sleep streak on {{date}}',
-                fast_sleep_streaks_lost:'since you lost both of your fasting and sleep streaks on {{date}}',
+                fast_streak_lost: 'since you lost your fasting streak on {{date}}',
+                sleep_streak_lost: 'since you lost your sleep streak on {{date}}',
+                fast_sleep_streaks_lost: 'since you lost both of your fasting and sleep streaks on {{date}}',
                 sleep_streak_not_growing: 'since you didn\'t grow your sleep streak',
                 not_satisfied_after_delete: 'since you no longer have a fasting streak that satisfy the base requirement',
             }
         },
+        notification: {
+            action_title: {
+                start_timer_now: '一键立即开始计时',
+                pick_earlier_start: '选择更早开始',
+                skip: '跳过',
+                end_timer_now: '一键立即结束计时',
+                pick_earlier_end: '选择更早结束',
+            }
+        },
         common: {
             prompt: '提示',
             action_sheet_cancel: '取消',

+ 99 - 99
src/features/trackTimeDuration/actions/TrackTimeActions.tsx

@@ -1,7 +1,7 @@
 import { API_LOCAL_PUSHES } from "@/services/http/api";
 import { request } from "@/services/http/request";
 import { recordCheck } from "@/services/trackTimeDuration";
-import trackTimeService, { machine } from "@/store/trackTimeMachine"
+import trackTimeService from "@/store/trackTimeMachine"
 import Taro from "@tarojs/taro";
 import dayjs from 'dayjs'
 
@@ -106,83 +106,37 @@ export const uploadLocalPushInfo = (params) => {
 }
 
 export const getLocalPush = () => {
-    request({
-        url: API_LOCAL_PUSHES, method: 'GET', data: {}
-    }).then(res => {
-        const { messages } = res as any;
-        if (messages.length == 0) {
-            return;
-        }
-        if (process.env.TARO_ENV == 'weapp') {
-            return;
-        }
-        PushNotification.configure({
-            onRegister: function (token) {
-                console.log('TOKEN:', token);
-            },
-
-            onNotification: function (notification) {
-                console.log('NOTIFICATION:', notification);
-                // notification.finish(PushNotificationIOS.FetchResult.NoData);
-            },
-
-            permissions: {
-                alert: true,
-                badge: true,
-                sound: true,
-            },
-
-            popInitialNotification: true,
-            requestPermissions: true,
-        });
-        PushNotification.cancelAllLocalNotifications()
-
-        messages.map(item => {
-            if (Taro.getSystemInfoSync().platform == 'ios') {
-                if (item.mode == 'ONCE') {
-                    PushNotification.localNotificationSchedule({
-                        //... You can use all the options from localNotifications
-                        channelId: item.id,
-                        title: item.title,
-                        message: item.content + '  ', // (required)
-                        date: new Date(item.once), // in 60 secs
-                        allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
-                        messageId: item.id,
-                        // repeatType:'minute',
-                        /* Android Only Properties */
-
-                    })
-                }
-                else if (item.mode == 'RECURRING') {
-                    const { time, repeat_type } = item.recurring;
-                    const date = dayjs().format('YYYY-MM-DD')
-                    var Jto = require('react-native').NativeModules.NativeBridge;
-                    Jto.addLocalPush(item.title,item.content,time)
-                    // PushNotification.localNotificationSchedule({
-                    //     //... You can use all the options from localNotifications
-                    //     channelId: item.id,
-                    //     title: item.title,
-                    //     message: item.content + '  ', // (required)
-                    //     date: new Date(date + 'T' + time), // in 60 secs
-                    //     allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
-                    //     messageId: item.id,
-                    //     repeatType: repeat_type,
-                    //     // repeatType:'minute',
-                    //     /* Android Only Properties */
-
-                    // })
-                }
+    if (process.env.TARO_ENV == 'rn') {
+        request({
+            url: API_LOCAL_PUSHES, method: 'GET', data: {}
+        }).then(res => {
+            const { messages } = res as any;
+            if (messages.length == 0) {
+                return;
             }
-            else {
-                PushNotification.createChannel({
-                    channelId: item.id, // (required)
-                    channelName: "My channel", // (required)
-                    channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
-                    playSound: true, // (optional) default: true
-                    soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
-                    importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
-                    vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
-                }, (created) => {
+            PushNotification.configure({
+                onRegister: function (token) {
+                    console.log('TOKEN:', token);
+                },
+
+                onNotification: function (notification) {
+                    console.log('NOTIFICATION:', notification);
+                    // notification.finish(PushNotificationIOS.FetchResult.NoData);
+                },
+
+                permissions: {
+                    alert: true,
+                    badge: true,
+                    sound: true,
+                },
+
+                popInitialNotification: true,
+                requestPermissions: true,
+            });
+            PushNotification.cancelAllLocalNotifications()
+
+            messages.map(item => {
+                if (Taro.getSystemInfoSync().platform == 'ios') {
                     if (item.mode == 'ONCE') {
                         PushNotification.localNotificationSchedule({
                             //... You can use all the options from localNotifications
@@ -200,31 +154,77 @@ export const getLocalPush = () => {
                     else if (item.mode == 'RECURRING') {
                         const { time, repeat_type } = item.recurring;
                         const date = dayjs().format('YYYY-MM-DD')
-                        const { HolaModule } = NativeModules
-                        debugger
-                        HolaModule.addLocalPush(item.title, item.content, time)
-                        return;
-
-                        PushNotification.localNotificationSchedule({
-                            //... You can use all the options from localNotifications
-                            channelId: item.id,
-                            title: item.title,
-                            message: item.content + '  ', // (required)
-                            date: new Date(date + 'T' + time), // in 60 secs
-                            allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
-                            messageId: item.id,
-                            repeatType: repeat_type,
-                            // repeatType:'minute',
-                            /* Android Only Properties */
-
-                        })
+                        var Jto = require('react-native').NativeModules.NativeBridge;
+                        Jto.addLocalPush(item.title, item.content, time, item)
+                        // PushNotification.localNotificationSchedule({
+                        //     //... You can use all the options from localNotifications
+                        //     channelId: item.id,
+                        //     title: item.title,
+                        //     message: item.content + '  ', // (required)
+                        //     date: new Date(date + 'T' + time), // in 60 secs
+                        //     allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
+                        //     messageId: item.id,
+                        //     repeatType: repeat_type,
+                        //     // repeatType:'minute',
+                        //     /* Android Only Properties */
+
+                        // })
                     }
-                })
-            }
+                }
+                else {
+                    PushNotification.createChannel({
+                        channelId: item.id, // (required)
+                        channelName: "My channel", // (required)
+                        channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
+                        playSound: true, // (optional) default: true
+                        soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
+                        importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
+                        vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
+                    }, (created) => {
+                        if (item.mode == 'ONCE') {
+                            PushNotification.localNotificationSchedule({
+                                //... You can use all the options from localNotifications
+                                channelId: item.id,
+                                title: item.title,
+                                message: item.content + '  ', // (required)
+                                date: new Date(item.once), // in 60 secs
+                                allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
+                                messageId: item.id,
+                                // repeatType:'minute',
+                                /* Android Only Properties */
+
+                            })
+                        }
+                        else if (item.mode == 'RECURRING') {
+                            const { time, repeat_type } = item.recurring;
+                            const date = dayjs().format('YYYY-MM-DD')
+                            const { HolaModule } = NativeModules
+                            debugger
+                            HolaModule.addLocalPush(item.title, item.content, time)
+                            return;
+
+                            PushNotification.localNotificationSchedule({
+                                //... You can use all the options from localNotifications
+                                channelId: item.id,
+                                title: item.title,
+                                message: item.content + '  ', // (required)
+                                date: new Date(date + 'T' + time), // in 60 secs
+                                allowWhileIdle: true, // (optional) set notification to work while on doze, default: false
+                                messageId: item.id,
+                                repeatType: repeat_type,
+                                // repeatType:'minute',
+                                /* Android Only Properties */
+
+                            })
+                        }
+                    })
+                }
 
+            })
+
+            console.log('notificatin push set', messages)
         })
+    }
 
-        console.log('notificatin push set', messages)
-    })
 }
 

+ 62 - 0
src/features/trackTimeDuration/components/IndexConsole.tsx

@@ -69,6 +69,68 @@ export default function IndexConsole(props: { record: any, count: number }) {
 
     })
 
+    useEffect(() => {
+        if (process.env.TARO_ENV == 'rn') {
+            if (Taro.getSystemInfoSync().platform == 'ios') {
+                var Jto = require('react-native').NativeModules.NativeBridge;
+                var NativeAppEventEmitter = require('react-native').NativeAppEventEmitter;
+                Jto.getNotificationAuthStatus()
+                NativeAppEventEmitter.addListener('notificationReceive', (data) => {
+                    console.log('notification receive action', data)
+                    const { category_id, action_id } = data
+                    switch (action_id) {
+                        case 'START_TIMER_NOW':
+                            {
+                                if (category_id == 'REMINDER_FS_START_FAST'){
+                                    operateType = 'startFast'
+                                }
+                                else {
+                                    operateType = 'startSleep'
+                                }
+                                global.set_time = new Date().getTime()
+                                pickerConfirm(new Date().getTime())
+                            }
+                            break;
+                        case 'PICK_EARLIER_START':
+                            {
+                                if (category_id == 'REMINDER_FS_START_FAST'){
+                                    tapStartFast(null)
+                                }
+                                else {
+                                    tapStartSleep(null)
+                                }
+                            }
+                            break;
+                        case 'END_TIMER_NOW':
+                            {
+                                if (category_id == 'REMINDER_FS_END_FAST'){
+                                    operateType = 'endFast'
+                                }
+                                else {
+                                    operateType = 'endSleep'
+                                }
+                                global.set_time = new Date().getTime()
+                                pickerConfirm(new Date().getTime())
+                            }
+                            break;
+                        case 'PICK_EARLIER_END':
+                            {
+                                if (category_id == 'REMINDER_FS_END_FAST'){
+                                    tapEndFast(null)
+                                }
+                                else {
+                                    tapEndSleep(null)
+                                }
+                            }
+                            break;
+                        case 'SKIP':
+                            break;
+                    }
+                })
+            }
+        }
+    }, [])
+
     useEffect(() => {
         if (currentRecord.fast) {
             var fastCount = currentRecord.fast.target_end_time - currentRecord.fast.target_start_time

+ 8 - 7
src/pages/clock/Clock.tsx

@@ -20,15 +20,11 @@ import IndexConsole from "@/features/trackTimeDuration/components/IndexConsole";
 import Modal from '@/components/layout/Modal'
 import { compareVersion, getTimezone, getTimezoneId, getTimezoneName, rpxToPx } from "@/utils/tools";
 import RecordFastSleep from "@/features/trackTimeDuration/components/RecordFastSleep";
-import DayLight from "@/features/trackTimeDuration/components/DayLight";
-import { getInfo, latestLocation } from "@/services/user";
-import { TimeFormatter } from "@/utils/time_format";
 import WeekCalendar from "@/features/trackTimeDuration/components/WeekCalendar";
 import { useTranslation } from "react-i18next";
 import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
 import Layout from "@/components/layout/layout";
 import { ModalType, NaviBarTitleShowType, TemplateType } from "@/utils/types";
-import TitleView from "@/features/trackTimeDuration/components/TitleView";
 import ClockHeader from "@/features/trackTimeDuration/components/ClockHeader";
 import DurationPicker from "@/features/trackTimeDuration/components/DurationPicker";
 import SegmentPop from "@/features/trackTimeDuration/components/SegmentPop";
@@ -41,7 +37,6 @@ import { showDay } from "@/store/day";
 import { clientInfo, staticResources, systemVersion } from "@/services/common";
 import { changeFastDuration, changeSleepDuration, setCurrentRecord, setSchedule } from "@/store/ring";
 import { checkAuthorized } from "@/utils/check_authorized";
-import NoData from "@/components/view/NoData";
 import { AtActivityIndicator } from "taro-ui";
 import Tooltip from "@/components/view/Tooltip";
 import AllRings from "@/features/daynight/AllRings";
@@ -150,7 +145,7 @@ export default function Page() {
         }, 1000)
     }, [])
 
-    
+
 
     useEffect(() => {
 
@@ -287,7 +282,7 @@ export default function Page() {
 
     }, [])
 
-    async function demo(){
+    async function demo() {
     }
 
     useEffect(() => {
@@ -312,10 +307,16 @@ export default function Page() {
                 if (Taro.getSystemInfoSync().platform == 'ios') {
                     var Jto = require('react-native').NativeModules.NativeBridge;
                     Jto.getNotificationAuthStatus()
+                    Jto.rnPageLoaded()
                     NativeAppEventEmitter.addListener('notificationResult', (data) => {
+                        console.log('notification auth result', data)
                         global.notification = data;
                         uploadPermissions()
                     })
+                    NativeAppEventEmitter.addListener('notificationReceive', (data) => {
+                        console.log('notification receive action 222', data)
+                        debugger
+                    })
                 }
 
                 // uploadPermissions()

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff