Daily Digest

每日新聞摘要

2026年08月27日

今日總結

內容會跟隨語言切換。

📝 今日焦點 - R8 誤刪反射載入建構子,讓正式版功能失效;也提醒第三方 AAR 規則可能直接關閉最佳化。 - Compose 與 coroutines 文章重申:要理解重組、穩定性、context 與 dispatchers,才能避免卡頓與誤用。 🔧 效能最佳化 - Compose 應縮小狀態讀取、改用不可變集合與 derivedStateOf,並用 Layout Inspector 追蹤重組熱點。 - 另有案例將重組從 180 次降為 0 次,顯示穩定參數與生產環境調校很關鍵。 🏗 架構設計 - Flutter add-to-app 可結合原生 Kotlin 與 Dynamic Features,將大型模組拆成按需載入以縮小安裝體積。 - Muffle 採全離線架構,以 Room、WorkManager、AlarmManager 與 BroadcastReceiver 落實隱私優先設計。 - VPN 與相機新 API 也強調流程完整性:前者要處理 WireGuard 連線旅程,後者可動態更新輸出配置。 ✅ 測試與品質 - LongShot 透過 debug 版套用 minify,成功重現只在 release 出現的錯誤,也避免模糊訊息掩蓋根因。 - 第三方 SDK 與 Android 建置工具的互動需嚴格檢查,否則可能悄悄破壞效能與可維護性。 🚀 語言演進 - KSwift 把 takeIf、apply、ifBlank 類似體驗帶進 Swift;reified 則讓 Kotlin inline 函式保留型別資訊。

01

Two features were dead in every release build for a month — and worked in every debug build

Dev.to Kotlin 作者:Codnet Software Company 發布:08-27 10:48

兩個功能在每個 Release 版本中都壞了整整一個月——但在每個 Debug 版本都正常

不經 R8 的 debug 版,無法重現任何 R8 問題。

重點摘要

LongShot 的兩個文字功能只在壓縮後的 release 版失效
R8 透過反射流程刪掉了 TextRegistrar 必要的建構子
將 debug 也啟用 minify,才能提早抓到 release 才會發生的錯誤

LongShot 的 Copy text 與 Hide personal data 兩個功能,在整整一個月內於所有 release 版本都失效,卻在 debug 版本正常。作者原本懷疑是記憶體、掃描預算或影像解碼問題,最後才發現真正原因是 R8 在混淆/縮減時刪掉了 ML Kit 的 TextRegistrar 無參數建構子,而該類別是透過 Firebase component 的反射機制載入。程式雖捕捉到例外,卻只回傳「Couldn't read this image」的模糊訊息。解法是補上一條保留 ComponentRegistrar 建構子的規則,並讓 debug 版也套用 minify,以便重現只會出現在正式版的問題。

02

Recomposition: The Silent Performance Killer in Your Jetpack Compose App

ProAndroidDev 作者:Majidshahbaz 發布:08-27 14:53

Recomposition:Jetpack Compose App 中無聲的效能殺手

你不是寫了一個 bug,而是寫了一個每秒執行 47 次的 Composable。

重點摘要

List 等不穩定參數會讓 Compose 無法跳過重組,導致過度 recomposition。
Layout Inspector 的 Recomposition Counts 可直接找出重組過多的元件。
使用不可變集合、記住 callback、搭配 derivedStateOf 可減少不必要更新。

本文指出,Jetpack Compose 的效能問題常來自 recomposition,它通常不會在程式碼中顯現,卻會在執行時造成卡頓。作者以 List 這類不穩定參數為例,說明它會讓 Compose 無法跳過未變更的元件,進而引發過多重組。文章建議改用不可變集合、記住 callbacks,並以 derivedStateOf 控制衍生狀態,降低不必要的 UI 更新。同時也介紹 Android Studio 的 Layout Inspector,可透過 Recomposition Counts 快速定位問題。最後強調應縮小狀態讀取範圍,讓只有真正依賴該狀態的元件重新組合。

03

Mastering On-Demand Feature Delivery in Flutter Add-to-App with Native Kotlin & Google Play Dynamic…

Medium Kotlin 作者: Shabbir Hussain 發布:08-27 07:32

在 Flutter Add-to-App 中運用原生 Kotlin 與 Google Play 動態功能,實現按需功能交付

一份逐步的架構指南,說明如何將較重的 Flutter 模組拆分到 Google Play 動態功能中,以縮小初始下載量並提升交付效率。

重點摘要

說明 Flutter add-to-app 與原生 Kotlin 的整合架構。
展示如何把較重的 Flutter 模組移至 Google Play 動態功能拆分。
重點在於減少初始下載量並提升按需交付效率。

本文提供一份步驟清楚的架構指南,說明如何在 Flutter add-to-app 架構中,結合原生 Kotlin 與 Google Play Dynamic Features 實作按需功能交付。文章主張將較重的 Flutter 模組移出初始安裝包,改以動態功能拆分方式提供,藉此降低首次下載體積,並讓大型功能只在需要時才載入。

04

Building Android Apps with Jetpack Compose: A Performance-First Engineering Deep Dive

Medium Kotlin 作者:Android Expert 發布:08-27 09:19

使用 Jetpack Compose 建構 Android 應用程式:以效能為先的工程深度解析

從 180 次重組降到 0 次:深入探討重組、穩定性,以及多數團隊在實務中忽略的生產環境陷阱。

重點摘要

探討 Jetpack Compose 的重組與穩定性
聚焦降低重組次數以提升效能
提醒團隊注意常被忽略的生產環境問題

本文以實務工程角度檢視 Jetpack Compose 的效能,並以將重組次數從 180 次降到 0 次的案例切入,說明重組行為、穩定性與效能調校的關鍵。文章同時點出許多團隊在開發 Android 應用時容易忽略的生產環境陷阱,強調要讓 Compose 應用在規模化情境下更有效率且更可靠,必須理解相關原理與常見風險。

05

Missing Kotlin’s takeIf, apply, and ifBlank in Swift? Introducing KSwift.

Medium Kotlin 作者:Wildan N 發布:08-27 10:14

Swift 缺少 Kotlin 的 takeIf、apply 和 ifBlank?KSwift 登場

KSwift 將 takeIf、apply、ifBlank 這些熟悉的 Kotlin 輔助方法帶進 Swift。

重點摘要

把常見的 Kotlin 工具函式帶到 Swift
讓 Swift 程式碼更精簡、更具表達力
面向同時開發 Android 與 iOS 的工程師

文章介紹 KSwift,這是一個受 Kotlin 常用函式 takeIf、apply、ifBlank 啟發的 Swift 工具。作者指出,對同時在 Android 與 iOS 開發的人來說,Kotlin 那些簡潔的輔助寫法在 Swift 中並不容易直接取得,因此常會感到不習慣。KSwift 的目的就是把這些便利帶進 Swift,幫助開發者寫出更短、更具可讀性的程式碼,特別適合跨平台、需要在兩種語言間切換思維的工程師。

06

Turning the page: a real page-curl on iOS with Compose Multiplatform

Medium Kotlin 作者:Zeyad Gasser 發布:08-27 10:30

翻頁:在 iOS 上以 Compose Multiplatform 實現真實頁面捲曲效果

我正在打造一款以紙張隱喻為核心的日記 App。

重點摘要

日記 App 的視覺設計以紙張隱喻為主軸
介面包含米白紙張與墨色深色模式
文章主題是在 iOS 上實作真實的頁面捲曲效果

作者正在開發一款日記 App,整體視覺識別強調紙張隱喻,包括米白色頁面、墨色深色模式,以及邊欄中的手寫風格細節。這篇內容主要是在介紹專案方向,並引導讀者前往 Medium 完整文章,了解如何使用 Compose Multiplatform 在 iOS 上做出逼真的翻頁捲曲效果。

07

Reified Functions in Kotlin, Explained Simply

Medium Kotlin 作者:Wagner Franchin 發布:08-27 10:38

Kotlin 中的 reified 函式:簡明解說

為什麼 Kotlin 有時會「忘記」型別,以及讓它重新記起來的那個關鍵字

重點摘要

說明 Kotlin 在執行期可能遺失型別資訊
介紹 reified 型別參數作為解法
指出 inline 函式中的關鍵字可讓 Kotlin 保留型別資訊

本文說明 Kotlin 的常見限制:型別資訊在執行期往往會被抹除,因此語言看起來像是「忘了」型別。接著文章介紹 reified 型別參數,說明它如何在需要時保留型別資訊。內容聚焦於 reified 函式的實際概念,並強調只要搭配 inline 函式中的特定關鍵字,就能讓 Kotlin 記住型別。

08

The Uninvited Guest: How One Third‑Party Line Was Quietly Disabling R8 for Our Whole App

Medium Kotlin 作者:José Pedro Cardoso 發布:08-27 14:03

不速之客:一行第三方設定如何悄悄讓整個 App 停用了 R8

一個第三方 RFID SDK 在 AAR 中帶來了看似無害的 consumer ProGuard 規則。

重點摘要

第三方 RFID SDK 的 AAR 內夾帶了 consumer ProGuard 規則。
那一行設定悄悄讓整個 App 的 R8 失效。
文章提醒開發者留意第三方套件對建置最佳化的影響。

本文說明第三方 RFID SDK zebra-api3lib 隨 AAR 釋出了一條看似無害的 consumer ProGuard 規則,卻意外讓整個 App 的 R8 被停用。作者藉此提醒,依賴套件中的單一設定就可能改變建置行為、降低程式碼最佳化效果,甚至造成難以察覺的效能問題。面對第三方元件時,特別是會影響 Android 建置工具的封裝細節,更應謹慎檢查。

09

From Tap-to-Connect to WireGuard Handshake: Building a Production VPN Flow on Android

Medium Kotlin 作者:Hadiuzzaman 發布:08-27 14:31

從點擊連線到 WireGuard 握手:在 Android 上打造可上線的 VPN 流程

真正的 VPN 應用絕不只是那麼簡單。

重點摘要

許多 VPN 教學只做到呼叫 VpnService,實際產品需求遠不止此。
真正的 Android VPN 流程要處理從使用者點擊到安全連線的完整路徑。
文章聚焦於以 WireGuard 握手為核心的實作流程。

本文指出,真正的 VPN 應用遠比教學中「呼叫 VpnService 就完成」複雜得多。作者以 Android 為場景,說明一個可上線的 VPN 流程必須從使用者點擊開始,一路處理到安全的 WireGuard 握手與連線建立。文章強調,簡化範例無法涵蓋產品需求,實務上必須完整設計連線旅程,才能做出可用且可靠的 VPN 應用。

10

Architecting for Privacy: Why I Chose Local-Only SQLite Storage over Firebase

Dev.to Kotlin 作者:Haseeb 發布:08-27 01:56

以隱私為核心的架構選擇:我為何放棄 Firebase,改用本機 SQLite

隱私不再是事後補救,而是功能本身;除非使用者明確匯出,資料不會離開裝置。

重點摘要

改用 Room 與 SQLite,避免將敏感資料上傳雲端
以 WorkManager、AlarmManager、GeofencingClient 實作全本機運作
從離線優先架構中學到隱私、信任與程式可維護性的價值

Haseeb 分享他為 Muffle 採取全離線、只在本機儲存的 Android 架構,而不是使用 Firebase。由於 App 需要處理位置紀錄、行事曆與祈禱時間等敏感資料,他認為隱私應是設計核心,而非雲端服務需額外承擔的責任。這也把複雜度轉回裝置端,必須依賴 Room、SQLite、WorkManager、ForegroundService、AlarmManager,並透過 BroadcastReceiver 在開機後重建排程與地理圍欄。他同時提到背景執行限制、Doze 模式與本地祈禱時間計算的挑戰,最後認為隱私優先的設計更能贏得使用者信任,也讓程式碼更乾淨模組化。

11

The Output List Is the Part That Changes: Android 17 Lets a Camera Session Attach and Detach Streams Without Being Rebuilt

Dev.to Kotlin 作者:Super Funicular 發布:08-27 02:55

變動的是輸出清單:Android 17 讓相機工作階段可在不重建下附加與移除串流

Android 17 為 CameraCaptureSession 新增 updateOutputConfigurations(),可在不重新設定整個相機工作階段的情況下動態附加或移除輸出表面。

重點摘要

輸出變動時不必重建整個相機工作階段
降低預先保留所有輸出表面的記憶體與程式複雜度
減少直播視圖切換時的卡頓、閃爍或暫停

Android 17 為 CameraCaptureSession 新增 updateOutputConfigurations(),讓應用程式能在不重建整個工作階段的情況下,動態附加或移除輸出表面。文章指出,這對無人看管的攝影情境特別重要,因為真正會改變的不是場景,而是有多少人同時要求影格。過去要不是一開始就配置所有輸出、長期承擔記憶體與管理成本,就是在觀看者出現時重建工作階段,可能造成錄影或預覽的明顯停頓。新 API 只改變切換輸出的成本,並不增加裝置原本可支援的能力。

12

Coroutine context and dispatchers in Kotlin

Medium Kotlin 作者:Nirali Pandya 發布:08-27 00:14

Kotlin 中的 Coroutine Context 與 Dispatchers

當我們開始使用 Kotlin coroutines 時,有兩個術語經常出現:coroutine context 與 dispatchers。

重點摘要

介紹 coroutine 的兩個核心概念:context 與 dispatchers
說明這些術語為何在 Kotlin coroutine 程式中常見
作為理解 coroutine 執行機制的入門內容

這篇文章以 Kotlin coroutines 為主題,指出在開始接觸時最常遇到的兩個名詞是 coroutine context 與 dispatchers。根據目前可見內容,文章主要是在鋪陳這兩個概念的重要性,作為理解 Kotlin coroutine 運作方式的基礎。雖然摘要片段未提供進一步細節,但可看出本文定位為入門導讀,協助讀者建立對 coroutine 執行與排程觀念的初步認識。