Daily Digest

每日新聞摘要

2026年10月13日

今日總結

內容會跟隨語言切換。

📝 今日焦點 - Kotlin 在 JVM 上支撐生產級 AI,單一 monorepo 結合 Koog、Exposed、coroutines 與 kotlinx.serialization,並以結構化輸出、fallback 與觀測處理模型失效,移除 blocking code 後吞吐量提升 5×。 - AI agent 與行動應用持續強調可控性:退款需人工核准、派送狀態改採雙軸模型防止重複送出,並以 checkpoint、scripted 測試與硬性規則把風險移出 prompt。 🔧 效能最佳化 - Android 冷啟動可透過 Baseline Profiles 取得雙位數改善,重點是正確產生、驗證與維持可信結果。 - Jetpack Compose 重組過多常源自狀態不穩,修正常見陷阱能避免不必要重繪。 🏗 架構設計 - Onetap、地理圍欄與相機導引都把重邏輯留在本機,搭配 WorkManager、Room、GeofencingClient 與感測器規則,降低耗電並提升穩定性。 - Compose Multiplatform、React Native、Bazel 與 KMP 相關文章則聚焦跨平台銜接、混合 UI 測試與依賴衝突處理,顯示工具鏈整合仍是核心課題。 ✅ 測試與品質 - 多篇文章強調可驗證性:JVM 測試與場景重播、離線 scripted ChatModel、錄製混合式 UI 互動,以及用日誌與 pinning 流程排查 Bazel 衝突。 - Flow 收集與 switch 回傳值的討論,也凸顯生命週期感知與失敗語意要明確,才能維持 UI 與狀態的一致性。 🚀 語言演進 - Kotlin 2.5 的 companion block 與 companion extension 讓 static 風格 API 更自然,並減少 companion object 的樣板與互通成本。 - Jetpack Compose 的 collectAsStateWithLifecycle 成為建議預設,另有關於 iOS 與 Android 互通、Swift SDK、以及 object/companion 用法的實務整理。

01

The JVM Speaks AI: Cobrainer's Journey with Kotlin, Koog and Exposed

Dev.to Kotlin 作者:Daniel Alker 發布:10-13 07:51

JVM 也能談 AI:Cobrainer 使用 Kotlin、Koog 與 Exposed 的實戰旅程

Cobrainer 的生產環境 AI 建立在同一個 Kotlin monorepo 上,端到端共享型別,並以 Koog、Exposed、coroutines 與 kotlinx.serialization 為基礎。

重點摘要

Kotlin 讓六位工程師與 coding agents 在同一套型別安全堆疊上協作。
Koog 保留 Kotlin 的控制流程、契約與 provider 差異,適合生產環境。
可靠性來自 fallback chain、circuit breaker、LLMObs、contract tests 與移除 blocking code。
展開詳細摘要

Cobrainer 說明他們如何在 JVM 上以 Kotlin 建立生產級 AI,而不是另外引入 Python 技術棧。團隊使用單一 Kotlin monorepo,讓型別從前到後共享,並以 Koog 負責 agent 與 prompt 編排、Exposed 處理 SQL、coroutines 支援非阻塞 I/O、kotlinx.serialization 定義結構化契約。Koog 的優勢在於緊貼 Kotlin 本身,使控制流程、sealed types 與 provider 能力差異都保持可見。生產上,結構化輸出支撐 Job Architecture 生成;遇到 provider 限流或失效時,則靠 fallback chain、circuit breaker 與 LLM 觀測處理。團隊也提到,移除 coroutine 路徑中的 blocking code 後,吞吐量提升了 5×。

02

Tracking a Tapped Pixel Patch with a Gyroscope That Is Never Allowed to Say "Green"

Dev.to Kotlin 作者:Mehmet Apaydın 發布:10-13 08:23

用永遠不能說「綠色」的陀螺儀追蹤被點選的像素區塊

最重要的規則是:估計只能以估計的方式顯示,提供方向指引,但永遠不算測量值。

重點摘要

系統追蹤的是使用者點選的像素區塊,而不是做物件偵測。
陀螺儀可在快速轉動時補位,但估計結果不能觸發綠色狀態。
針對資料新鮮度、座標系與測試都設了嚴格限制,避免陳舊或含糊的結果。
展開詳細摘要

這篇文章介紹一個 Android 相機 App 的設計:使用者點選畫面中的細節後,App 會持續追蹤那一小塊影像,並引導使用者移動手機,直到該細節對齊構圖輔助線。作者沒有採用物件偵測,而是以正規化互相關在小型灰階影格上追蹤被點選的區塊,並排除低變異、模糊或歧義過高的匹配。當快速轉動導致影像匹配失敗時,系統會用陀螺儀旋轉歷史來預測位置,但這些估計只能算「可能」,不能變成綠色、不能觸發自動拍攝或回饋。文章也說明感測器與相機資料的新鮮度規則、共用的正規化座標系、模擬器上的效能觀察,以及以 JVM 測試和場景重播為主的測試方法。

03

An AI agent that asks before it pays: human approval for tool calls in Kotlin

Dev.to Kotlin 作者:Manuel Alejandro Hermoso 發布:10-13 12:26

會先詢問才付款的 AI agent:Kotlin 中的工具呼叫需人工核准

真正能解決問題的是包住模型的結構:讓一般程式碼決定模型何時可自行行動、何時必須等待。

重點摘要

退款前先經人工核准,再執行工具呼叫。
將中斷狀態寫入 checkpoint,重啟後可續跑。
把硬性規則放進 Kotlin 圖結構,而不是 prompt。
展開詳細摘要

本文示範如何用 Kotlin 建立一個不能在未經人工核准下退款的 AI agent。作者以 Telar 為例,先建立可呼叫工具的 agent,再在工具執行前插入中斷點,讓高風險操作能被審核、同意或拒絕。這個暫停狀態可透過 checkpoint 保存,讓服務重啟後繼續處理;也能用 scripted ChatModel 在不連網、不用金鑰的情況下測試。最後,文章說明如何把逾期訂單等硬性規則放進圖結構中,而不是交給 prompt,讓模型根本碰不到不該處理的案件。

04

Turning bank notifications into expenses on Android, without a bank login

Dev.to Kotlin 作者:Rao Asad 發布:10-13 13:00

在 Android 上把銀行通知轉成支出,且不需銀行登入

Onetap 只監看你選定的銀行或錢包 App,將付款通知轉成支出項目,完全不需要銀行登入或銀行 API。

重點摘要

只讀取使用者明確選定的 App 通知;OTP 與其他敏感代碼會留在裝置上不外送。
付款文字會先在本機遮罩敏感識別資訊,再交給模型處理,對含糊資訊不硬猜。
透過先寫入磁碟、WorkManager 重試、去重與重新綁定 listener,提升記錄可靠性。
展開詳細摘要

Onetap 是一款 Android 應用,能把使用者選定的銀行或錢包 App 所發出的付款通知轉成支出紀錄,且不需要銀行登入或銀行 API。文章說明其通知監聽流程:先依 package name 過濾,再在裝置端丟棄 OTP,並於送交語言模型前遮罩卡號、帳號等敏感資訊。作者也處理了幣別歧義、避免重複入帳、先寫入加密 inbox、以 WorkManager 重試,以及在 listener 中斷或重連後補抓通知等問題,並提到 Xiaomi/HyperOS 的特殊行為與除錯測試方式。

05

Swift on Android, part 1: what the official SDK does and how it differs from KMP

Dev.to Kotlin 作者:Kirill Lukyanov 發布:10-13 13:13

Swift 在 Android 上運行:第 1 部分,官方 SDK 做了什麼,以及它與 KMP 有何不同

自 Swift 6.3 起,Android 已有官方支援的 Swift SDK,但那是開源 Swift 專案的成果,不是 Apple 為 Android 發行 Swift。

重點摘要

Swift 6.3 帶來首個正式版 Android Swift SDK。
SDK 以 cross-compilation 產生原生 .so,並透過 swift-java 與 JNI 溝通。
與 KMP 相反,這裡是 Swift 走向 Android,而 Android 仍是主體應用。
展開詳細摘要

作者是使用 Kotlin Multiplatform 交付產品的 iOS 工程師,從自己的專案出發思考:如果共享邏輯改成 Swift 在 Android 執行,而不是 Kotlin 在 iPhone 執行,會怎麼樣。文章指出,Swift 6.3 起已有由開源 Swift 專案提供的 Android 官方 SDK,但它不是 Apple 直接為 Android 發行的版本,也不是完整的 UI 解法。內容說明 SDK 的運作方式、已包含與缺少的能力,以及 swift-java 如何透過 JNI 讓 Swift 與 Kotlin 雙向互通,並逐項對照 KMP。最後也整理了適合與不適合現在嘗試的情境。

06

Bridging React Native with Native iOS and Android Screens

Medium Kotlin 作者:Silversky Technology 發布:10-13 10:14

將 React Native 與原生 iOS 和 Android 畫面銜接起來

React Native 讓單一 JavaScript 程式碼庫可同時對應 iOS 與 Android。

重點摘要

以單一 JavaScript 程式碼庫同時支援 iOS 與 Android
主題是把 React Native 與原生畫面銜接
點出資深行動工程師最終會遇到的限制
展開詳細摘要

React Native 讓團隊能以單一 JavaScript 程式碼庫同時開發 iOS 與 Android,但本文指出,經驗豐富的行動工程師終究會碰到這種做法的瓶頸。文章聚焦於如何將 React Native 與原生 iOS、Android 畫面銜接,暗示在某些情境下仍需要把跨平台程式碼與平台專屬介面結合。截文未提供實作細節或結果,只呈現文章的切入點與問題意識。

07

Daily Kotlin: Object Declarations and Companion Objects

Medium Kotlin 作者:Jason Kwon 發布:10-13 11:00

Daily Kotlin:物件宣告與 companion object

精通執行緒安全的單例、companion factory,以及 Kotlin Multiplatform 中的匿名物件運算式。

重點摘要

聚焦 Kotlin 的物件宣告與 companion object。
涵蓋執行緒安全的單例、companion factory 與匿名物件運算式。
主題延伸到 Kotlin Multiplatform 的使用情境。
展開詳細摘要

本文主題是 Kotlin 的物件宣告與 companion object,重點放在如何運用這些機制實作執行緒安全的單例、companion factory,以及匿名物件運算式。從標題與內文可知,文章聚焦於 Kotlin Multiplatform 脈絡下的實務用法,強調掌握這些物件相關模式,而非討論其他 API 或未提及的效能結論。

08

Fixing Uploads That Stop When a Compose iOS Screen Closes

Medium Kotlin 作者:Sijan Neupane 發布:10-13 12:40

修正 Compose iOS 畫面關閉時中斷的上傳

離開照片審閱畫面後,使用者應該能繼續操作 App。

重點摘要

Compose Multiplatform 在 iOS 上可能因畫面被銷毀而取消上傳。
問題出現在離開照片審閱畫面時。
文章重點是避免上傳在畫面關閉後意外停止。
展開詳細摘要

本文說明在 Compose Multiplatform 的 iOS 流程中,當使用者離開照片審閱畫面時,畫面被銷毀可能導致上傳被取消。作者指出,關閉畫面不應中斷 App 的後續操作,重點在於處理這種上傳中斷問題,讓傳輸即使在 UI 離開該頁後仍能持續進行。

09

One guard clause, four switches in my app, and the return value you cannot copy

Medium Kotlin 作者:Muhammad Azhar 發布:10-13 12:43

一個 guard clause、我應用程式中的四個 switch,以及你無法複製的回傳值

三個分支在設定讀取失敗時回傳 false,另一個則回傳 null,而這個差異就是整個安全設計的關鍵。

重點摘要

三個分支在讀取設定失敗時回傳 false。
其中一個分支改為回傳 null,形成不同的安全契約。
這個回傳值差異是應用程式安全設計的核心。
展開詳細摘要

本文指出,應用程式中的四個 switch 分支看似相近,卻有一個關鍵差異:當設定讀取失敗時,三個分支回傳 false,只有一個分支回傳 null。作者強調,正是這個回傳值的不同,構成了整體的安全設計,讓失敗語意可以被更精確地表達,而不是把所有錯誤都視為同一種情況。

10

Cutting Android Cold Start With Baseline Profiles: Generating, Verifying, and Keeping It Honest in…

Medium Kotlin 作者:Ramadan Sayed 發布:10-13 13:01

透過 Baseline Profiles 降低 Android 冷啟動:生成、驗證與維持真實性

你的專案裡其實正躺著一個尚未被拿走的冷啟動時間雙位數百分比改善。

重點摘要

Baseline Profiles 可改善 Android 冷啟動時間。
文章說明如何生成並驗證 profile。
也強調要持續維持結果的真實性。
展開詳細摘要

本文指出,Android 專案中可能已經存在一項可觀的冷啟動時間改善機會,幅度可達雙位數百分比,而且不需要新增新的程式路徑或大幅改動。文章重點放在實務流程:如何生成 Baseline Profiles、如何驗證其正確性,以及如何在專案演進過程中維持結果的可信度,避免只靠未經驗證的主張。

11

Fixing Recomposition in Jetpack Compose: 12 Stability Mistakes That Redraw Your UI Twice

Medium Kotlin 作者:Ramadan Sayed 發布:10-13 13:01

修正 Jetpack Compose 中的重組:12 個會讓 UI 重繪兩次的穩定性錯誤

你的畫面重繪次數,遠比你想像的還多。

重點摘要

說明重組可能比開發者預期更頻繁發生。
聚焦 12 個會引發額外 UI 重繪的穩定性錯誤。
主題圍繞 Jetpack Compose 的狀態與穩定性陷阱。
展開詳細摘要

本文指出,Jetpack Compose 的畫面重繪次數可能遠超開發者預期,而 UI 狀態不穩定是造成重組過於頻繁的主要原因之一。從標題與摘要可知,文章聚焦於 12 個常見的穩定性錯誤,這些問題會導致不必要的重組,甚至讓 UI 重繪兩次。內容應是協助開發者在使用 Jetpack Compose 時辨識並避開這些陷阱。

12

Filling the Test-Recording Gap in Compose-First Android Applications

Medium Kotlin 作者:Tharusha Haththella 發布:10-13 14:31

補上以 Compose 為主的 Android 應用程式中的測試錄製缺口

為 XML Views 與 Jetpack Compose 並存的應用程式打造互動錄製器。

重點摘要

聚焦於 Compose 為主的 Android 應用程式測試錄製。
處理 XML Views 與 Jetpack Compose 並存的情境。
說明如何建構互動錄製器。
展開詳細摘要

這篇文章探討以 Jetpack Compose 為主、但仍包含 XML Views 的 Android 應用程式,在測試錄製上的工具缺口。作者指出,現有工具難以同時捕捉兩種 UI 系統中的使用者互動,因此嘗試打造一個可在混合式 Compose 與 Views 環境中運作的互動錄製器。本文重點在實務上的工具問題,而非對 Compose 本身提出更廣泛的變更。

13

Architecting a Low-Power Geofencing Engine: Lessons from the Android Location API

Dev.to Kotlin 作者:Haseeb 發布:10-12 23:19

打造低耗電地理圍欄引擎:來自 Android Location API 的經驗

真正的挑戰,是正確處理 PendingIntent receiver。

重點摘要

以 GeofencingClient 取代頻繁輪詢定位,可降低電池耗電。
透過前景服務與常駐通知,維持背景中的 geofence 運作。
結合本機 Room、BOOT_COMPLETED 重新註冊與半徑編輯器,提升可靠性與使用者理解。
展開詳細摘要

本文分享作者為 Muffle 建立離線 Android 地理圍欄系統的經驗,讓手機能依據位置自動切換靜音與音量設定。作者一開始嘗試定期輪詢定位,但很快發現這會喚醒 GPS、耗電嚴重,因此改用 GeofencingClient,把邊界偵測交給系統處理。為了因應背景限制,實作中加入前景服務與常駐通知,並用輕量的 PendingIntent receiver 從本機 Room 資料庫讀取規則。作者也指出,網路型定位在高密度城市可能不夠精準,太小的半徑會讓觸發不穩定;此外,裝置重開機後 geofence 也可能被清除,所以需要用 BOOT_COMPLETED 重新註冊。核心結論是:遵守 Android 的系統限制,盡量把邏輯留在本機,才能做出省電且穩定的定位功能。

14

Why Your AI Agent Produces Duplicates (It’s a Modeling Error, Not a Logic Error)

Dev.to Kotlin 作者:StareBrain 發布:10-13 04:02

為什麼 AI Agent 會產生重複:這是建模錯誤,不是邏輯錯誤

多數 AI agent 的重複派送 bug,源自把兩個獨立問題壓成同一個狀態欄位。

重點摘要

將配送確認與語意接受分開建模。
衍生最終狀態,不直接儲存合併結果。
只有在確認失敗後才重送,未解決狀態不能重試。
展開詳細摘要

本文指出,AI agent 的多數重複派送問題,並非缺少 retry guard 或 idempotency key,而是把兩個獨立問題誤併成單一狀態欄位:是否已有派送證據,以及該證據是否符合預期結果。作者提出以 DeliveryState 與 AcceptanceState 組成的雙軸模型,並用狀態機規則限制先確認配送、後判斷接受,避免在未確認時就進入重試。這樣可把「尚未確認」和「真的失敗」區分開來,未解決狀態先進入 reconciliation,語意不符則修正後再派送,同時保留每次 dispatch 的獨立綁定。

15

Taming Bazel Dependency Conflicts: An Android Case Study

ProAndroidDev 作者:Taufik Amaryansyah 發布:10-12 23:38

駕馭 Bazel 相依性衝突:Android 案例研究

Bazel 的 MVS 一開始會讓人覺得很死板,但透過手動覆寫與仔細釘選相依項,仍可解決衝突。

重點摘要

Gradle 與 Bazel 的版本解析策略不同。
僅設定 version_conflict_policy = "pinned" 無法真正解衝突。
實際作法是檢查 maven_pin.txt,並用 maven.artifact 覆寫特定套件版本。
展開詳細摘要

作者在 Bazel 驅動的 Android 專案中更新 Compose BOM 2024.12.01 後,遇到相依性衝突。文中說明 Bazel 的 Bzlmod 採用 Minimal Version Selection,和 Gradle 預設的「選最新版本」不同,因此當多個套件要求不同版本時就容易出錯。單純加入 version_conflict_policy = "pinned" 並不能解決問題;真正的做法是先執行 Maven pinning 流程,把完整錯誤輸出到 maven_pin.txt,再從日誌中找出衝突套件,最後在 MODULE.bazel 透過 maven.artifact 手動覆寫版本。經過多次迭代後,建置終於恢復正常。作者也提到,Bazel 的可重現性很有價值,但 rules_android、rules_kotlin 等規則更新本身仍相當棘手。

16

The Evolution of Statics: Say Goodbye to Kotlin Companion Objects?

ProAndroidDev 作者:Nav Singh 發布:10-12 23:57

靜態成員的演進:向 Kotlin companion object 說再見?

Kotlin 2.5 引入 companion block 與 companion extension,讓類別層級成員更接近原生 static。

重點摘要

companion object 本質上是 singleton,可能帶來記憶體開銷與 Java 互通不便。
companion block 直接編譯為 JVM 的 static 成員;companion extension 可從類別外新增類 static 成員。
這些功能在 Kotlin 2.5.0-Beta1 屬於 experimental,需設定預覽倉庫與編譯器旗標。
展開詳細摘要

本文說明 Kotlin 過去如何以 companion object 集中管理類別層級的常數與工廠方法,但它在底層仍是 singleton,可能帶來記憶體開銷,也會讓 Java 互通多出 @JvmStatic 等處理。Kotlin 2.5 以實驗性形式推出 companion block 與 companion extension:前者省略 object 關鍵字,會直接編譯成 JVM 上的原生 static 成員;後者則可從外部為既有類別加入靜態風格的屬性或函式。文中也示範在 2.5.0-Beta1 啟用預覽倉庫與編譯器旗標的設定方式。

17

The Evolution of Flow Collection in Jetpack Compose

ProAndroidDev 作者:chanzmao 發布:10-13 00:04

Jetpack Compose 中 Flow 收集的演進

Compose 中的 Flow 收集演進,重點在於減少樣板碼,同時不犧牲生命週期正確性。

重點摘要

collectAsState() 讓 Flow 整合變簡單,但不會在低於 STARTED 時自動停止收集。
repeatOnLifecycle() 與 flowWithLifecycle() 帶來更安全的生命週期感知收集。
collectAsStateWithLifecycle() 將生命週期處理與 Compose State 整合為單一 API。
展開詳細摘要

本文回顧 Jetpack Compose 中 Flow 收集方式的演進,從最初的 collectAsState() 到具備生命週期感知的 UI 更新。collectAsState() 雖然簡潔,但當 Android 生命週期低於 STARTED 時不會自動停止收集,因此在背景狀態下可能仍持續執行。接著文章介紹 Lifecycle 2.4.0 的 launchWhenStarted()、repeatOnLifecycle() 與 flowWithLifecycle(),雖提升安全性,卻仍帶來較多樣板碼。最後,collectAsStateWithLifecycle() 將常見模式整合成單一 API,成為多數 Compose 畫面的建議預設,也說明停止 UI 收集不一定等於停止上游工作或資料刷新。