概要
この記事では、2025年6月1日にリリース予定のiOSアプリ「Fuyomi」の開発過程で得られた、以下の技術的知見をまとめます:
- SwiftUIでPDFと画像を同一構造で扱う方法
- PencilKitでの描画内容をStorageに保存・同期する構造
- Firebase Authentication(匿名認証)+ Firestore/Storageの統合
- Core Hapticsによる振動付きメトロノームの実装
アプリ概要と実装方針
Fuyomiは、演奏者向けに以下の機能を1つに統合した音楽支援アプリです:
機能 | 実装技術 |
---|---|
メトロノーム | Core Haptics + Timer + 音/光連携 |
チューナー | AudioEngine + FFT(周波数解析) |
楽譜ノート(PDF/画像) | PDFKit + UIImageView + PencilKit |
自動スクロール | ScrollView + Timer or スライダー制御 |
クラウド同期 | Firebase Auth + Firestore + Storage |
PDF/画像+手書き描画の統合表示
背景
SwiftUIにおいてPDFKitはUIViewRepresentableを通じて使う必要がありますが、同一画面でPencilKitの描画も重ねたい場合、レイヤー構造とサイズ調整が煩雑になります。
解決アプローチ
- PDF/画像はどちらも CanvasView に共通処理を持たせる
- 表示用には ZStack を使い、背景(PDF/画像)と描画レイヤーを重ねる
- 描画領域のスケーリングとオフセットは、PDFのpage.bounds(for:)や画像のsizeから動的に計算
swift
ZStack {
if isPDF {
PDFPageView(page: pdfPage)
} else {
Image(uiImage: image)
.resizable()
.scaledToFit()
}
CanvasView(drawing: $drawing) // PencilKit
}
PencilKit描画とFirebase Storageの連携
保存処理(書き込み)
let drawingData = drawing.dataRepresentation()
let ref = storageRef.child("users/\(uid)/notes/\(noteId)/drawings/page_0.data")
ref.putData(drawingData, metadata: nil)
読み込み処理(復元)
ref.getData(maxSize: 5 * 1024 * 1024) { data, error in
if let data = data {
self.drawing = try? PKDrawing(data: data)
}
}
- PKDrawingはシリアライズ可能なDataとしてStorage保存が可能
- Firestoreではページごとのメタ情報(ページ数・ページ順など)を保存
Firebase匿名認証+Firestore構成
認証
Auth.auth().signInAnonymously { result, error in
// uidは result.user.uid
}
Firestoreドキュメント構造(例)
users/{uid}/notes/{noteId}
├── title: String
├── createdAt: Timestamp
├── pageCount: Int
メトロノームの振動制御(Core Haptics)
do {
let engine = CHHapticEngine()
try engine.start()
let event = CHHapticEvent(
eventType: .hapticTransient,
parameters: [.init(parameterID: .hapticIntensity, value: 1.0)],
relativeTime: 0
)
let pattern = try CHHapticPattern(events: [event], parameters: [])
let player = try engine.makePlayer(with: pattern)
try player.start(atTime: 0)
} catch {
print("Haptics Error: \(error)")
}
- 拍ごとに振動パターンを変更可能(1拍目は強く、それ以外は弱く等)
スクロール制御の失敗談と方針転換
当初、BPMに合わせた自動譜めくりをTimer制御で実装していましたが:
- スクロール速度とテンポの微妙なズレ
- 長時間演奏時の累積誤差
…といった問題から、BPM連動は廃止し、ユーザーが速度を調整できるスライダーUIに変更しました。
Dreamifyと今後の展望
このアプリは、非営利団体「Dreamify」のプロジェクトとして開発されました。
Dreamifyは、2025年6月中に非営利型一般社団法人として法人化予定で、今後も教育・音楽・災害支援などの分野でアプリ開発を行っていく予定です。
Fuyomiの今後の機能追加予定:
- MP3音源からの耳コピ機能(楽譜自動生成)
- AIによる演奏解析/自動テンポ制御
- アカウント機能と他端末共有
- Android / watchOS 対応
ご意見・Issue・Fork歓迎です!
本記事の内容やFuyomiに関する技術質問・提案は大歓迎です!
コメント欄で気軽にどうぞ!
リンク集
- App Storeリンク(リリース後に追記予定)
- Dreamify公式サイト:fuyomi.com
- Zenn / noteでも開発背景を公開中