我們將會開發一隻很簡單的 iPhone + Watch App,你可以在iPhone App輸入簡訊然後顯示在Apple Watch上。從中理解如何利用NSUserDefaults
及 App Group 功能把iPhone app的資料分享至 Watch App。
新增一個單一畫面樣板的專案
事不宜遲,首先打開Xcode,選擇 Create a new Xcode project。點選 iOS > Application > Single View Application,然後按 Next。
專案名稱(Product Name)取名為WatchSimpleNote、組織名稱(Organization Name)與Organization Identifier(組織識別)請自行命名,並選擇Swift作為開發語言、Devices裝置為iPhone,Use Core Data的選項此範例不會使用到,無需勾選,之後按 Next 繼續。
設定App Groups
由於我們使用到NSUserDefaults
作為資料的存放方式,我們必須去設定App Groups的功能。選擇專案後,依照圖片所示選擇Targets > Capabilities > App Groups,將off啟動為on的狀態。啟動App Group是由於我們需要將iPhone app的資料分享至Apple Watch App。
之後,選擇你要使用的開發者帳號。
接著再空的列表中按下+
,來新增一個新的App Groups。App Groups需要有一組識別用的ID為group.
開頭,並且在後面加上跟Bundle Identifier相同的反向域名。
完成後,便可以看到我們剛剛所新增的group.com.appcoda.WatchSimpleNote
,勾選並使用他。
在Apple Developer網站中,也可以看到我們所新增的group.com.appcoda.WatchSimpleNote
。
為專案新增WatchKit App
選擇File > New > Target。在iOS中選擇Apple Watch > WatchKit App for watchOS 1。由於本範例不會使用到Notification的功能,我們不需要勾選Include Notification Scene,之後按Finish繼續。
接著如前面一般,我們也要為WatchKit App啟動App Groups的功能,注意這邊的Target跟先前步驟不同。
這邊我們可以看到先前建立的group.com.appcoda.WatchSimpleNote
,請勾選並使用他。
佈置我們的storyboard
現在終於開始設計Watch App 介面。 開啟Main.storyboard
,利用Xcode中所提供的元件庫,我們為手機介面建立了UILabel
、UITextField
、UIButton
三個元件。
稍微調整一下大小和擺放位置,並且加上一些顏色,在這邊我們將UILabel
元件拉大,並將行數調整為6行。接著再UITextField
元件中的Placeholder加上提示輸入字樣”type something here…”。最後,將三個元件選取後,按下右下方”Resolve Auto Layout Issues”裡的Add Missing Constraints。
處理完手機的部份後,我們開啟”WatchSimpleNote WatchKit 1 App”中的Interface.storyboard
,來佈置手錶中的介面。一樣利用Xcode所提供的元件庫,我們在手錶上建立了一個Label和一個Button。
自行加上喜歡的色彩後,將Label範圍拉大並且調整行數為6行。
將View和Controller建立關連
在ViewController.swift
中,建立三個介面與程式的關聯性 (包括兩個IBOutlet
及一個IBAction
):
@IBOutlet weak var label: UILabel!
@IBOutlet weak var textField: UITextField!
@IBAction func pressSubmit(sender: AnyObject) {
}
利用Assistant Editor模式建立IBOutlet
及IBAction
。只要按住control加滑鼠左鍵從Storyboard 中選取所需連結的元件並拖曳至ViewController.swift
,鬆開按鈕之後,你就可以建立相關的outlet或action。
接著開啟Interface.storyboard
,也為我們手錶介面中的元件建立連結,搭配的controller為WatchSimpleNote WatchKit 1 Extension中的InterfaceController.swift
。完成後,你會有一個IBOutlet及一個IBAction。
@IBOutlet var watchLabel: WKInterfaceLabel!
@IBAction func pressUpdate() {
}
實作NSUserDefaults
現在我們要依序建立需要的變數。利用NSUserDefaults
來存放我們的Note內容。依序我們先於ViewController.swift
中建立兩個常數,分別為:
groupID
– 存放我們的App Groups ID 為group.com.appcoda.WatchSimpleNote
defaults
– 使用NSUserDefaults
的方法去讀取我們所指定的group
將這些功能寫在按鈕觸發的動作之中,當我們按下送出按鈕時將觸發下列程式碼:
@IBAction func pressSubmit(sender: AnyObject) {
let groupID = "group.com.appcoda.WatchSimpleNote"
if let defaults = NSUserDefaults(suiteName: groupID) {
defaults.setValue(textField.text, forKey: "Note")
label.text = textField.text
}
}
當defaults
有讀取到對應的group時,我們透過defaults.setValue(textField.text, forKey: "Note")
將textField中的文字存入NSUserDefaults
中指定的group並且對應的Key為Note
,然後label.text = textField.text
會把我們所輸入的文字替換到Label上顯示。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var textField: UITextField!
@IBAction func pressSubmit(sender: AnyObject) {
let groupID = "group.com.appcoda.WatchSimpleNote"
if let defaults = NSUserDefaults(suiteName: groupID) {
defaults.setValue(textField.text, forKey: "Note")
label.text = textField.text
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
再來我們於InterfaceController.swift
實作讀取NSUserDefaults
的部份。一樣我們建立兩個常數分別為:
groupID
– 存放我們的App Groups ID 為group.com.appcoda.WatchSimpleNote
defaults
– 使用NSUserDefaults
的方法去讀取我們所指定的group
寫在按鈕的觸發中,當我們按下Update按鈕時,便會去讀取定的group,透過defaults?.stringForKey("Note")
去撈取相對應Key為Note
的資料,在利用watchLabel.setText()
的方法將內容替換到Label中。
在這邊defaults
後面的”?”是因為我們沒有使用跟先前if let ... {}
相同的做法,因此必須加上”?”。
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
@IBOutlet var watchLabel: WKInterfaceLabel!
@IBAction func pressUpdate() {
let groupID = "group.com.appcoda.WatchSimpleNote"
let defaults = NSUserDefaults(suiteName: groupID)
watchLabel.setText(defaults?.stringForKey("Note"))
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
}
現在是時候試試我們的Watch app。你可以選擇 WatchSimpleNote WatchKit 1 App
Scheme執行Watch app 程式。
運行起來試試看吧,你是不是也完成了一個簡易的Apple Watch App呢?試試在iPhone app輸入簡訊,然後按Watch app 的Update按鈕,你的簡訊就會在出現!
從這裡出發
能夠初步了解到WatchKit和iPhone之間的資料交換,也許你可以試著使用 CoreData 或是 SQLite 的方式去存放資料,更可以搭配WCSession
去做到更即時的資料交換唷!
供你參考,請從這裡下載本文的完整 Xcode 專案。別忘了更新專案裡面的 Bundle ID 及 App Groups ID。