📝 今日焦點 本日重點包括:說明在 Android 10+ 上打包並執行二進位(例如 QEMU)會遭遇 SELinux W^X 限制的根因與可行解法 — 將執行檔改名為 .so 並放入 jniLibs/<abi>/,使用以 Bionic(Android linker)為 ELF 直譯器的編譯產物(如 Termux build),並在 AGP 3.6+ 設定 packagingOptions.jniLibs.useLegacyPackaging true 強制解壓,這組做法可在非 root APK 中允許 execve() 成功,對於需要在 App 內啟動 VM 或原生工具的專案(如 Pockr)具有直接可用性與部署影響。
📝 今日焦點 EveryCal:一款以場景卡(Smart Cards)為核心的 Android 計算器,聚焦減少日常情境中的上下文切換(烹飪、購物等),提供即時輸入結果、語音喚出、懸浮計算器與 19 種情境卡片(稀釋/濃度、瓦數換算、單位/匯率/價格比較等);技術採用 Kotlin + Jetpack Compose、Room、Retrofit、Coroutines/Flow,強調 UX 連續性與可客製化工作區,對提升使用情境效率有實務價值。
🏗 架構設計 Sub Tracker(以 AI agents 主導開發):作者以需求定義與 agent orchestration 為開發流程核心,前端採 Kotlin + Jetpack Compose(MVVM + Clean Architecture),後端為 Java Spring Boot + MongoDB,雙方透過 REST API 串接;使用 Gemini/Claude/Antigravity 等工具。意義在於示範 AI 可加速產出與原型驗證,但開發者角色轉向系統設計師與 AI 協調者,需加強審查、測試與架構治理以確保品質與可維護性。
🏗 架構設計 UI 狀態建模建議:文章主張以 Kotlin sealed class 明確建模 UI 狀態(例如 Loading、Success(data)、Error),取代零散布林旗標。好處是讓狀態成為編譯期可檢查的閉集合,當使用 when 做模式匹配時能獲得分支完整性檢查,提升可讀性、可測試性與維護性,降低因旗標競合或遺漏情況導致的錯誤風險。
✅ 測試與品質 Pockr 的重啟迴圈案例揭示 race condition:問題源於 Kotlin 層以布林 isRunning 作為狀態來源,導致在 stopVm() 與新 QEMU 啟動間的短暫窗格回報為 stopped,使 Flutter 端重新允許啟動並觸發重複啟動。修正做法是在 getStatus() 優先檢查 vmProcess 並確認其 exitValue(),僅在進程確實終止時回報 stopped,並在 Dart 層加入啟動護欄以忽略重複呼叫;經 Firebase Test Lab 驗證後問題消失。此案強調以「實際資源(process handle)」為真實來源、加強日誌與在自動化 UI 測試下預期會曝露 race 的重要性。
📝 今日焦點 本日重點包括:說明在 Android 10+ 上打包並執行二進位(例如 QEMU)會遭遇 SELinux W^X 限制的根因與可行解法 — 將執行檔改名為 .so 並放入 jniLibs/<abi>/,使用以 Bionic(Android linker)為 ELF 直譯器的編譯產物(如 Termux build),並在 AGP 3.6+ 設定 packagingOptions.jniLibs.useLegacyPackaging true 強制解壓,這組做法可在非 root APK 中允許 execve() 成功,對於需要在 App 內啟動 VM 或原生工具的專案(如 Pockr)具有直接可用性與部署影響。
📝 今日焦點 EveryCal:一款以場景卡(Smart Cards)為核心的 Android 計算器,聚焦減少日常情境中的上下文切換(烹飪、購物等),提供即時輸入結果、語音喚出、懸浮計算器與 19 種情境卡片(稀釋/濃度、瓦數換算、單位/匯率/價格比較等);技術採用 Kotlin + Jetpack Compose、Room、Retrofit、Coroutines/Flow,強調 UX 連續性與可客製化工作區,對提升使用情境效率有實務價值。
🏗 架構設計 Sub Tracker(以 AI agents 主導開發):作者以需求定義與 agent orchestration 為開發流程核心,前端採 Kotlin + Jetpack Compose(MVVM + Clean Architecture),後端為 Java Spring Boot + MongoDB,雙方透過 REST API 串接;使用 Gemini/Claude/Antigravity 等工具。意義在於示範 AI 可加速產出與原型驗證,但開發者角色轉向系統設計師與 AI 協調者,需加強審查、測試與架構治理以確保品質與可維護性。
🏗 架構設計 UI 狀態建模建議:文章主張以 Kotlin sealed class 明確建模 UI 狀態(例如 Loading、Success(data)、Error),取代零散布林旗標。好處是讓狀態成為編譯期可檢查的閉集合,當使用 when 做模式匹配時能獲得分支完整性檢查,提升可讀性、可測試性與維護性,降低因旗標競合或遺漏情況導致的錯誤風險。
✅ 測試與品質 Pockr 的重啟迴圈案例揭示 race condition:問題源於 Kotlin 層以布林 isRunning 作為狀態來源,導致在 stopVm() 與新 QEMU 啟動間的短暫窗格回報為 stopped,使 Flutter 端重新允許啟動並觸發重複啟動。修正做法是在 getStatus() 優先檢查 vmProcess 並確認其 exitValue(),僅在進程確實終止時回報 stopped,並在 Dart 層加入啟動護欄以忽略重複呼叫;經 Firebase Test Lab 驗證後問題消失。此案強調以「實際資源(process handle)」為真實來源、加強日誌與在自動化 UI 測試下預期會曝露 race 的重要性。
📝 Highlights Key takeaways: the Android execve() blockage on Android 10+ is caused by SELinux W^X labeling app data as non-executable; practical workaround is to package binaries as .so in jniLibs/<abi>/ so PackageManager extracts them into nativeLibraryDir (exec_type), build with the Android/Bionic linker (Termux builds) and set packagingOptions.jniLibs.useLegacyPackaging true on AGP 3.6+ — together these steps enable running bundled native tools (e.g., QEMU) inside non-root APKs and impact how VM-enabled apps are shipped.
📝 Highlights EveryCal: a context-driven Android calculator that minimizes context switches for everyday tasks (cooking, shopping) via real-time input results, voice trigger, floating calculator and 19 Smart Cards (dilutions, wattage, units/currency, price-per-unit, etc.). Implemented with Kotlin + Jetpack Compose, Room, Retrofit, Coroutines/Flow; it demonstrates how focused UX patterns and domain-specific automation reduce friction in common user flows.
🏗 Architecture Sub Tracker (AI-agent driven development): the project shows orchestrating AI agents to generate UI and backend code while the author defines requirements and reviews outputs. Client uses Kotlin + Jetpack Compose (MVVM, Clean Architecture); backend is Java Spring Boot + MongoDB via REST. Tooling included Gemini/Claude/Antigravity/Stitch. The takeaway: AI can accelerate implementation, but engineers shift toward architecting, validating, and governing generated artifacts to maintain quality and long-term maintainability.
🏗 Architecture UI state modeling: use Kotlin sealed classes to model UI states (e.g., Loading, Success(data), Error) instead of scattered boolean flags. This produces a closed, compiler-checked set of states, enabling exhaustive when branches, improving readability, testability, and reducing bugs from forgotten or conflicting flags.
✅ Testing & Quality Pockr restart-loop root cause and fix: a race where getStatus() relied on a transient isRunning flag caused Flutter to re-enable Start and trigger duplicate VM launches. Fixes: make getStatus() consult the vmProcess and verify exitValue() before reporting stopped, and add a Dart-side guard to ignore duplicate start calls. Verified in Firebase Test Lab; lesson: prefer actual resource state over transient flags, add defensive checks and detailed logging because automated UI tests will surface such races.