Apple Watch App 開発|watchOS 5でゼロから作成する手順とコツ
watchOS 5を使い、初めてのApple Watchアプリ開発に挑戦する方必見。基本から実践まで丁寧に解説し、スムーズに完成まで導く具体的な手順を紹介します。
本記事は AI による翻訳をもとに作成されています。表現が不自然な箇所がありましたら、ぜひコメントでお知らせください。
記事一覧
Apple Watchアプリを作ってみよう!(Swift)
watchOS 5 ハンズオンで学ぶ Apple Watch アプリ開発:ゼロから始める
[最新] Apple Watch Series 6 開封&2年間使用体験レビュー >>>クリックして移動
前書き:
前回のApple Watch 入手開箱文から約3ヶ月が経ち、最近ようやくApple Watchアプリの開発に取り組む機会ができました。
補足して3ヶ月使用した感想:
- e-sim(LTE)はまだ使うタイミングが思いつかず、申請も使用もしていません。
- よく使う機能:近づくだけでMacのロック解除、手を上げて通知確認、Apple Pay。
- 健康リマインダー:3ヶ月経ってだんだん怠けてきて、通知は見るものの、リング達成してもあまり感じません。
- サードパーティ製アプリの対応は依然として非常に悪いです。
- 時計の文字盤は気分に合わせて自由に変更でき、新鮮さが増します。
- より詳細な運動記録:例えば少し遠くまで夕食を買いに行くと、時計が自動で検知して運動記録を取るか尋ねてきます。
3ヶ月間使用した後、全体的には元の開封レビューに書かれている通り、まるで複数の生活の小さなアシスタントのように、細かい問題を解決してくれます。
サードパーティ製アプリの対応は依然として非常に悪い
Apple Watchアプリを実際に開発する前は、なぜApple Watchのアプリはどれも簡素で、使える程度にしかなっていないのか疑問でした。LINE(メッセージが同期されず、更新もされていない)、Messenger(使えるだけ)も含めてです。実際にApple Watchアプリを開発してみて、初めて開発者の苦労がわかりました…。
まずは、Apple Watchアプリの位置づけを理解し、シンプルにすること
Apple Watchの位置づけ 「iPhoneの代わりではなく、補助である」 公式の紹介や公式App、watchOSのAPIもこの方針に沿っています。そのため、サードパーティのAppはシンプルで機能が少ないと感じることがあります(すみません、欲張りすぎましたOrz)
以 我們的A アプリを例にすると、店舗検索、コラム閲覧、掲示板、オンライン問い合わせなどの機能があります。オンライン問い合わせは、リアルタイムかつ迅速な返信が必要なため、Apple Watchに移す価値のある項目です。迅速な返信は注文獲得のチャンスを高めます。一方、店舗検索、コラム閲覧、掲示板は比較的複雑な機能であり、腕時計の画面では表示できる情報が少なく、リアルタイム性も必要ないため、Apple Watchで実装してもあまり意味がありません。
核心のコンセプトは「補助を主とする」ため、すべての機能をApple Watchに移す必要はありません。そもそもユーザーが腕時計だけをつけてスマホを持っていない時間は非常に少なく、そのような場合でもユーザーのニーズは重要な機能だけに限られます(例えば、コラム記事の閲覧のように、すぐに腕時計で見る必要がないものは含まれません)。
さあ、始めましょう!
これも私にとって初めてのApple Watchアプリ開発なので、内容が十分に深くないかもしれません。どうぞご指導ください!!
本記事はiOSアプリ/UIKitの基礎知識がある開発者向けです
本記事で使用:iOS ≥ 9、watchOS ≥ 5
iOSプロジェクトにwatchOSターゲットを新規作成する:
File -> New -> Target -> watchOS -> WatchKit App
Apple Watch Appは単独でインストールできず、必ずiOS Appに依存します
新規作成後、ディレクトリはこのようになります:
二つのTarget項目があり、どちらも欠かせません:
WatchKit App: リソースとUI表示を担当
/Interface.storyboard:iOSと同様に、システムがデフォルトで作成したビューコントローラが含まれる
/Assets.xcassets:iOSと同様に、使用するリソースを格納
/info.plist:iOSと同様に、WatchKit Appに関する設定WatchKit Extension: プログラムの呼び出しとロジック処理を担当(*.swift)
/InterfaceController.swift:デフォルトのビューコントローラープログラム
/ExtensionDelegate.swift:SwiftのAppDelegateに類似し、Apple Watch Appの起動入口
/NotificationController.swift:Apple Watch App上のプッシュ通知表示を処理
/Assets.xcassets:ここでは使用せず、WatchKit AppのAssets.xcassetsに統一して配置
/info.plist:iOSと同様に、WatchKit Extensionの関連設定
/PushNotificationPayload.apns:プッシュ通知データで、シミュレーターでプッシュ通知機能のテストに使用可能
詳細は後ほど説明しますので、まずは目次とドキュメントの内容・機能をざっと把握してください。
ビューコントローラー:
Apple WatchではビューコントローラーはViewControllerではなくInterfaceControllerと呼ばれます。WatchKit App/Interface.storyboard内でInterface Controller Sceneを見つけることができ、その制御用のコードはWatchKit Extension/InterfaceController.swiftに配置されます(iOSと同じ概念です)。
SceneはデフォルトでNotification Controller Sceneと一緒に配置されます(私は少し上に移動して分けます)
右側でInterfaceControllerのタイトル表示テキストを設定できます。
タイトルの色はInterface Builder DocumentのGlobal hint設定を使用しており、アプリ全体のスタイルカラーが統一されます。
コンポーネントライブラリ:
複雑なコンポーネントはあまりなく、コンポーネントの機能もシンプルでわかりやすいです。
UI レイアウト:
万丈の高楼はViewから始まる。レイアウト部分はUIKit(iOS)のAuto Layoutや制約、レイヤーを使わず、すべてパラメータでレイアウト設定を行うため、よりシンプルで強力です(UIKitのUIStackViewに似ています)。
すべてのレイアウトはGroupで構成されており、UIKitのUIStackViewに似ていますが、より多くのレイアウトパラメータを設定できます
Groupのパラメータ設定
Layout:内包された子Viewのレイアウト方式を設定(水平、垂直、レイヤースタック)
Insets:Groupの上下左右の間隔を設定する
Spacing:内部に包まれた子View同士の間隔を設定する
Radius:Groupの角丸を設定します。そうです!WatchKitには角丸設定のパラメータが標準で備わっています。
Alignment/Horizontal:水平の配置方法(左、中央、右)を設定し、隣接するビューや外側のラップビューの設定と連動します
Alignment/Vertical:垂直方向の配置(上、中、下)を設定します。隣接するビューや外側のラップビューの設定と連動します。
Size/Width:Groupのサイズを設定します。3つのモードがあります。「Fixed:固定幅を指定」、「Size To Fit Content:子Viewのサイズに合わせて幅を決定」、「Relative to Container:親Viewのサイズを基準に幅を設定(%や+ -の補正値も設定可能)」
Size/Height:Size/Widthと同様に、高さを設定する項目です
フォント/フォントサイズの設定:
システムのText Stylesを直接適用するか、Customを使用できます(ただし、Customではフォントサイズを設定できませんでした)。そのため、私はSystemを使って 各表示ラベルのフォントサイズをカスタマイズしています。
実践で学ぶ:Lineのレイアウトを例に
排版部分はiOSほど複雑ではないので、サンプルを使って直接説明します。すぐに使い始められます。Lineのホーム画面のレイアウトを例にします:
WatchKit App/Interface.storyboardでInterface Controller Sceneを見つける:
- ページ全体は、iOSアプリ開発で使用するUITableViewに相当しますが、Apple Watchアプリでは操作が簡略化され、「WKInterfaceTable」と呼ばれています。
まずはInterface Controller SceneにTableをドラッグします。
UIKitのUITableViewと同様に、テーブル本体とセル(Apple WatchではRowと呼ばれます)があります。使い方は大幅に簡略化されており、このインターフェース上で直接セルのデザインやレイアウトが可能です!
- レイアウト構造の分析とRow表示スタイルの設計:
左側に角丸の全幅イメージを配置し、その上にラベルを重ねます。右側は上下に均等に分割された2つの領域を配置し、上部にラベル、下部にもラベルを配置します。
2–1: 左右二つのブロック構造を作成する
2つのGroupを1つのGroupにドラッグし、それぞれのSizeパラメータを設定します:
左側の緑色部分:
Layout設定でOverlapし、その中の子Viewに未読メッセージLabelのレイヤースタック表示を行う
幅と高さを40に固定した正方形を設定する
右側の赤い部分:
LayoutをVerticalに設定し、その中の子Viewを上下に2つ表示する
幅は外側を参照し、比率は100%、左側の緑部分40を差し引く。
左右コンテナ内のレイアウト:
左側部分:Imageをドラッグし、その後Labelを包むGroupをドラッグして右下に揃える(Groupに背景色を設定し、間隔と角丸を設定)
右側部分:Labelを2つ配置し、1つは左上揃え、もう1つは左下揃えに設定してください。
Rowに名前を付ける(UIKitのUITableViewでCellにidentifierを設定するのと同様):
Row->Identifier->カスタム名を入力
Rowの表示スタイルは一種類だけではありませんね?
非常に簡単で、Table内にRowをドラッグして配置し(実際に表示するRowのスタイルはプログラムで制御)、Identifierを入力して命名するだけです。
ここにデータがない場合のメッセージを表示するためのRowを追加します
レイアウトに関する情報
watchKitのhiddenはスペースを取らないため、インタラクティブな用途に使えます(ログインしていればTableを表示し、ログインしていなければ案内用のLabelを表示)。
レイアウトはここまでで一旦区切ります。個人のデザインに合わせて調整してください。操作は簡単なので、何度か繰り返し配置や整列パラメータを試して慣れましょう!
プログラム制御部分:
Rowに続いて、Rowを参照操作するためのクラスを作成する必要があります:
1
2
class ContactRow:NSObject {
}
1
2
3
4
5
6
7
8
class ContactRow:NSObject {
var id:String?
@IBOutlet var unReadGroup: WKInterfaceGroup! // 未読グループ
@IBOutlet var unReadLabel: WKInterfaceLabel! // 未読ラベル
@IBOutlet weak var imageView: WKInterfaceImage! // 画像ビュー
@IBOutlet weak var nameLabel: WKInterfaceLabel! // 名前ラベル
@IBOutlet weak var timeLabel: WKInterfaceLabel! // 時間ラベル
}
Outletを接続し、変数を保存する
Table部分も同様にOutletをControllerに接続します:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
class InterfaceController: WKInterfaceController {
@IBOutlet weak var Table: WKInterfaceTable!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// インターフェースオブジェクトをここで設定します。
}
override func willActivate() {
// このメソッドはウォッチのビューコントローラーがユーザーに表示される直前に呼ばれます
super.willActivate()
}
struct ContactStruct {
var name:String
var image:String
var time:String
}
func loadData() {
// APIコールバックを取得...
//postData {
let data:[ContactStruct] = [] // APIから返されたデータ...
self.Table.setNumberOfRows(data.count, withRowType: "ContactRow")
// 複数のROWを表示する場合は以下を使用:
//self.Table.setRowTypes(["ContactRow","ContactRow2","ContactRow3"])
//
for item in data.enumerated() {
if let row = self.Table.rowController(at: item.offset) as? ContactRow {
row.nameLabel.setText(item.element.name)
// ラベルや画像に値を割り当てる......
}
}
//}
}
override func didDeactivate() {
// このメソッドはウォッチのビューコントローラーが表示されなくなった時に呼ばれます
super.didDeactivate()
loadData()
}
// Row選択時の処理:
override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
guard let row = table.rowController(at: rowIndex) as? ContactRow,let id = row.id else {
return
}
self.pushController(withName: "showDetail", context: id)
}
}
Tableの操作は大幅に簡略化されており、delegateやdatasourceは不要です。データの設定はsetNumberOfRows/setRowTypesで行数と行の種類を指定し、rowController(at:)を使って各行のデータ内容を設定するだけです!
TableのRow選択イベントも override func table( _ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) を実装するだけで操作可能です!(Tableはこのイベントのみです)
ページ遷移の方法は?
まずはInterface ControllerにIdentifierを設定します
watchKitには2つのページ遷移モードがあります:
- iOS UIKitのpushに似ています
self.pushController(withName: Interface Controller Identifier , context: Any? )
push方式は左上に戻るボタンがあります
前のページに戻る(iOS UIKitと同様):self.pop()
ルートページに戻る:self.popToRootController()
新しいページを開く:self.presentController( )
- タブ表示方法 WKInterfaceController.reloadRootControllers(withNames: [ インターフェースコントローラ識別子 ], contexts: [ Any? ] )
またはStoryboard上で、最初のページのInterface ControllerからControlキーを押しながらクリックしてドラッグし、次のページに「next page」を選択することもできます。
タブ表示は左右にスワイプしてページを切り替えられます。
2つのページ遷移方法は混用できません。
ページ遷移のパラメータ?
iOSのようにカスタムdelegateやsegueでパラメータを渡す必要はなく、watchKitのページ遷移でパラメータを渡す場合は、上記メソッドの contexts にパラメータを入れるだけです。
接続パラメータは InterfaceController の awake(withContext context: Any?) で受け取る
例えば、AページからBページにid:Intを渡して遷移する場合:
Aページ:
1
self.pushController(withName: "showDetail", context: 100)
Bページ:
1
2
3
4
5
6
7
8
9
override func awake(withContext context: Any?) {
super.awake(withContext: context)
guard let id = context as? Int else {
print("パラメータエラー!")
self.popToRootController()
return
}
// インターフェースオブジェクトの設定をここで行う。
}
プログラム制御コンポーネント部分
iOS UIKitと比べてかなり簡素化されており、iOS開発経験があればすぐに慣れるでしょう!
例えば、labelはsetText()に変わります。
p.s. しかもgetTextメソッドがなく、extensionの変数を使うか外部変数に保存するしかありません。
iPhoneとの同期/データ転送
もしiOSの関連Extensionを開発したことがあれば、無意識にApp Groupsを使ってUserDefaultsを共有する方法を使うでしょう。私も最初はその方法でやってみて、ずっとデータが渡らなくて悩みましたが、調べてみるとwatchOS 2以降はこの方法がサポートされていないことが分かりました…。
新しいWatchConnectivity方式を使ってiPhoneとApple Watch間で通信を行う(ソケットのような概念)、iOS側とwatchOS側の両方で実装が必要です。以下はシングルトンパターンでの実装例です:
モバイル端末:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import WatchConnectivity
class WatchSessionManager: NSObject, WCSessionDelegate {
@available(iOS 9.3, *)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
// iPhone側のセッション起動完了
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
// iPhone側がWatchから送られたUserInfoを受信
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
// iPhone側がWatchからのMessageを受信
}
// 他にもdidReceiveMessageData,didReceiveFileがあり、いずれもWatchからのデータ受信を処理
// データの送受信ニーズに応じて使い分ける
func sendUserInfo() {
guard let validSession = self.validSession,validSession.isReachable else {
return
}
if userDefaultsTransfer?.isTransferring == true {
userDefaultsTransfer?.cancel()
}
var list:[String:Any] = [:]
// UserDefaultsの内容をlistに入れる....
self.userDefaultsTransfer = validSession.transferUserInfo(list)
}
func sessionReachabilityDidChange(_ session: WCSession) {
// Watchアプリの接続状態が変わったとき(Watchアプリ起動時/終了時)
sendUserInfo()
// 状態変化時にWatchアプリ起動ならUserDefaultsを同期
}
func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
// UserDefaultsの同期完了(transferUserInfo)
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
static let sharedManager = WatchSessionManager()
private override init() {
super.init()
}
private let session: WCSession? = WCSession.isSupported() ? WCSession.default : nil
private var validSession: WCSession? {
if let session = session, session.isPaired && session.isWatchAppInstalled {
return session
}
// 有効で接続中かつWatchアプリが起動中のセッションを返す
return nil
}
func startSession() {
session?.delegate = self
session?.activate()
}
}
WatchConnectivity iPhone側のコード
iOS/AppDelegate.swiftのapplication( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)内にWatchSessionManager.sharedManager.startSession()を追加し、スマホアプリ起動後にセッションを接続するようにします。
ウォッチ側:
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
import WatchConnectivity
class WatchSessionManager: NSObject, WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func sessionReachabilityDidChange(_ session: WCSession) {
guard session.isReachable else {
return
}
}
func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
DispatchQueue.main.async {
//UserDefaults:
//print(userInfo)
}
}
static let sharedManager = WatchSessionManager()
private override init() {
super.init()
}
private let session: WCSession? = WCSession.isSupported() ? WCSession.default : nil
func startSession() {
session?.delegate = self
session?.activate()
}
}
WatchConnectivity ウォッチ側のコード
そして、WatchOS Extension/ExtensionDelegate.swift の applicationDidFinishLaunching( ) 内に WatchSessionManager.sharedManager.startSession( ) を追加し、ウォッチアプリ起動後にセッションを接続します。
WatchConnectivity データ転送方法
データ送信:sendMessage, sendMessageData, transferUserInfo, transferFile
データ受信:didReceiveMessageData, didReceive, didReceiveMessage
両端の送受信メソッドは同じです
時計から携帯へのデータ送信は問題なくできますが、携帯から時計へのデータ送信は時計のアプリが開いている時に限られます。
watchOSプッシュ通知処理
プロジェクトディレクトリの下にあるPushNotificationPayload.apnsはここで役立ちます。これはシミュレーター上でプッシュ通知をテストするためのもので、シミュレーターにWatch Appターゲットをデプロイし、インストールしてアプリを起動すると、このファイルの内容を使ったプッシュ通知を受け取れます。これにより、開発者はプッシュ通知機能を簡単にテストできます。
PushNotificationPayload.apnsを変更/有効化/無効化するには、ターゲットを選択してからEdit Schemeを選んでください。
watchOS プッシュ通知の処理:
iOSと同様にUNUserNotificationCenterDelegateを実装し、watchOSでも同じメソッドをwatchOS Extension/ExtensionDelegate.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
41
import WatchKit
import UserNotifications
import WatchConnectivity
class ExtensionDelegate: NSObject, WKExtensionDelegate, UNUserNotificationCenterDelegate {
func applicationDidFinishLaunching() {
WatchSessionManager.sharedManager.startSession() //前述のWatchConnectivity接続開始
UNUserNotificationCenter.current().delegate = self //UNUserNotificationCenterのデリゲートを設定
// アプリケーションの最終初期化処理を行う
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.sound, .alert])
// iOSと同様に、アプリがフォアグラウンドの時でも通知を表示するための処理
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// 通知をタップした時
guard let info = response.notification.request.content.userInfo["aps"] as? NSDictionary,let alert = info["alert"] as? Dictionary<String,String>,let data = info["data"] as? Dictionary<String,String> else {
completionHandler()
return
}
// response.actionIdentifierでタップイベントのIdentifierを取得可能
// デフォルトのタップイベント:UNNotificationDefaultActionIdentifier
if alert["type"] == "new_ask") {
WKExtension.shared().rootInterfaceController?.pushController(withName: "showDetail", context: 100)
// 現在のroot interface controllerを取得し、pushする
} else {
// その他の処理....
//WKExtension.shared().rootInterfaceController?.presentController(withName: "", context: nil)
}
completionHandler()
}
}
ExtensionDelegate.swift
watchOS の通知表示は、以下の3種類に分かれます:
- static:デフォルトのプッシュ通知の表示方法
携帯のプッシュ通知と連動して、ここではiOS側でUNUserNotificationCenter.setNotificationCategoriesを実装し、通知の下にボタンを追加しています;Apple Watch側でもデフォルトで同様に表示されます。
dynamic:プッシュ通知の表示スタイルを動的に処理(内容の再構成、画像の表示)
interactive:watchOS 5以降でサポートされ、dynamicに加えてボタン操作にも対応
Interface.storyboardのStatic Notification Interface Controller Sceneでプッシュ通知の処理方法を設定可能です
staticは特に説明することはありません。デフォルトの表示方法を使います。ここではdynamicを紹介します。「Has Dynamic Interface」にチェックを入れると「Dynamic Interface」が表示され、ここでカスタムの通知表示方法をデザインできます(Buttonは使用できません):
私のカスタムプッシュ通知の表示デザイン
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import WatchKit
import Foundation
import UserNotifications
class NotificationController: WKUserNotificationInterfaceController {
@IBOutlet var imageView: WKInterfaceImage!
@IBOutlet var titleLabel: WKInterfaceLabel!
@IBOutlet var contentLabel: WKInterfaceLabel!
override init() {
// ここで変数を初期化します。
super.init()
self.setTitle("結婚吧") // 右上のタイトルを設定
// インターフェースオブジェクトをここで設定します。
}
override func willActivate() {
// このメソッドはウォッチのビューコントローラがユーザーに表示される直前に呼ばれます
super.willActivate()
}
override func didDeactivate() {
// このメソッドはウォッチのビューコントローラが表示されなくなった時に呼ばれます
super.didDeactivate()
}
override func didReceive(_ notification: UNNotification) {
if #available(watchOSApplicationExtension 5.0, *) {
self.notificationActions = []
// iOS側で実装したUNUserNotificationCenter.setNotificationCategoriesによる通知下部のボタンをクリア
}
guard let info = notification.request.content.userInfo["aps"] as? NSDictionary,let alert = info["alert"] as? Dictionary<String,String> else {
return
}
// プッシュ通知の情報
self.titleLabel.setText(alert["title"])
self.contentLabel.setText(alert["body"])
if #available(watchOSApplicationExtension 5.0, *) {
if alert["type"] == "new_msg" {
// 新しいメッセージ通知の場合、通知下に返信ボタンを追加
self.notificationActions = [UNNotificationAction(identifier: "replyAction",title: "返信", options: [.foreground])]
} else {
// その他の場合は閲覧ボタンを追加
self.notificationActions = [UNNotificationAction(identifier: "openAction",title: "閲覧", options: [.foreground])]
}
}
// このメソッドは通知を表示する必要があるときに呼ばれます。
// 動的通知インターフェースを使う場合に実装してください。
// 動的通知インターフェースをできるだけ速く設定してください。
}
}
プログラム部分も同様にアウトレットをコントローラーに接続し、機能を実装します。
次にinteractiveについて説明します。dynamicと同様ですが、Buttonを追加でき、dynamicと同じClassでプログラムを制御できます。私はinteractiveを使っていません。なぜなら、ボタンはプログラムでself.notificationActionsを使って追加しているからです。違いは以下の通りです:
左はinteractiveを使用し、右はself.notificationActionsを使用しています
両方の方法ともwatchOS 5以上が必要です。
self.notificationActionsでボタンを追加した場合、ボタンのイベント処理はExtensionDelegate内の userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) で行い、identifierでアクションを識別します。
メニュー機能?
コンポーネントライブラリからMenuをドラッグし、次にメニュー項目のMenu Itemをドラッグして、IBActionをコードに接続します。
ページを強く押すと以下が表示されます:
内容入力?
内蔵のpresentTextInputControllerメソッドを使うだけでOK!
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
@IBAction func replyBtnClick() {
guard let target = target else {
return
}
self.presentTextInputController(withSuggestions: ["後で返信します","ありがとうございます","ご連絡お待ちしております","はい","OK!"], allowedInputMode: WKTextInputMode.plain) { (results) in
guard let results = results else {
return
}
// 入力値がある場合
let txts = results.filter({ (txt) -> Bool in
if let txt = txt as? String, txt != "" {
return true
} else {
return false
}
}).map({ (txt) -> String in
return txt as? String ?? ""
})
// 入力の前処理
txts.forEach({ (txt) in
print(txt)
})
}
}
まとめ
ご覧いただきありがとうございます!お疲れ様です!
ここまでで記事は一段落です。UIレイアウト、プログラム、プッシュ通知、インターフェース応用について大まかに触れました。iOS開発経験があれば習得は非常に早く、ほぼ同じで多くの方法が簡略化されていて使いやすいですが、できることは確かに減っています(例えば、現時点ではTableの「もっと読み込む」機能の実装方法がわかっていません)。現状できることは少ないですが、今後公式がより多くのAPIを開発者に開放してくれることを期待しています❤️❤️❤️
MurMur:
Apple Watch App Target を手首のデバイスにデプロイするのは本当に遅い — Narcos
ご質問やご意見がありましたら、こちらからご連絡ください 。
Post は ZMediumToMarkdown によって Medium から変換されました。
本記事は Medium にて初公開されました(こちらからオリジナル版を確認)。ZMediumToMarkdown による自動変換・同期技術を使用しています。

































{:target="_blank"}](/assets/e85d77b05061/1*-J9qZ846ZysJEhMTSZeE3w.webp)