自分用のiOSアプリづくり
概要

初めてiOSアプリを作り始めた。自分用のライフログ(になる予定の)アプリです。
作業の流れ
大筋では以下の様な流れで作った
- ClaudeCodeとコンセプトを考える
- アプリの名前を考える
- そのコンセプトをClaudeCodeに伝える
- システム構成について制約を伝える
- 仕様を決めて、Issueを切ってもらう
- /loopで作ってもらう(loopのブロックになるものを解消する
- 動作確認
github projectでboardを作っておいて、プロジェクトの全体は管理できるようにしておいた。
具体的な作業で印象的な部分
自分の実機だけで動くものを
まずは動く小さいものを作るというコンセプトで、ライフログを記録し、それを日記に貼り付けられるようクリップボードにコピーできるというものを作ることにしました。

こんな感じのもの。書き出す画面はこんな感じに。

画面では出てないけど、Siriをつかって登録できる機能もつけた。 ロック画面から入力できるようにした。

構成など
概要
| 項目 | 内容 |
|---|---|
| 目的 | 短いメモ(つぶやき)を記録し、1日のタイムラインとして振り返る |
| iOS | SwiftUI、iOS 18 以降、XcodeGen でプロジェクト生成 |
| サーバー | Rails 8.1(API モード)+ PostgreSQL 17、Ruby 4.0.1 |
| インフラ | VPS 1GB、Docker Compose、Caddy、GitHub Actions で自動デプロイ |
| 配布 | 無料の Apple アカウントで実機に直接インストール(TestFlight は未使用) |
| 規模 | PR 約40本、テスト Rails 31件・iOS 62件 |
設計方針
実装前にコンセプトを docs/designs/concept.md にまとめた。データ設計に影響したのは次の3点。
- 用途を先に決めない:入力時に分類やタグをつけず、本文・時刻・出どころだけを保存する。見せ方はあとから足す
- 時刻を3つ持つ:
occurred_at(やった時刻)、posted_at(つぶやいた時刻)、created_at(サーバーに届いた時刻)。一覧はoccurred_at順 - 入力コストを下げる:文字入力の手間を減らすことを優先する。Siri やコントロールセンターからの投稿もこの方針から
つぶやきは、本文と occurred_at だけ編集できる。posted_at・source・user_id は attr_readonly で固定し、削除は物理削除にした。マルチテナントを想定して、データはすべて current_user.posts 経由で扱う。
アプリ名はエーテルの一般式 R-O-R’ からとった。
開発フロー
タスクは GitHub Issue とプロジェクトボードで管理し、Claude Code のスキル /next-issue を /loop で繰り返し実行した。1周の中身は次のとおり。
backend/iosラベルの Issue から、依存が片付いているものを選ぶ- ブランチを切り、テストを先に書いて実装する(RSpec / Swift Testing)
- PR を作り、
/code-reviewでセルフレビューする - Codex の自動レビュー(最大10分)と CI を待ち、指摘を直す
- squash マージ。iOS は実機確認待ちとして
needs-device-checkをつける
iOS は CI を用意していない。macOS ランナーは無料枠の消費が大きいためだ。代わりに、ローカルの xcodebuild test と、シミュレーター+ローカルの Rails での動作確認で完了を判定した。
サーバー
- 認証:ユーザーごとの API トークン(Bearer)。DB には SHA256 のダイジェストだけを保存する
- API:
GET/POST /api/posts、PATCH/DELETE /api/posts/:id。occurred_from/occurred_toで期間を指定できる(最大1000件) - 他のユーザーのつぶやきは 404 を返す
- デプロイ:main にマージすると GitHub Actions が VPS に SSH し、
git pullしてdeploy.shを実行する。そのあと/upでヘルスチェックする
iOS
実機に入れるまで
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer(初期状態は Command Line Tools を向いていた)- Xcode → Settings → Accounts で Apple ID を登録し、Personal Team を使う
- Xcode の Devices and Simulators で iPhone をペアリングする(未ペアリングだと「unpaired」で実行できない)
- iPhone のデベロッパモードをオンにする(ペアリング後に設定項目が現れる)
- 初回起動時に、iPhone の「VPNとデバイス管理」で開発元を信頼する
無料アカウントで入れたアプリは7日で期限が切れる。Apple Developer Program(年額 12,800円)には、まだ入っていない。
構成
- XcodeGen で
project.ymlから.xcodeprojを生成する。エンタイトルメントはpropertiesに書かないと、空のファイルで上書きされる - ソースは機能ごとのフォルダに分けた(
App/Core/Compose/Timeline/Export/Settings/Intents) - シミュレーターは
#if targetEnvironment(simulator)でローカルの Rails(localhost:3010)につなぐ - トークンは Keychain に保存する
アプリを開かずに投稿する
App Intent「ROR につぶやく」を作り、App Shortcuts(Siri・ショートカット)と ControlWidget(コントロールセンター)から呼ぶ。@Parameter の requestValueDialog で本文を聞くので、アプリは開かない。
ControlWidget は別ターゲット(ウィジェット拡張)で動く。そのためトークンを Keychain Sharing(keychain-access-groups)で共有した。無料の Personal Team でも署名できた(プロビジョニングプロファイルは TEAMID.* を許可している)。App Groups は使っていない。
おわりに
本当に簡単なアプリですが、iPhoneアプリをずっと作ってみたかったのでわたしにとっては魔法。Swiftを一行も知らなくても一応動く物を作れてしまう時代になりました。安全面や構成などiOS開発者では目に余るところがあるかもしれませんが、そちらは追ってやっていきたい。一般的に公開する直前かなと思っている。