構建一個無法關閉的安卓 POS 應用

已發表: 2022-03-11

移動應用程序開發的世界是廣闊且不斷發展的,幾乎每天都會出現新的框架和技術。 當您想到移動設備時,您可能會想到您的手機或平板電腦,儘管它們遠沒有智能手機那麼受歡迎。

蘋果的 iOS 和谷歌的安卓在移動市場上佔據主導地位,在過去的十年裡它們都有起起落落。 今天,我將更多地討論 Android 及其在不一定是移動設備上的使用。

開源對谷歌的移動操作系統產生了非常有趣的副作用。 當然,我們可能會想到來自不同智能手機公司的所有不同的 Android 分支,但是所有運行 Android 的非移動設備呢? 如今,從冰箱、智能烤箱、門鎖甚至銷售點 (POS) 設備等各種設備都可以運行 Android。 後者是我最終寫這篇文章的原因。

如今,銷售點 (POS) 設備可以運行 Android

安卓 POS 系統

大約一年前,我開始使用一款非常普通的 Android 設備,而且大多數人都不太可能使用它。 有問題的設備是來自一家中國供應商的基於 Android 的 POS 系統,該系統還具有集成的熱敏打印機(例如用於在商店或 ATM 上打印收據的打印機)。

不過,最大的驚喜是它的軟件:它運行的是安卓的骨幹版本。 如果我沒記錯的話,當時它運行的是 Android 8,或者如果你更喜歡 Google 代號,它運行的是 Android Oreo。 該設備本身看起來像一個老式的便攜式 POS 設備,但它不是用於輸入 PIN 的物理鍵盤,而是像過去的 Android 手機中使用的那樣採用電容式觸摸屏。

我的要求很簡單:我必須看看是否有一種方法可以在運行我們正在開發的應用程序的同時使用該設備的功能,例如熱敏打印機。 當我意識到需求本身是可能的時,另一個問題引起了我的注意:安全性

問題是,如果你有一個處理卡支付和其他類型交易的設備,你可能不希望同一設備能夠運行 TikTok、Gmail 或 Snapchat。 該設備的行為與平板電腦完全一樣,它甚至還預裝了 Google 的 Play 商店。 想像一下去一家小型便利店,看到你的收銀員在自拍,打開尼日利亞王子的電子郵件,瀏覽奇怪的、充滿惡意軟件的網站。

之後,收銀員會遞給您相同的設備以輸入您的 PIN 碼。 就個人而言,通過這樣的設備提供我的信用卡信息我會感到不安全。

將用戶鎖定在 Android 菜單之外

拋開安全不談,我不得不接受一個更重要的挑戰:我必須將使用 Android POS 設備的人鎖定在我的應用程序中。 由於這些設備是交付給非技術人員的,因此無法選擇使用操作系統。

當然,收銀員不僅能夠安裝應用程序,但他們中的大多數人無法刷新自定義 ROM 或處理其他較低級別的操作。 該應用程序本身是用 React Native 編寫的,儘管在這種情況下這無關緊要。 我所做的所有修改都是在本機 Java 代碼中進行的,因此無論您使用什麼來開發主應用程序,這些調整都應該有效。

作為一點免責聲明,此過程僅適用於 Android 應用程序。 Apple 沒有給我們在 iPhone 或 iPad 上輕鬆完成此類事情所需的控制權,鑑於 iOS 的封閉性,這是可以理解的。

用戶可以通過四種方式退出應用程序:

  • 使用主頁按鈕。
  • 使用返回按鈕。
  • 使用“最近”按鈕。
  • 通過通知欄離開您的應用程序。

單擊最近的通知或從該欄轉到設置都會導致用戶退出我們的應用程序。 您也有手勢,但歸根結底,這些手勢會觸發與常規按鈕按下完全相同的動作。

此外,擁有解鎖應用程序的 PIN 系統對於管理設備的人非常有用。 這樣,只有持有 PIN 碼的人才能安裝不同版本的應用程序,而無需為最終用戶提供更深入的訪問權限。

主頁按鈕

為了防止用戶按下 Home 按鈕,我們不必實際禁用它。

Android 的一項有用功能是提供不同的啟動器。 通常,這些應用程序為您提供不同的主屏幕、應用程序抽屜以及對各種 UI 自定義的訪問。 每台 Android 設備都由製造商預裝了一個。 最終,這些只是普通的常規應用程序,只有一個小但至關重要的例外。

這意味著如果操作系統可以將我們的應用程序識別為啟動器,我們可以將其設置為默認啟動器。 這樣做的副作用是,每次您按下 Home 按鈕時,設備都會將您帶到 Home 啟動器。 如果我們的應用程序是 Home 啟動器,那麼基本上,這個 Home 按鈕就變得無用了。 為此,我們必須在我們的 Android 項目中編輯 AndroidManifest XML 文件並添加這兩行代碼:

 <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>

第一行將使我們的應用程序有資格在用戶按下 Home 按鈕時被選中,第二行允許我們的應用程序在此操作發生時被設置為默認值。

現在,唯一剩下要做的就是讓現場代理在將應用程序交付給客戶時在設備上安裝應用程序。 每當您安裝可能成為啟動器的應用程序時,Android 都會詢問您是否要使用另一個啟動器以及是否要將其設置為默認啟動器。

所以現在,如果您按下主頁按鈕或清除所有最近的應用程序,設備會自動將您定向到我的應用程序。

構建一個無法關閉的安卓 POS 應用

後退按鈕

接下來,我們必須處理後退按鈕。 移動應用程序通常提供通過屏幕返回的屏幕方式,特別是因為許多設備沒有專用的“返回”鍵。

幾年前,Apple 的 iOS 設備就是這種情況,它採用了已經標誌性的設計,屏幕下方只有一個物理按鈕。 然而,近年來,大多數 Android 設備也放棄了物理 Home 按鈕。 首先,他們轉向屏幕按鈕,現在我們看到他們正在逐步淘汰手機,取而代之的是手勢,因為手機製造商轉向具有小邊框和下巴的全屏設備。

這意味著 Android 默認提供的後退按鈕並不是真正需要的,為了使這個按鈕完全無用,我們只需要在我們的活動中添加一個簡單的代碼塊:

 @Override public void onBackPressed() { } 

構建一個無法關閉的安卓 POS 應用

這是一段非常簡單的代碼:我們的主要活動允許我們在用戶按下後退按鈕時進行攔截。 在我們的例子中,由於我們不希望用戶按下該按鈕太多次以退出應用程序,我們可以簡單地用一個什麼都不做的方法覆蓋默認方法,告訴我們的應用程序在返回的情況下什麼也不做按鈕被按下。

這就是某些應用程序在您通過返回太多次而意外退出它們之前要求確認的方式。

最近按鈕

我們仍然需要處理“最近”按鈕,這是最棘手的一個。 此外,這絕對不是最佳實踐,也不是您應該推送到 Play 商店的東西,但它確實適用於我們這裡的小眾案例。

與主活動讓我們知道何時按下後退按鈕的方式相同,它也讓我們知道應用程序何時暫停。 這是什麼意思? 每當我們的應用程序從前台應用程序切換到後台時,都會觸發此代碼。

在攔截這個事件的時候,我們會得到我們當前應用的任務ID,並告訴活動管理器把這個任務移到最前面。 為此,我們需要在之前編輯的同一個 Android 清單文件中獲得一項特殊權限。

 <manifest xmlns:andro package="com.johnwick"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.REORDER_TASKS" /> <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> </application> </manifest>

這將允許我們閱讀正在進行的任務並對這些任務進行更改。 此外,我們仍然需要截取應用程序被發送到後台的時刻。 我們可以再次覆蓋活動中的onPause方法。

在這裡,我們獲取任務管理器並強制它將特定任務移動到前台。 在我們的例子中,該特定任務是剛剛發送到後台(我們的應用程序)的任務。

 @Override public void onPause() { super.onPause(); ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); activityManager.moveTaskToFront(getTaskId(), 0); }

現在,每次您想進入最近的菜單時,應用程序都會自動重新聚焦。 當然,您有時可能會出現一點屏幕閃爍,但您將無法退出此應用程序。 還有一件更酷的事情 - 還記得我說過您也可以通過單擊通知或通過通知托盤直接進入設置來退出嗎? 好吧,執行這些操作會將應用程序置於後台,這將觸發我們的代碼,然後用戶會立即被推回。

所有這些都發生得如此之快,以至於用戶不會注意到後台發生的事情。 此外,這種方法的另一個好處是您的快速切換仍然可用。 例如,您仍然可以選擇 wifi 網絡,或禁用聲音,但任何需要您進入實際設置應用程序的操作都是不允許的。

構建一個無法關閉的安卓 POS 應用

解決方案

我不確定這是不是最好的方法,但在研究一個我什至不知道可能的主題時,這仍然是一個非常有趣的過程。 它有效! 一個警告:此時,作為開發人員退出應用程序的方式只有兩種——要么重新安裝操作系統,要么通過 ADB 殺死/卸載應用程序。

如果您不知何故失去了與設備的 ADB 連接,我不知道有什麼簡單的方法可以讓您離開。 為了避免這種情況,我最終建立了一個 PIN 系統。

邊緣案例

有幾種情況我們需要確保我們考慮到這一點。 首先,如果設備重啟怎麼辦? 它不一定是手動重啟,也可能是操作系統崩潰。

由於我們之前將我們的應用程序設置為默認啟動器,因此一旦操作系統啟動備份,它應該會自動啟動我們的應用程序。 但是 Android 是如何知道在啟動時加載主屏幕的呢? 這是因為它基本上只是加載您的默認啟動器。 由於此時我們是默認啟動器,因此重新啟動應該不是問題。 Android 會在某個時候扼殺我們的應用程序嗎? 從理論上講,如果 RAM 內存填滿,它可能會殺死應用程序,但在現實生活中,這幾乎是不可能的。 由於我們的應用程序是不可關閉的,沒有人可以打開其他應用程序,因此 RAM 內存不應該填滿。

我能想到填充它的唯一方法是如果我們的應用程序有巨大的內存洩漏,但在這種情況下,你會遇到比將用戶留在應用程序中更大的問題。 儘管如此,即使 Android 以某種方式向我們的應用程序觸發了終止信號,每當您嘗試回家時,操作系統都會嘗試再次啟動我們的應用程序,因為它是默認啟動器,從而使用戶鎖定。

建立後門

作為快速解釋,應用程序設置中有一個地方可以輸入 PIN 碼來解鎖應用程序。 如果 PIN 正確,它將通過執行一個簡單的條件語句來禁用我們的 onPause 和 onBackPressed 方法設置的限制。 從那裡,用戶將被允許通過快速切換菜單輸入設置。 之後,您始終可以將默認啟動器設置回庫存啟動器,這將使您完全退出應用程序。 有很多方法可以處理這部分,但最好有一種機制來禁用您設置的相同限制。 也許你可以做一個指紋認證來解鎖。 可能性幾乎是無窮無盡的。

構建一個無法關閉的安卓 POS 應用

包起來

最終,我留下了一個沒有人可以關閉或殺死的應用程序。 即使重新啟動設備也無濟於事,因為它會直接重新啟動到默認啟動器,當前是我們的應用程序。 事實證明它對我們的項目很有用,嘗試如此古怪和不合時宜的東西的滿足感確實很棒,而且非常激勵人心。

在許多設備和用例中,Android 讓開發人員的生活變得輕鬆。 如今,編寫 Android 應用程序比使用許多不同的特定於平台的語言和工具要容易得多。 想想物聯網設備、信息亭應用程序、銷售點系統、出租車的導航和支付網關等等。

這些是 Android 使應用程序開發更容易的用例,但也是您希望以與我們在本文中演示的方式類似的方式限制訪問的利基用例。