私事ですが、先日iPhone 6 Plusを買いました。

とっても満足しております。画面が大きいは正義だと思います。

そして新機能として巷で盛り上がっていたiOS8のAppExtensions、色々なアプリが実装していて便利だなと思いました。

ということで、今日はこのAppExtensionsをどうやって実装するのか気になったので、お決まりのHello Worldをしてみました。

ただ表示するだけじゃ面白くないので、NSUserDefaultsを使って、アプリ側で名前を入力してもらい、それを表示するものを作ってみました。

とっても簡単だったのでぜひ遊んでみてください。

ソースコード

ということで、実装側は特に難しいことをしていないのでソースコードだけ載せます。

アプリ側

ユーザーさんに操作してもらう側のViewControllerです。

ViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textFiled: UITextField!
let suiteName = "group.SampleShareName"
let nameKey = "name"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let sharedDefaults: NSUserDefaults = NSUserDefaults(suiteName: self.suiteName)
if let name = sharedDefaults.stringForKey(self.nameKey) {
NSLog("NSUserDefaults has string for key : %@", self.nameKey)
self.textFiled.text = name;
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func pushSaveName(sender: AnyObject) {
let name = self.textFiled.text
if (name == "") {
self.showAlertViewController()
return
}
let sharedDefaults:NSUserDefaults = NSUserDefaults(suiteName: "group.SampleShareName")
sharedDefaults.setObject(self.textFiled.text, forKey: "name")
sharedDefaults.synchronize()
NSLog("Completed Name value")
}
func showAlertViewController() {
let alertViewController = UIAlertController(title: "alert!", message: "Please enter a value in the TextField.", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "YES", style: UIAlertActionStyle.Default) {
action in NSLog("push YES Button")
}
alertViewController.addAction(okAction)
self.presentViewController(alertViewController, animated: true, completion: nil)
}
}

AppExtensions

こちらは表示する専用ですね。

TodayViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import UIKit
import NotificationCenter
class TodayViewController: UIViewController, NCWidgetProviding {
@IBOutlet weak var label: UILabel!
let suiteName = "group.SampleShareName"
let nameKey = "name"
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didChangeUserDefaults:", name: NSUserDefaultsDidChangeNotification, object: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view from its nib.
self.updateTextField()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
completionHandler(NCUpdateResult.NewData)
}
func didChangeUserDefaults(notification: NSNotification) {
self.updateTextField()
}
func updateTextField() {
let userDefaults: NSUserDefaults = NSUserDefaults(suiteName: self.suiteName)
if let name = userDefaults.stringForKey(self.nameKey) {
NSLog("NSUserDefaults has string for key : %@", self.nameKey)
self.label.text = "Hello \(name) !!!"
}
}
}

ソースコードの説明

簡単に説明すると

  1. ユーザーさんに名前を入力してもらい、ボタンを押してもらう
  2. @IBAction func pushSaveName(sender: AnyObject)が呼ばれ、NSUserDefaultsに保存する
  3. AppExtensionsが表示されるときにNSUserDefalutsに値があるかチェックし、値があったらlabelに値を表示する。

という流れです。

色々設定すること

複数設定しなければならないことがあります。

AppExtensionsのターゲットを生成するところから説明します。

targetにAppExtensionsを追加する

AppExtensionsを表示するためにtargetを追加しなければなりません。

ナビゲーションバーのFile -> New -> Targetを押してください。

以下の画面になると思います。

ScreenShot78

これでToday Extensionを選択して、必要な値を入力してください。

これでtargetの生成は完了です。

App Groupの設定

NSUserDefaultsをアプリ間で使うためにAppGroupというものを設定します。

これを設定すればNSUserDefaultsの他にCore Dataも共有することが出来ます。

詳しくは調べてみてください。

では設定方法を紹介します。

Projectファイルを選択 -> Capabilitiesを選択してください。

下の方にApp Groupsというものがあります。

ScreenShot79

ここに新たにGroupを追加します。

ちなみに色々試しましたが、アプリ名やBundle Identifierと同じ値はダメでしたので、違う値を設定してください。

問題がある場合はApp Groupsが赤く表示されます。

ここで設定できたらToday Extensiontargetでも同じように設定します。

ScreenShot80

そしてここの値(App Groupsで指定したGroup名)をNSUserDefaultsを生成するときに渡します。

1
2
let suiteName = "group.SampleShareName"
let userDefaults: NSUserDefaults = NSUserDefaults(suiteName: suiteName)

これで共通のNSUserDefaultsを使う事が出来ます。

Run時の設定

最初エラーが出て、動かせませんでした。

Edit Schemeを開いて、Run -> Executableをアプリのターゲットに設定してください。

僕の場合はこれで動きました。

ScreenShot81

アプリのスクリーンショット

これをすべて出来れば、こんな感じになります。

  • アプリ側

    ScreenShot82

  • App Extensions側

    ScreenShot83

こんな感じになりました。

終わりに

使っていくうちに気になる機能がありましたら、実装してみたいと思います。

以上になります。

参考

How to create iOS 8 Today extension and share data with containing app – tutorial

Swiftでウィジェットを作ってみた [iOS]