iOS 负一屏(Today widget)功能的实现

3,572 阅读2分钟

概要

文章只是为了记录 iOS todayWidget 的实现流程。

实现

添加 TodayWidget

1, 添加一个 target,如下图(图中的 TodayWidget 是我已添加的组件)

2,选择 Today Extension

3,点击 Next,结果如下图。(刚生成时应该只有 ViewController 文件,其他的类都是我后期加上去的)

UI 效果实现

1,这里没什么细讲的,和 iOS 原生开发没什么区别,唯一注意的一点是,可以通过如下枚举控制 Widget 是否可以展开

self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;

2,实现两个代理,注释很明确,没什么可说的。

// If implemented, the system will call at opportune times for the widget to update its state, both when the Notification Center is visible as well as in the background.
// An implementation is required to enable background updates.
// It's expected that the widget will perform the work to update asynchronously and off the main thread as much as possible.
// Widgets should call the argument block when the work is complete, passing the appropriate 'NCUpdateResult'.
// Widgets should NOT block returning from 'viewWillAppear:' on the results of this operation.
// Instead, widgets should load cached state in 'viewWillAppear:' in order to match the state of the view from the last 'viewWillDisappear:', then transition smoothly to the new data when it arrives.
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult result))completionHandler;

// If implemented, called when the active display mode changes.
// The widget may wish to change its preferredContentSize to better accommodate the new display mode.
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize __API_AVAILABLE(ios(10.0));

数据交互

  • 数据交互的前提是设置 App Groups,具体设置步骤如下

    • 点击如下红框按钮,弹出后选择 App Groups,然后点击App Groups 下面的“+”,输入名称。两个需要通讯的 targte 分别设置,例子中选中“Premium”和“TodayWidget”分别设置。记得勾选刚才设置的名称。
  • 数据传递和事件传递

    • 设置了App Groups 的两个 target 之间有两种通讯方式,各有利弊
      • 通知的方式,CFNotificationCenterPostNotification,

          // 发送通知
          - (void)postNotificaiton {
              CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter();
              CFNotificationCenterPostNotification(notification, CFSTR("com.your.name.to_app"), NULL,NULL, YES);
          }
          // 注册接收通知
          - (void)receiveNotification {
              CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter ();
              CFNotificationCenterAddObserver(notification, (__bridge const void *)(self), observerMethod,CFSTR("com.your.name.to_weiget"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
          }
          void observerMethod (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
              NSNotification *notification = [[NSNotification alloc] initWithName:@"callBack" object:nil userInfo:nil];
              [[NSNotificationCenter defaultCenter] postNotification:notification];
          }
        
      • 通过 NSUserDefaults 共享数据,存取类似,需要注意的是 NSUserDefaults 的实例化方法和确保 suiteName 两端保持一致

          NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.ingeek.widget"];
          NSArray *array = [userDefaults objectForKey:@"group.com.ingeek.your.suiteName"];
        
    • 通过通知的方式只能传递事件响应,无法传递和接收数据,NSUserDefaults 的方式只能共享数据,无法做到数据的及时响应,所以最好两种方式都一起使用。

结束

都是调用官方的 Api,干货不多。这篇文章一来记录下自己的实现过程,二来抛砖引玉,主要是数据交互部分,可能有更好的方式,也希望看官不吝赐教。