取り組みの背景
Apple Watch は世界で最も普及しているスマートウォッチであり、ヘルスケア・フィットネス・通知管理など日常的に使われるウェアラブルデバイスです。しかし、従来の watchOS アプリ開発は Xcode のセットアップ、WatchKit Extension の構成、iPhone アプリとの通信設計など、初中級者にとってハードルの高い作業が多く存在しました。
Rork Max を使えば、AI の力を借りて SwiftUI ベースの Apple Watch コンパニオンアプリを効率的に構築できます。ここではRork Max での watchOS アプリ開発の基本から、iPhone アプリとの連携、HealthKit データの活用、そしてコンプリケーション(文字盤ウィジェット)の実装までを順を追って解説します。
この記事の対象読者:
- Rork でアプリ開発の基礎を学んだ方
- Apple Watch 向けにアプリを拡張したい方
- ウェアラブルデバイス対応で差別化を図りたい個人開発者
Rork Max の基本的な使い方については、Rork Max ネイティブ Swift 完全ガイドで詳しく解説していますので、あわせてご覧ください。
watchOS アプリの基本構造を理解する
Apple Watch アプリは、大きく分けて2つのアーキテクチャで構成されます。
独立型アプリ(Independent App): Apple Watch 単体で動作するアプリです。iPhone がなくても基本機能が使えます。watchOS 6 以降で対応しており、App Store for Apple Watch から直接ダウンロードできます。
コンパニオンアプリ(Companion App): iPhone アプリと連携して動作する Watch アプリです。データの同期やリモート操作など、双方向の通信が特徴です。多くの商用アプリがこの形式を採用しています。
Rork Max ではどちらの形式にも対応していますが、ここでは最も実用性の高い「iPhone アプリ + Watch コンパニオンアプリ」の構成を解説します。
watchOS プロジェクトのディレクトリ構成
Rork Max で watchOS ターゲットを追加すると、以下のような構成が自動生成されます。
MyApp/
├── MyApp/ # iPhone アプリ本体
│ ├── ContentView.swift
│ └── MyAppApp.swift
├── MyAppWatch/ # Watch アプリ
│ ├── MyAppWatchApp.swift # Watch アプリのエントリポイント
│ ├── ContentView.swift # Watch のメイン画面
│ ├── ComplicationController.swift
│ └── Assets.xcassets
└── Shared/ # iPhone・Watch 共通コード
├── Models/
└── Services/
この構造を理解しておくと、Rork Max に対する指示がより的確になり、生成されるコードの質も向上します。
Rork Max で watchOS プロジェクトを作成する
ステップ1: プロジェクトの初期化
Rork Max でプロジェクトを新規作成し、watchOS ターゲットを含める指示を出します。
// Rork Max プロンプト例:
// 「iPhoneアプリとApple Watch コンパニオンアプリを持つプロジェクトを作成してください。
// Watch側にはタスクリスト表示と完了トグル機能を実装してください。」
// 生成される Watch アプリのエントリポイント
import SwiftUI
@main
struct MyAppWatchApp: App {
var body: some Scene {
WindowGroup {
TaskListView()
}
}
}ステップ2: Watch 用 UI を SwiftUI で構築する
watchOS の UI は SwiftUI をベースに構築します。画面サイズが小さいため、情報の優先順位付けが重要です。
// TaskListView.swift — Watch 側のタスク一覧画面
import SwiftUI
struct TaskListView: View {
@StateObject private var viewModel = TaskViewModel()
var body: some View {
NavigationStack {
List {
ForEach(viewModel.tasks) { task in
TaskRow(task: task) {
viewModel.toggleComplete(task)
}
}
}
.navigationTitle("タスク")
}
.onAppear {
viewModel.fetchTasks()
}
}
}
struct TaskRow: View {
let task: TaskItem
let onToggle: () -> Void
var body: some View {
Button(action: onToggle) {
HStack {
Image(systemName: task.isCompleted
? "checkmark.circle.fill"
: "circle")
.foregroundColor(task.isCompleted ? .green : .gray)
Text(task.title)
.strikethrough(task.isCompleted)
.lineLimit(2)
}
}
}
}
// 期待される出力:
// Apple Watch 上にタスク一覧が表示され、
// タップで完了/未完了を切り替えられるリストが表示されるWatch UI を設計する際のポイントは、タップターゲットを十分な大きさに保つことと、一画面に表示する情報量を絞ることです。
iPhone と Apple Watch のデータ連携を実装する
コンパニオンアプリの最大の魅力は、iPhone との双方向データ同期です。Apple は WCSession(Watch Connectivity)フレームワークを提供しており、これを使ってリアルタイムのメッセージ交換やバックグラウンドでのデータ転送が可能です。
WCSession によるリアルタイム通信
// Shared/Services/WatchConnectivityManager.swift
import WatchConnectivity
class WatchConnectivityManager: NSObject, ObservableObject, WCSessionDelegate {
static let shared = WatchConnectivityManager()
@Published var receivedTasks: [TaskItem] = []
private override init() {
super.init()
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}
// iPhone → Watch へタスクを送信
func sendTasks(_ tasks: [TaskItem]) {
guard WCSession.default.isReachable else { return }
let data = tasks.map { [
"id": $0.id.uuidString,
"title": $0.title,
"isCompleted": $0.isCompleted
] as [String: Any] }
WCSession.default.sendMessage(
["tasks": data],
replyHandler: nil
) { error in
print("送信エラー: \(error.localizedDescription)")
}
}
// 受信ハンドラ
func session(
_ session: WCSession,
didReceiveMessage message: [String: Any]
) {
if let tasksData = message["tasks"] as? [[String: Any]] {
DispatchQueue.main.async {
self.receivedTasks = tasksData.compactMap {
TaskItem(from: $0)
}
}
}
}
// 必須デリゲートメソッド
func session(
_ session: WCSession,
activationDidCompleteWith state: WCSessionActivationState,
error: Error?
) {}
#if os(iOS)
func sessionDidBecomeInactive(_ session: WCSession) {}
func sessionDidDeactivate(_ session: WCSession) {
WCSession.default.activate()
}
#endif
}
// 期待される出力:
// iPhone でタスクを追加・更新すると、Watch 側にリアルタイムで反映される
// Watch でタスクを完了にすると、iPhone 側にも同期されるApplication Context による永続化
sendMessage はリアルタイム通信に適していますが、Watch が非アクティブな場合にはメッセージが届きません。updateApplicationContext を使うと、最新のデータが永続化され、Watch が起動した際に最新の状態を取得できます。
// バックグラウンド対応のデータ同期
func syncTasksInBackground(_ tasks: [TaskItem]) {
let context: [String: Any] = [
"tasks": tasks.map { $0.toDictionary() },
"lastUpdated": Date().timeIntervalSince1970
]
do {
try WCSession.default.updateApplicationContext(context)
} catch {
print("Context更新エラー: \(error.localizedDescription)")
}
}
// Watch 側で受信
func session(
_ session: WCSession,
didReceiveApplicationContext context: [String: Any]
) {
if let tasksData = context["tasks"] as? [[String: Any]] {
DispatchQueue.main.async {
self.receivedTasks = tasksData.compactMap {
TaskItem(from: $0)
}
}
}
}HealthKit データを Watch アプリに統合する
Apple Watch の最大の強みの一つが、リアルタイムのヘルスケアデータへのアクセスです。HealthKit を統合することで、心拍数、歩数、ワークアウトデータなどを活用したアプリが構築できます。
// Shared/Services/HealthKitManager.swift
import HealthKit
class HealthKitManager: ObservableObject {
private let healthStore = HKHealthStore()
@Published var todaySteps: Int = 0
@Published var currentHeartRate: Double = 0
// HealthKit 利用許可をリクエスト
func requestAuthorization() async throws {
let typesToRead: Set<HKObjectType> = [
HKQuantityType(.stepCount),
HKQuantityType(.heartRate),
HKQuantityType(.activeEnergyBurned)
]
try await healthStore.requestAuthorization(
toShare: [],
read: typesToRead
)
}
// 今日の歩数を取得
func fetchTodaySteps() async {
let stepsType = HKQuantityType(.stepCount)
let startOfDay = Calendar.current.startOfDay(for: Date())
let predicate = HKQuery.predicateForSamples(
withStart: startOfDay,
end: Date(),
options: .strictStartDate
)
let descriptor = HKStatisticsQueryDescriptor(
predicate: .init(
quantityType: stepsType,
predicate: predicate
),
options: .cumulativeSum
)
do {
let result = try await descriptor.result(for: healthStore)
let steps = result?.sumQuantity()?
.doubleValue(for: .count()) ?? 0
await MainActor.run {
self.todaySteps = Int(steps)
}
} catch {
print("歩数取得エラー: \(error.localizedDescription)")
}
}
}
// 期待される出力:
// Watch アプリ上に「今日の歩数: 8,432歩」のように表示されるHealthKit を使ったアプリは App Store 審査でプライバシーポリシーの明示が求められます。審査対策について詳しく知りたい方は、Rork アプリの App Store 審査完全攻略ガイドが参考になります。
コンプリケーション(文字盤ウィジェット)を実装する
コンプリケーションは Apple Watch の文字盤に小さなウィジェットを配置する機能です。ユーザーがアプリを開かなくても一目で情報を確認できるため、エンゲージメント向上に大きく貢献します。
// ComplicationProvider.swift
import WidgetKit
import SwiftUI
struct TaskComplicationEntry: TimelineEntry {
let date: Date
let remainingTasks: Int
let nextTask: String?
}
struct TaskComplicationProvider: TimelineProvider {
func placeholder(in context: Context) -> TaskComplicationEntry {
TaskComplicationEntry(
date: Date(),
remainingTasks: 3,
nextTask: "サンプルタスク"
)
}
func getSnapshot(
in context: Context,
completion: @escaping (TaskComplicationEntry) -> Void
) {
let entry = TaskComplicationEntry(
date: Date(),
remainingTasks: 5,
nextTask: "企画書を提出"
)
completion(entry)
}
func getTimeline(
in context: Context,
completion: @escaping (Timeline<TaskComplicationEntry>) -> Void
) {
// 実際のタスクデータを取得してタイムラインを構築
let tasks = TaskStorage.shared.incompleteTasks
let entry = TaskComplicationEntry(
date: Date(),
remainingTasks: tasks.count,
nextTask: tasks.first?.title
)
let nextUpdate = Calendar.current.date(
byAdding: .minute, value: 30, to: Date()
)!
let timeline = Timeline(
entries: [entry],
policy: .after(nextUpdate)
)
completion(timeline)
}
}
// コンプリケーションの表示 UI
struct TaskComplicationView: View {
let entry: TaskComplicationEntry
var body: some View {
VStack(alignment: .leading) {
Text("\(entry.remainingTasks)")
.font(.title2)
.fontWeight(.bold)
Text("残タスク")
.font(.caption2)
.foregroundColor(.secondary)
}
.containerBackground(.fill.tertiary, for: .widget)
}
}
// 期待される出力:
// 文字盤上に「5 残タスク」のようなコンプリケーションが表示されるまとめ
Rork Max を使った Apple Watch コンパニオンアプリ開発のポイントをまとめます。
- watchOS アプリの基本構成: iPhone アプリ + Watch ターゲット + Shared コードの3層構造で設計する
- SwiftUI ベースの Watch UI: 小さな画面に最適化したシンプルなインターフェースを心がける
- WCSession によるデータ連携: リアルタイム通信には
sendMessage、永続化にはupdateApplicationContextを使い分ける - HealthKit 統合: 歩数・心拍数・ワークアウトデータを活用してアプリの価値を高める
- コンプリケーション: 文字盤ウィジェットでユーザーの日常にアプリを溶け込ませる
Apple Watch アプリ対応は、App Store での差別化要因として非常に有効です。多くの個人開発者がまだ watchOS に進出していない今こそ、Rork Max の AI コード生成を活かして素早く市場に参入するチャンスです。
Watch アプリをストアに公開する際の具体的な手順については、Rork Max の2クリック App Store 公開完全解説で詳しく解説しています。