iOS 負一屏(Today widget)功能的實現

gaozm0509發表於2020-03-27

概要

文章只是為了記錄 iOS todayWidget 的實現流程。

實現

新增 TodayWidget

1, 新增一個 target,如下圖(圖中的 TodayWidget 是我已新增的元件)

iOS 負一屏(Today widget)功能的實現

2,選擇 Today Extension

iOS 負一屏(Today widget)功能的實現

3,點選 Next,結果如下圖。(剛生成時應該只有 ViewController 檔案,其他的類都是我後期加上去的)

iOS 負一屏(Today widget)功能的實現

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”分別設定。記得勾選剛才設定的名稱。
      iOS 負一屏(Today widget)功能的實現
  • 資料傳遞和事件傳遞

    • 設定了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,乾貨不多。這篇文章一來記錄下自己的實現過程,二來拋磚引玉,主要是資料互動部分,可能有更好的方式,也希望看官不吝賜教。

相關文章