wol-light プロジェクトまとめ(Windows 10 / VS Code / Claude Code + Sonnet 4.6)
概要
Fing の WoL機能を代替する Android アプリ。
Kotlin + Jetpack Compose で実装。
- 場所:
D:\AI\Claude\maybe_public\wol-light - 種別: maybe_public(将来公開候補)
実装機能
| # | 機能 | 状態 |
|---|---|---|
| ① | LAN スキャン(IP取得) | ✅ 実装済み |
| ② | デバイス一覧・選択・登録 | ✅ 実装済み |
| ③ | WoL 送信(Magic Packet) | ✅ 実装済み・動作未確認 |
| ④ | Ping 送信(1秒間隔・10回) | ✅ 実装済み・動作確認済み |
| ⑤ | on/off 表示(起動時自動確認) | ✅ 実装済み・動作確認済み |
| ⑥ | デバイス削除 | ✅ 実装済み |
| ⑦ | ホスト名取得(NetBIOS + mDNS) | ⚠️ 実装済み・効果なし(後述) |
技術スタック
| 項目 | 選定 |
|---|---|
| 言語 | Kotlin |
| UI | Jetpack Compose |
| 非同期 | Coroutines + Flow |
| DI | Hilt |
| DB | Room |
| 最小SDK | API 26 (Android 8.0) |
| ターゲットSDK | API 34 (Android 14) |
実装ステップ履歴
ステップ1: Gradle設定・Hilt初期化
gradle/libs.versions.tomlにHilt/Room/Navigation/ViewModelを追加build.gradle.kts・app/build.gradle.ktsにプラグイン・依存関係を追加WolLightApplication.ktを新規作成(@HiltAndroidApp)AndroidManifest.xmlにパーミッション4件を追加
技術的負債:gradle.properties に android.builtInKotlin=false / android.newDsl=false を追加(AGP 9.x の kapt 制限の workaround)。AGP 10.0 で削除される deprecated な設定のため、将来 kapt → KSP への移行が必要。
ステップ2: Device モデル・Room DB・DAO
model/Device.ktドメインモデルdata/db/DeviceEntity.ktRoom エンティティdata/db/DeviceDao.ktDAO(getAll/insert/update/delete)data/db/AppDatabase.ktRoomDatabasedata/repository/DeviceRepository.ktRepository(Entity↔Domain変換)di/AppModule.ktHilt モジュール
ステップ3: WolSender + WolUseCase
network/WolSender.ktMagic Packet生成・UDPブロードキャスト・MACバリデーションdomain/usecase/WolUseCase.kt
Magic Packet仕様:0xFF × 6バイト + MACアドレス × 16回 = 計102バイト
UDP ブロードキャスト(宛先: 255.255.255.255、ポート: 9)
ステップ4: PingSender + PingUseCase
network/PingSender.kt(PingResult・isReachable・応答時間計測)domain/usecase/PingUseCase.kt
ステップ5: IpScanner + ArpResolver + LanScanUseCase
network/IpScanner.kt(API31+/30以下分岐・254並列スキャン)network/ArpResolver.kt(ARPテーブル取得・MAC抽出・失敗時空文字)domain/usecase/LanScanUseCase.kt(LanScanState sealed class・channelFlowで進捗と結果を配信)
ステップ6: UI 3画面
DeviceListScreen + DeviceListViewModel
- 登録済みデバイスをリスト表示
- タップ → DeviceDetailScreen へ遷移
- 長押し → 削除確認ダイアログ
- スキャンボタン → ScanScreen へ遷移
ScanScreen + ScanViewModel
- スキャン開始/中断ボタン
- LinearProgressIndicator(0〜254の進捗)
- 結果リスト・デバイス名入力ダイアログ・登録機能
DeviceDetailScreen + DeviceDetailViewModel
- デバイス情報カード
- WoL送信ボタン(結果をSnackbarで表示)
- Pingボタン(ローディング中無効)
- 編集ダイアログ(名前・MAC・ブロードキャストアドレス・ポート)
- Ping結果リアルタイム表示・集計
ステップ7: Navigation接続
ui/navigation/AppNavigation.kt(NavHostで3画面接続)MainActivity.kt(@AndroidEntryPoint追加・AppNavigation接続)
ステップA〜C: 機能追加
追加内容:
- ホスト名取得(canonicalHostName、取得不可時はIPアドレスを使用)
DeviceモデルにisOnlineフラグ追加(DB保存なし)- 起動時に登録済み全デバイスへ並列Pingを実行しon/off表示
- PingSender を1秒間隔・10回送信の
Flow<PingResult>に変更 - DeviceDetailScreen にPing結果リアルタイム表示・集計を追加
ステップD: ホスト名取得改善(NetBIOS + mDNS)
実装内容:
network/NetBiosResolver.kt(UDP 137番ポート・Node Status Request・タイムアウト500ms)network/MdnsResolver.kt(MulticastLock・PTRクエリ・.localホスト名抽出・タイムアウト500ms)network/IpScanner.kt修正(NetBIOS + mDNS を並列実行・先着採用)
結果: 効果なし(後述)
ホスト名取得の調査結果
問題
InetAddress.getByAddress(ip).canonicalHostName は逆引きDNSに依存しており、家庭内LANでは機能しない。
Claude Code / Codex レビュー結果(共通の推奨)
| 優先度 | 手段 | 対象デバイス | 難易度 |
|---|---|---|---|
| 1 | NetBIOS NBNS | Windows PC・NAS | 低〜中 |
| 2 | mDNS PTR | Apple・IoT・Linux | 中 |
| 3 | 逆引きDNS | 企業LAN・一部ルーター | 低 |
調査結果
| 手段 | 結果 | 理由 |
|---|---|---|
| NetBIOS NBNS | ❌ 機能しない | Windows 10/11でNetBIOSが無効・廃止 |
| mDNS PTR | ❌ 機能しない | Bonjour未インストール・mDNSサービスなし |
| 逆引きDNS | ❌ 機能しない | 家庭内LANに逆引きDNSサーバーなし |
Fingがホスト名を取得できる理由(推定)
最も可能性が高いのはルーターのDHCPテーブル参照。
DHCPリストにはホスト名が含まれており、Fingはルーターにアクセスして取得していると思われる。ただしルーターごとにAPIが異なり実装が複雑なため、今回は見送り。
現在の方針
手動入力で割り切る。
スキャン結果にIPアドレスを表示し、登録時にユーザーが任意の名前を付ける。当面使ってみて改善が必要か判断する。
将来の改善候補
| 項目 | 内容 | 優先度 |
|---|---|---|
| kapt → KSP 移行 | AGP 10.0対応 | 中 |
| MACベンダー表示 | OUIリストの主要ベンダーを同梱 | 低 |
| ルーターDHCPテーブル参照 | ホスト名取得の抜本的解決 | 低 |
| WoL動作確認 | 対象PC確保後に確認 | 高 |
動作確認状況
| 機能 | 状態 |
|---|---|
| アプリ起動・DeviceListScreen表示 | ✅ |
| LANスキャン実行・デバイス検出 | ✅ |
| デバイス登録 | ✅ |
| on/off表示(起動時自動Ping) | ✅ |
| Ping 10回リアルタイム表示・集計 | ✅ |
| デバイス編集・削除 | ✅ |
| WoL送信 | 🔲 未確認(対象PC確保後に実施) |
| ホスト名自動取得 | ❌ 現環境では取得不可 |