iOS 8から導入されたウィジェット機能を使ってみる - Qiitaでも掲載しております。
※本記事は、 一般に公開されている情報を元に作成しています。
iOS 8から通知センターにウィジェット(Widgets)を設置できるようになりました。
実装方法はすでに 一般にも公開されており、 開発者以外も読むことができます。
App Extension Programming Guide
ウィジェットは Extensions のひとつ
iOS 8 から Extensions という、新しいアプリ間連系の仕組みが導入されました。Extensions については shu223 さんの記事でとてもわかりやすく解説されています。
【iOS8】App Extension の実装方法 その1:Action
その中の「Today Extension」がウィジェットにあたります。(つまり、ウィジェットは Extensions のひとつ。なので "Widgets" で検索しても引っかからないかも)
実装方法
実装上のポイントは次の通り。
- ウィジェットは別ターゲットとして作成する
- ウィジェット内ではキーボードが使えない
- あまりスペースを専有しすぎないように注意
- ウィジェット内では定期的にスナップショットが撮られ、表示する際には最新のスナップショットが使われる
- スナップショットが更新されるタイミングで呼ばれるメソッドが用意されている
1. Extension 追加
File > New > Target から画面を開いて「Today Extension」を選びましょう。
(iOS Developerサイトから引用。Xcode 6のスクリーンショットではありません)
ウィジェット用のストーリーボードが自動で作成されます。
2. Info.plist
ウィジェット用のストーリーボードと一緒に Info.plist が作成されます。
<key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.widget-extension</string> <key>NSExtensionMainStoryboard</key> <string>MainInterface</string> </dict>
NSExtensionMainStoryboard
に指定したストーリーボードがウィジェットに表示されます。
ストーリーボードを使わない場合は NSExtensionMainStoryboard
を削除し、NSExtensionPrincipalClass
を追加します。このキーに、ウィジェットとして表示したいビューコントローラクラスを指定します。
3. スナップショット更新直前に呼ばれるメソッドを実装
ウィジェットは定期的に更新されるようです。そのたびに次のメソッドが呼ばれます。
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { // Perform any setup necessary in order to update the view. // データの更新があるならここでビューを更新しておく // 該当する値を返却する // If an error is encoutered, use NCUpdateResultFailed // If there's no update required, use NCUpdateResultNoData // If there's an update, use NCUpdateResultNewData completionHandler(NCUpdateResultNewData); }
このメソッド内でウィジェットの更新処理を行い、その結果を NSExtensionPointIdentifier
に渡します。
- NCUpdateResultFailed - データの更新処理に失敗した
- NCUpdateResultNoData - データが更新されていない
- NCUpdateResultNewData - データの更新処理に成功した
(データの更新がない場合、またはデータの更新に失敗した場合はスナップショットの更新をしない?)
4. 実行
アプリを起動し、通知センターを表示すると新しくウィジェットが追加されています。
Xcode 6 は 現在NDA下にある ため、実行結果のスクリーンショットの掲載は控えておきます。
ウィジェットからアプリを開く
URLスキームを使って特定のアプリを開くことができるようです。
NSString *urlStr = @"urlscheme://"; [[self extensionContext] openURL:[NSURL URLWithString:urlStr] completionHandler:nil];
ウィジェット↔アプリ間のデータ共有をどうするのか調査中です。
おそらくキーチェーンを使い、同じ Keychain Access Group 間でデータを共有するか、両者からアクセスできる場所にファイルを置き、App Group
機能を使って共有することになるんだと思います。
ウィジェットを非表示にする
アプリ側から 次のコードを実行することで、データが無いことを伝えます。こうすることでウィジェットが非表示になります。
NCWidgetController *widgetController = [NCWidgetController widgetController]; [widgetController setHasContent:YES forWidgetWithBundleIdentifier:@"Myapp.QiitaWidget.Widget"];