Android EncryptedSharedPreference 系統升級後無法解密的錯誤與解決方案

一、問題描述 1 2 使用者的手機為 Sony 品牌,首次安裝 App 時,系統版本為 Android 14,能夠正常使用。 近期系統升級為 Android 15 後,開啟 App 即閃退。即使移除後重新安裝,仍然無法使用。 二、查看錯誤事件 查找 Crashlytics 上的錯誤事件,全部事件只有兩筆,其中只有 BasePreference.pref_delegate$lambda$0 這筆看起來最為相關。 查看錯誤訊息的內容,確認是在實例化 EncryptedSharedPreference 時出了問題。 程式裡實例的方式是參考 Android 開發 | 加密版的 SharedPreference - EncryptedSharedPreferences。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Fatal Exception: com.google.crypto.tink.shaded.protobuf.D: Protocol message contained an invalid tag (zero). at com.google.crypto.tink.shaded.protobuf.InvalidProtocolBufferException.<init>(InvalidProtocolBufferException.java:100) at com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite.parsePartialFrom(GeneratedMessageLite.java:100) at com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite.parseFrom(GeneratedMessageLite.java:100) at com.google.crypto.tink.proto.Keyset.parseFrom(Keyset.java:3) at com.google.crypto.tink.integration.android.SharedPrefKeysetReader.read(SharedPrefKeysetReader.java:67) at com.google.crypto.tink.CleartextKeysetHandle.read(CleartextKeysetHandle.java:67) at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.read(AndroidKeysetManager.java:67) at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewKeyset(AndroidKeysetManager.java:67) at com.google.firebase.messaging.GmsRpc.i(GmsRpc.java:17) at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:180) at // ... 錯誤訊息 Fatal Exception: com.google.crypto.tink.shaded.protobuf.D: Protocol message contained an invalid tag (zero). InvalidProtocalBufferException 代表 解密資料時解析 protobuf 格式失敗,通常是因為解密出的內容是無效的(可能是空的或亂碼)。 ...

Published on February 11, 2025 · 4 min · 642 words · Daniel Huang

如何在 Android 上取得準確且不被用戶竄改的時間

一、前言 前陣子專案有一項需求,是希望 App 能夠取得準確且不會被使用者竄改的時間。 研究了一下 StackOverflow: How do I get the most accurate time with Android? 上面的討論,決定整理成一篇完整的筆記,也許能拯救到未來的自己? XD 1-1 在 Android 中取得當下時間 大家應該都會直覺地想到以下幾個方式: System.currentTimeMillis()。 Calendar.getInstance() Instant.now() 但這幾個方式,拿到的時間都是所謂的系統時間,只要使用者到系統設定中手動調整,就可以輕易地修改這幾個方式回傳的時間。 二、Android SDK 的 SystemClock Android 的 SystemClock 類別中,有提供以下兩個方法可以拿到準確的時間。 2-1 SystemClock.currentGnssTimeClock() 時間跟稍後會提到的LocationManager.GPS_PROVIDER拿到的時間一樣。 官方文件 SystemClock.currentGnssTimeClock() Returns a Clock that starts at January 1, 1970 00:00:00.0 UTC, synchronized using the device’s location provider. API 29 以上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import android.os.Build import android.os.SystemClock import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter fun getGpsApiDateTime(): String { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { try { val zoneClock = SystemClock.currentGnssTimeClock().withZone(ZoneId.of("Asia/Taipei")) ZonedDateTime.now(zoneClock).format(dateTimeFormatter) } catch (e: Exception) { "GNSS NOT AVAILABLE" } } else { "SYSTEM NOT AVAILABLE" } } :::danger 📢 注意! 在部分裝置上,GNSS API 回傳的時間有可能是錯誤的… 細節請看 問題-GNSS-API-與-Location-Provider-所拿到的時間可能是錯誤的。 ::: ...

Published on August 26, 2024 · 6 min · 1093 words · Daniel Huang

如何查看檔案雜湊值 (MD5、SHA256、SHA1)

Windows 使用命令提示字元 CMD 開啟檔案所在位置。 於視窗上方網址列輸入 cmd 開啟命令提示字元。 輸入指令certutil -hashfile {你的檔案名稱} {演算法}。 ENTER 執行後就會出現該檔案的雜湊值。 MD5 1 2 3 4 5 certutil -hashfile myfile.txt MD5 // MD5 hash of v1.5.4-20211130-debug.apk: // c90323574f66283d6b146f2d98d477c4 // CertUtil: -hashfile command completed successfully. SHA-1 1 certutil -hashfile myfile.txt SHA1 使用 7-Zip 查看 右鍵點選檔案開啟選單 選擇 7-Zip / CRC SHA 選擇所需要的演算法。(如果點選 * 號,則會算出 7-Zip 支援的所有演算雜湊值。) Mac 開啟 Terminal 根據演算法選擇指令 md5 檔案路徑 shasum -a 1 檔案路徑 shasum -a 256 檔案路徑 參考資料 How to Check an MD5 Checksum on desktop/laptop (PC/MAC) Mac OSX 如何在命令行中生成 md5、sha1、sha256 校验 本文同步發表在 HackMD。 ...

Published on July 29, 2024 · 1 min · 87 words · Daniel Huang

Android Studio 產製 SBOM 軟體物料清單

前言 公司專案近期收到客戶的要求,疑似因為數發部想推動公部門的開放原始碼,需要廠商填寫系統相關資訊,其中一項就包含 SBOM 軟體物料清單。 什麼是 SBOM 軟體物料清單 SBOM 全稱為 Software Bill of Materials,中文翻譯為軟體物料清單。 白話來說,SBOM 就是一份描述軟體專案使用到的套件清單,就像買零食會看到的原料清單一樣。 SBOM 需要包含: 供應商名稱 套件名稱 套件版本 其他可識別套件的 ID 依賴關係 SBOM表作者 產表時間 SBOM 的報告格式: Software Package Data Exchange (SPDX): Linux 基金會推動。 CycloneDX: OWASP 發行。 Software Identification (SWID) Tags: ISO & IEC 發行。 為什麼要做 讓採購方可以清楚知道,該軟體中有使用到哪些套件,進而在採購與使用前發現有疑慮的資安問題。 OCF Lab 拒絕受駭!美國推行「軟體物料清單」公開軟體組成,採購更安心 實作 SPDX Gradle Plugin Github: spdx/spdx-gradle-plugin libs.versions.toml 1 2 3 4 5 6 7 [versions] # ... spdx = "0.8.0" [plugins] # ... spdx = { id = "org.spdx.sbom", version.ref = "spdx"} Top-Level build.gradle.kts 1 2 3 4 5 6 // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { // 略... // 加入 alias(libs.plugins.spdx) apply false } build.gradle.kts (App Level) 1 2 3 4 5 6 7 8 9 10 11 12 13 plugins { // 略... alias(libs.plugins.spdx) } // 加入以下 spdxSbom { targets { create("release") { configurations.set(listOf("releaseRuntimeClasspath")) } } } 📂 參考資料 Issue: Project Configuration Question #49 ...

Published on June 20, 2024 · 3 min · 480 words · Daniel Huang

Android 14 AlarmManager SCHEDULE_EXACT_ALARM 權限閃退

一、問題描述 Android 14 的使用者反映應用程式閃退,經查測後發現是設定指定時間提醒功能時出現閃退。 1 Fatal Exception: java.lang.SecurityException: Caller com.tms.qpass needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms. 從錯誤訊息可以清楚看到,問題發生當下是拋出 SecurityException 。 二、錯誤原因說明 其實從錯誤訊息中就可略知一二,一切都跟 SCHEDULE_EXACT_ALARM 還有 USE_EXACT_ALARM 有關。 ✍ 如果是日曆或鬧鐘應用程式,應該要宣告的是 USE_EXACT_ALARM 精確鬧鐘權限。 USE_EXACT_ALARM 是一項即將推出的新權限,作用是針對以 Android 13 (API 級別 33) 以上版本為目標的應用程式,授予精確鬧鐘功能的存取權。 USE_EXACT_ALARM 是一項受限制權限,只有當應用程式的核心功能支援精確鬧鐘需求,應用程式才能宣告這項權限。要求這項受限制權限的應用程式必須接受審查,若是應用程式不符合使用限制條件,就禁止在 Google Play 發布 核心功能: - 應用程式是鬧鐘或計時器應用程式。 - 應用程式是會顯示活動通知的日曆應用程式。 上述以外的用途,則應評估能否選擇使用 SCHEDULE_EXACT_ALARM 做為替代方案。 以上整理自 Google Play Policy。 SCHEDULE_EXACT_ALARM 權限 💡 適用的精準鬧鐘 API setExact() setExactAndAllowWhileIdle() setAlarmClock() Android 12 以前 可直接使用 API。 Android 12 後 從 Android 12 開始,所有 Target SDK 為 Android 12 的 App ,如果要使用 AlarmManager 的精準鬧鐘 API,都必須要在 AndroidManifest.xml 中宣告SCHEDULE_EXACT_ALARM 權限。 ...

Published on March 27, 2024 · 2 min · 294 words · Daniel Huang