Android Studio で Swift / iOS アプリを開発するノート
Xcode を直接立ち上げず、Android Studio(IntelliJ ベース)+ CLI で iPhone / iPad アプリを作る運用のまとめ。シミュレータのタップ自動化や Lint など周辺ツールも含む。
目次
1. 全体構成
┌─ Android Studio (エディタ) ─────────┐
│ ├─ Swift コードの編集 │
│ ├─ Run/Debug Configurations から │
│ │ 外部スクリプト経由でビルド・起動 │
│ └─ ターミナル(make / scripts) │
└──────────────────────────────────┘
│
▼
┌─ CLI ツール群 ──────────────────────┐
│ xcodebuild → iOS Simulator ビルド │
│ simctl → Simulator 起動・操作 │
│ idb → タップ自動化 │
└──────────────────────────────────┘
│
▼
┌─ iOS Simulator ──────────────────┐
│ アプリの起動・操作・SS 撮影が可能 │
└────────────────────────────────┘
ポイント: Android Studio 自体は Swift をネイティブビルドできない。Xcode CLI(xcodebuild)に投げる Run Configuration を作るのが肝。
2. 初回セットアップ
2.1. 必要ツール
# Xcode CLI
xcode-select --install
xcodebuild -version
# Homebrew でツール群(jq は idb の出力パースに使う)
brew install jq
# fb-idb は Python 3.14 で動かないので 3.11 系に固定して pipx で入れる(後述)
brew install python@3.11 pipx
pipx install --python python3.11 fb-idb
2.2. Android Studio 側
Run Configuration(外部スクリプト実行)
Run/Debug Configurations → + → Shell Script を選択し、Script path にビルド/実行スクリプトのパスを指定する。
| 構成名(例) | 中身 |
|---|---|
| Run (iPhone) | xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' build + Simulator 起動 |
| Run (iPad) | iPad 向け destination でビルド |
| Build only | ビルドのみ |
| Screenshot | xcrun simctl io booted screenshot 等 |
Swift プラグイン: AppCode は撤退済み。IntelliJ の Swift サポートは限定的なので、コード補完は割り切って cmd-click での定義ジャンプと grep / Find in Files に頼る。本格的に補完が必要なときだけ Xcode を別途開く(open *.xcodeproj)。
3. ビルド & 実行
# 基本形
xcodebuild \
-project YourApp.xcodeproj \
-scheme YourApp \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
-quiet build
ログを抑制したいので -quiet を付けるのがコツ。エラーだけ出る。
Makefile でラップしておくと便利:
PROJECT := YourApp.xcodeproj
SCHEME := YourApp
DEVICE_NAME ?= iPhone 17 Pro
DEST := platform=iOS Simulator,name=$(DEVICE_NAME)
build:
xcodebuild -project $(PROJECT) -scheme $(SCHEME) \
-destination '$(DEST)' -quiet build
run: build
xcrun simctl boot '$(DEVICE_NAME)' 2>/dev/null || true
open -a Simulator
xcrun simctl install booted $(BUILT_APP_PATH)
xcrun simctl launch booted $(BUNDLE_ID)
test:
xcodebuild -project $(PROJECT) -scheme $(SCHEME) \
-destination '$(DEST)' -quiet test
clean:
xcodebuild -project $(PROJECT) -scheme $(SCHEME) clean -quiet
install-hooks:
./scripts/install_hooks.sh
$(BUILT_APP_PATH) と $(BUNDLE_ID) は xcodebuild -showBuildSettings から取得するか、別シェルスクリプトに切り出すと安定する。
4. シミュレータ操作の自動化
4.1. タップ自動化(idb 経由)
idb_companion をバックグラウンド起動 → idb connect で接続済みなら、シミュレータがフォーカスにあるかどうかに関わらず操作できる。
準備(セッションごと)
idb_companion は永続化されないため、Mac を再起動するか companion が落ちたら再度起動が必要。~/.zshrc から自動起動するスクリプトを噛ませると楽(§8 参照)。
# 起動中の Simulator UDID を取得
UDID=$(xcrun simctl list devices booted -j \
| jq -r '.devices | to_entries[] | .value[] | select(.state=="Booted") | .udid' \
| head -1)
# companion をバックグラウンド起動 → 起動ログから grpc_port を取得
idb_companion --udid "$UDID" > /tmp/idb_companion.log 2>&1 &
sleep 1
PORT=$(jq -r '.grpc_swift_port // .grpc_port' /tmp/idb_companion.log | head -1)
# クライアント側で接続
idb connect localhost "$PORT"
使い方
# 座標タップ(points)
idb ui tap 200 400
# AXLabel から要素の frame を取得(中央座標を計算して tap に渡す)
idb ui describe-all \
| jq -r '.[] | select(.AXLabel=="開始") | "\(.frame.x + .frame.width/2) \(.frame.y + .frame.height/2)"' \
| xargs idb ui tap
ハマりどころ
RuntimeError: There is no current event loop→ fb-idb が Python 3.14 で動かない。Python 3.11 で再インストール- companion は落ちることがある →
pgrep idb_companionで確認、落ちていたら再起動・再接続 - フォーカスが Simulator から外れていても OK(Companion が gRPC で操作するため)
4.2. スクリーンショット
DIR=tmp/ss/$(date +%Y%m%d)
mkdir -p "$DIR"
xcrun simctl io booted screenshot "$DIR/ss_$(date +%H%M%S).png"
時分秒入りファイル名でディレクトリ分けして保存しておくと、後で見直しやすい。mkdir -p を忘れると simctl io ... screenshot はサイレントに失敗するので注意。
5. Lint / フォーマッタ
5.1. SwiftLint
brew install swiftlint
swiftlint # プロジェクトルートで実行
swiftlint --fix # 自動修正可能なものを修正
swiftlint --path Sources/ # 特定パス
設定ファイル .swiftlint.yml の例
identifier_name:
min_length:
warning: 1 # 1文字変数を許容(i, q, c 等のループ変数)
max_length:
warning: 60
excluded:
- id
line_length:
warning: 200
error: 300
ignores_comments: true
ignores_urls: true
ignores_interpolated_strings: true
function_body_length:
warning: 100
error: 150
file_length:
warning: 700
error: 1200
disabled_rules:
- todo # TODO コメントは開発中に有用
excluded:
- SomeTests
- SomeUITests
5.2. SwiftFormat(任意)
.swiftformat を導入すれば自動整形できるが、SwiftLint の --fix でも大半は足りる。チームで強制ルールが要るとき以外は SwiftLint だけで十分。
6. Git pre-commit hook の運用
ステージされた特定ファイルだけを検証する pre-commit パターン。
scripts/hooks/pre-commit の例
#!/bin/bash
set -e
ROOT="$(git rev-parse --show-toplevel)"
# 対象ファイルの抽出(例: Swift ファイルのみ)
STAGED=$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.swift$' || true)
[ -z "$STAGED" ] && exit 0
# SwiftLint があれば実行
if command -v swiftlint > /dev/null; then
echo "[pre-commit] Running SwiftLint on staged files..."
while IFS= read -r f; do
swiftlint lint --quiet --path "$ROOT/$f" || exit 1
done <<< "$STAGED"
fi
インストーラ scripts/install_hooks.sh
#!/bin/bash
set -e
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
HOOKS="$ROOT/.git/hooks"
SOURCE="$ROOT/scripts/hooks/pre-commit"
# 既存があればバックアップ
if [ -f "$HOOKS/pre-commit" ] && [ ! -L "$HOOKS/pre-commit" ]; then
mv "$HOOKS/pre-commit" "$HOOKS/pre-commit.backup.$(date +%Y%m%d_%H%M%S)"
fi
# シンボリックリンクで設置(リポジトリ更新に追従)
ln -sf "../../scripts/hooks/pre-commit" "$HOOKS/pre-commit"
chmod +x "$SOURCE"
echo "Installed pre-commit hook"
make install-hooks で叩けるようにしておくと、新規 clone 後すぐ導入できる。
回避(非推奨): git commit --no-verify
コツ
- リポジトリ管理されたスクリプトをシンボリックリンクで
.git/hooks/に配置すると、リポジトリ更新時に自動追従する(.git/hooks/自体は git 管理外なので) - 重い検証(ビルド・全ファイル lint 等)は CI に寄せ、pre-commit はステージ済みファイルだけに絞る
git config <project>.strict trueのような オプトインフラグ を読むようにすると、厳格モードを必要に応じて切替可能
7. 典型ワークフロー
# 1. ブランチ作成・コード編集(Android Studio)
# 2. ローカル lint
swiftlint --fix
swiftlint # warning/error が 0 か確認
# 3. ビルド
make build # まずビルドが通るか確認
make run # Simulator で起動
# 4. UI 動作確認(手動 or idb)
idb ui tap 200 400
xcrun simctl io booted screenshot tmp/ss/$(date +%Y%m%d)/...
# 5. テスト
make test
# 6. コミット(pre-commit が走る)
git add <files>
git commit -m "..."
8. ハマりどころメモ
- xcodebuild の destination が長い: シェル変数化して使い回す
export DEST='platform=iOS Simulator,name=iPhone 17 Pro' - destination にカッコが入る場合:
'platform=iOS Simulator,name=iPad Pro 13-inch (M5)'のようにシングルクォートで囲む - Simulator のブートが残る:
xcrun simctl shutdown allでリセット - ビルドキャッシュが壊れる:
make clean→make build - idb companion が頻繁に落ちる: シェル起動時に再起動するスクリプトを
~/.zshrcに登録すると楽 - fb-idb は Python 3.14 NG: 必ず 3.11 系で
pipx - 複数 Simulator が起動している:
simctl list devices bootedで確認、必要ならsimctl shutdown <UDID>
9. 補足: なぜ Android Studio?
- 普段 Android / Kotlin で IntelliJ 系を使っているなら、キーバインドや UI 操作がそのまま流用できる
- Xcode の Source Editor は VCS 連携や Git Hook 周りが弱い。IntelliJ 系の方が快適
- ただし Storyboard / Asset Catalog の編集、Provisioning / Signing、Instruments プロファイラ は Xcode が必要 → 適宜切替
- Swift コード補完は弱いので、深い IDE サポートが要るなら Xcode 併用が現実的