コンテンツにスキップ

Widget Extension

iOS 14からホーム画面やToday Viewに Widget Extension を設置できるようになりました。

実装は必須ではありませんが、ここでは、最新のお知らせタイトルを表示する方法についてご紹介します。


Extensionの作成

File > New > Target > iOS > Application Extension から、Widget Extension を選択し、Extension を作成します。

Extension


App Groupの作成

アプリ本体と Widget Extension でデータを共有するためには、App Group を作成することが必要です。

  1. ブラウザから iOS Dev Center にログインし、App Groups から App Group を作成します。
    App Groups1
  2. App IDs から iPhone アプリを選択し、App Groups を有効化します。プロビジョニングプロファイルは再作成してください。
    App Groups2
  3. iOS Dev Center において、Widget ExtensionのApp ID を作成します。(Xcode によって自動的に作られている場合もあります。)
  4. ここからは Xcode 上の作業となります。
    iPhone アプリと Widget Extension の TARGETS において、それぞれ Capabilities から App Groups を有効化します。
    App Groups3

アプリ側のコーディング

AppDelegate.swift において、お知らせを FANSHIP サーバーから取得した際にコールされる PopinfoReceiver デリゲートメソッドを実装します。

そのタイミングで、Widget Extension とデータを共有できる領域に最新のお知らせを保存します。

func popinfoReceiver(_ popinfoReceiver: PopinfoReceiver, updateMessagesResult result: Bool) {
    // 通信に失敗した場合は return
    guard result else { return }

    // 最新のお知らせを取得する
    let myListVC = PopinfoListViewController(nibName: "PopinfoListViewController", bundle: Bundle.main)
    let messages = myListVC.retrieveAllPopinfoMessages()
    guard messages.count > 0 else { return }
    let latestMessage = messages[0]

    // Widget Extension と連携するため、共有領域に最新のお知らせのタイトルと日時を保存する
    guard let ud = UserDefaults(suiteName: "App Group 名") else { return }
    ud.set(latestMessage.piTitle, forKey: "messageTitle")
    ud.set(latestMessage.piTime, forKey: "messageTime")

    // Widget Extensionのタイムラインを更新する
    WidgetCenter.shared.reloadAllTimelines()
}

Widget Extensionのコーディング

Extension を作成した際、Xcode のアプリプロジェクト上で、Product Nameで指定した名前のswiftファイルが自動で生成されます。
アプリ側で保存した値を読み込む例としては、以下のようなstructを用意して、Textなどで表示してください。

struct NewMessage {
    static let group = UserDefaults(suiteName: "App Group 名")
    static var messageTitle = group?.string(forKey: "messageTitle") ?? "お知らせはありません"
    static var messageTime : String {
        guard let time = group?.object(forKey: "messageTime") as? Date else { return "" }

        // 年月日ラベル用フォーマッタ
        let formatter = DateFormatter()
        let calendar = Calendar(identifier: .gregorian)
        formatter.calendar = calendar
        formatter.locale = NSLocale.system
        formatter.timeZone = NSTimeZone.system
        formatter.dateFormat = "yyyy/MM/dd"
        return formatter.string(from: time)
    }
}