Android 開發|一鍵清除 App 資料,還原初始狀態的實作方法

問題說明 前陣子剛好海巡到 一則 iT 邦幫忙上的技術提問,大略找了一下資料,發現實作細節不難就順手回了一下。對方最後成功地完成他預期的需求,很高興能夠幫到對方的忙~ 提問問題如下: 📢 App 需要新增一個刪除帳號的功能,需求方期望按下刪除鈕後,App 能夠回到初始安裝的狀態。等同於用戶直接到手機系統設定的應用程式清單中,按下清除資料。 解決方案 Android 4.4 以後請用: ActivityManager.clearApplicationUserData() 根據文件的說明,呼叫 ActivityManager.clearApplicationUserData() 等同使用者於設定中按下清除資料。 Android API 19 以上可用。 內部 (Internal) 與外部 (External) 的應用程式私有資料都會被清除。 所有已取得的動態請求權限都會被撤銷。 1 2 val activityManager = application.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager activityManager.clearApplicationUserData() 📢 注意: 呼叫此方法後 App 會強制退出,使用者需要自行重新開啟 App。 Android 4.4 以前請用: Runtime.exec() 透過 Runtime 執行 ADB 指令 pm clear packageName。 1 Runtime.getRuntime().exec("pm clear ${applicationContext.packageName}") Reference: StackOverflow: Clear Application’s Data Programmatically 💡 延伸討論: 開發過程中完整清除 App 資料 有時候在開發或測試 App 的時候,也會需要還原 App 的初始狀態。 這時候可以改在 ADB 環境下,執行前述 Runtime 執行的清除指令。 ...

Published on December 5, 2023 · 1 min · 113 words · Daniel Huang

Android 動態更改應用程式圖標 App Icon

一、問題描述 最近使用 Todoist 做任務管理時發現,App 內有提供自選圖標的功能,也就是動態更換 App 的 Launcher Icon。 Step 0 Step 1 Step 2 Step 3 按下按鈕啟用自選圖標功能。 原本 App 預設是紅色的 App Icon。 在 App 內設定指定的 Icon 後。 Launcher 上的 Todoist Icon 就真的換剛才所選的 App Icon 了! 另外一個 App DuckDuckGo 也有一樣的功能。不過操作流程上不太一樣。DuckDuckGo 不需要特別啟用自選圖標,但在每次更換 Icon 時,App 都會在設定完成後自動關閉,使用者必須自動重啟 App 才能繼續使用。 🚩 兩者使用體驗差異整理: Todoist: 首次使用必須啟用功能。 啟用功能後 App 會自行關閉,需要使用者自行重開 App。 重開後就可以使用自選圖標的功能,而且往後的更換行為 App 都不會再自動關閉。 DuckDuckGo: 不須特別啟用功能。 每次更換圖標都會自動關閉 App,使用者要自己重開。 ==如果想直接看怎麼做,可以跳到 三、解決方案。== 二、研究歷程 2-1 問題釐清 搜尋幾個關鍵字其實滿快就找到相關的解法了,基本上分成使用 AndroidManifest.xml 的 activity-alias 更換 App 進入點的參數,或是使用 App Shortcuts。 ...

Published on November 23, 2023 · 7 min · 1349 words · Daniel Huang

Android UI 日期時間選擇 DatePicker

簡介 Android 原生提供的日期時間選擇 UI。 官方推薦使用 Material Design 的 API MaterialDatePicker (Dialog) 日期區間選擇 DateRangePicker Kotlin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import com.google.android.material.datepicker.MaterialDatePicker val datePicker = MaterialDatePicker.Builder.dateRangePicker() .setTitleText("選擇調查日期區間") .setSelection(Pair(startPeriod, endPeriod)) .build() datePicker.show(childFragmentManager, TAG_DATE_RANGE_PICKER) datePicker.addOnPositiveButtonClickListener { startPeriod = it.first endPeriod = it.second setTvStartAndEnd() } Java 1 2 3 4 5 6 7 8 9 10 11 12 import androidx.core.util.Pair; import com.google.android.material.datepicker.MaterialDatePicker; MaterialDatePicker<Pair<Long, Long>> dateRangePicker = MaterialDatePicker.Builder.dateRangePicker() .setTitleText(R.string.date_filter) .setSelection(Pair.create(startTime, endTime)) .build(); dateRangePicker.addOnPositiveButtonClickListener(selection -> mMainViewModel.setFilterPeriod(selection)); dateRangePicker.show(getChildFragmentManager(), TAG_DATE_PICKER); 使用 MaterialDatePicker.Builder.dateRangePicker 建立,可設定 UI 上的標題 (setTitleText()) 與預選的日期區間 (setSelection)。 dateRangePicker 是泛型 Pair<Long, Long>,Pair 中儲存的是開始日期與結束日期的 UNIX時間(milliseconds)。 ...

Published on October 31, 2023 · 2 min · 425 words · Daniel Huang

Android BuildConfig 消失了?

問題 最近開新專案的時候,發現寫 BuildConfig 都沒有出現 prompt,後來才發現是新的專案要另外開設定。 什麼是 BuildConfig BuildConfig 是 Gradle 在編譯時期自動建立的類別,裡面包含目前建製版本的相關資訊,開發者也可以自行加入客製化的欄位資料。 為什麼會有這個問題? 根據 解決 Android Studio 中的 BuildConfig 找不到問題 與 Fixing the “Build Type contains custom BuildConfig fields, but the feature is disabled” error w/ buildConfigField的資訊,可以知道 Gradle 8.0.0 後的版本,預設 BuildConfig 是關閉的。 解法 在 module 的 build.gradle 中新增以下程式碼,在重新 build project 即可。 1 2 3 4 5 6 7 8 9 10 // (app) build.gradle android { // 略... buildFeatures { // 開啟 buildConfig true } }

Published on June 30, 2023 · 1 min · 75 words · Daniel Huang

Android 定位結果的 `Location.getTime()` 不一定是衛星時間

Photo by SpaceX on Unsplash 前言 最近的專案需要取定位的時間,並用該時間判斷使用者是否有在指定時間完成任務,而業主就提出希望以定位所取得的時間做為判斷依據。 然後,就發現事情沒有想像中的那麼單純。 原來目前在 Android 的定位結果中所取得的時間,只有在定位來源為純 GPS 的情況下才會是衛星所回傳的時間。 來看看究竟是怎麼一回事吧… 先認識 Location 型別 不論是使用 Android 官方推薦的 Fused Location Provider 或是 LocationManager ,定位結果所回傳的型別都是 Location。這個型別除了基本的經緯度與海拔等資訊,其中也包含定位的時間。 通常開發上指的定位時間,我們會使用 Location.getTime() 取得 Unix epoch time,再將這串數字轉成人類可閱讀的時間格式。 Unix epoch time:從 UTC 1970 年 1 月 1 日 0 時 0 分 0 秒起至現在的總秒數,不考慮閏秒。 – Wikipedia Location.getTime() 會跟定位來源有關 從 Android Doc: Location.getTime() 的說明會發現,不同的定位結果所取得的時間來源不見得相同。 當定位結果是由 LocationManager.GPS_PROVIDER 提供的時候,時間會是由衛星所提供。如果是其他的 Provider,時間來源則不一定,不過通常會是使用裝置系統的 Unix epoch time。 There is no guarantee that different locations have times set from the same clock. Locations derived from the LocationManager#GPS_PROVIDER are guaranteed to have their time originate from the clock in use by the satellite constellation that provided the fix. Locations derived from other providers may use any clock to set their time, though it is most common to use the device’s Unix epoch time system clock (which may be incorrect). ...

Published on May 27, 2023 · 2 min · 257 words · Daniel Huang