閉じられないAndroidPOSアプリの構築
公開: 2022-03-11モバイルアプリ開発の世界は広大で進化し続けており、新しいフレームワークとテクノロジーがほぼ毎日登場しています。 モバイルデバイスについて考えるとき、スマートフォンほど人気がないにもかかわらず、おそらく携帯電話やタブレットを思い浮かべるでしょう。
AppleのiOSとGoogleのAndroidはモバイル市場を支配しており、それぞれ過去10年間に浮き沈みがありました。 今日は、Androidと、必ずしもモバイルではないデバイスでのAndroidの使用について詳しく説明します。
オープンソースであることは、Googleのモバイルオペレーティングシステムに非常に興味深い副作用をもたらしました。 確かに、さまざまなスマートフォン会社のさまざまなAndroidフォークのすべてを考えるかもしれませんが、モバイルではないAndroidを実行しているすべてのデバイスについてはどうでしょうか。 冷蔵庫、スマートオーブン、ドアロック、さらにはPOS(Point of Sale)デバイスに至るまで、あらゆるものがAndroidを実行できます。 後者は私がこの記事を書くことになった理由です。
AndroidPOSシステム
約1年前、私は普通ではないAndroidデバイスで遊ぶようになりましたが、それはほとんどの人が使用する可能性が高いものではありません。 問題のデバイスは、中国のベンダーが提供するAndroidベースのPOSシステムであり、サーマルプリンターも統合されています(店舗やATMでレシートを印刷するために使用されるものなど)。
しかし、最大の驚きはそのソフトウェアでした。それはAndroidの骨ストックバージョンを実行していました。 正しく思い出せば、当時はAndroid 8を実行していたか、Googleコードネームを好む場合はAndroidOreoを実行していました。 デバイス自体は古い学校のポータブルPOSデバイスのように見えますが、PINを入力する物理的なキーボードの代わりに、以前のAndroidフォンで使用されていたような静電容量式タッチスクリーンを備えています。
私の要件は簡単でした。開発中のアプリを実行しながら、サーマルプリンターなど、このデバイスの機能を使用できる方法があるかどうかを確認する必要がありました。 要件自体が可能であることに気がつくとすぐに、別の問題が私の注意を引きました。それはセキュリティです。
カード支払いやその他の種類のトランザクションを処理するデバイスがある場合、同じデバイスでTikTok、Gmail、またはSnapchatを実行できないようにする必要があるかもしれません。 このデバイスはタブレットとまったく同じように動作し、GoogleのPlayストアがプリインストールされていました。 小さなコンビニエンスストアに行って、レジ係が自撮り写真を撮ったり、ナイジェリアの王子からのメールを開いたり、マルウェアに感染した奇妙なWebサイトを閲覧したりするのを想像してみてください。
その後、レジ係が同じデバイスを渡してPINを入力します。 個人的には、そのようなデバイスを介してクレジットカード情報を提供することについては安全ではありません。
Androidメニューからのユーザーのロック
セキュリティはさておき、私はさらに重要な課題に取り組む必要がありました。アプリ内でAndroidPOSデバイスを使用している人をロックする必要がありました。 これらのデバイスは技術者以外の人に配布されたため、オペレーティングシステムをいじることはできませんでした。
確かに、レジ係はアプリケーションをインストールすることはできますが、ほとんどのレジ係はカスタムROMをフラッシュしたり、他の低レベルの操作を処理したりすることができませんでした。 アプリ自体はReactNativeで作成されていますが、このコンテキストでは関係ありません。 私が行った変更はすべてネイティブJavaコードで行われているため、メインアプリケーションの開発に何を使用していても、これらの調整は機能するはずです。
少し免責事項として、この手順はAndroidアプリでのみ機能します。 Appleは、iPhoneやiPadでこのようなことを簡単に実行するために必要な制御を提供していません。これは、iOSの閉じた性質を考えると理解できます。
ユーザーがアプリケーションを終了する可能性のある方法は4つあります。
- ホームボタンを使用します。
- [戻る]ボタンを使用します。
- [最近]ボタンを使用します。
- 通知バーからアプリを終了します。
最近の通知をクリックするか、そのバーから設定に移動すると、ユーザーはアプリケーションを終了します。 ジェスチャもありますが、1日の終わりに、これらのジェスチャは通常のボタンを押すのとまったく同じアクションをトリガーします。
また、アプリケーションのロックを解除するためのPINシステムがあると、誰かがデバイスを管理するのに非常に役立ちます。 このように、PINを持っている人だけが、エンドユーザーへのより深いアクセスを提供することなく、異なるバージョンのアプリケーションをインストールできます。
ホームボタン
ユーザーがホームボタンを押さないようにするために、実際に無効にする必要はありません。
Androidの便利な機能の1つは、さまざまなランチャーが利用できることです。 通常、これらのアプリは、さまざまなホーム画面、アプリドロワー、およびさまざまなUIカスタマイズへのアクセスを提供します。 すべてのAndroidデバイスには、メーカーによってプリインストールされたものがあります。 最終的に、これらは1つの小さいが重要な例外を除いて、通常の通常のアプリです。
つまり、オペレーティングシステムがアプリケーションをランチャーとして認識できれば、それをデフォルトのランチャーとして設定できます。 これの副作用は、ホームボタンを押すたびに、デバイスがホームランチャーに移動することです。 そして、私たちのアプリケーションがホームランチャーである場合、基本的に、このホームボタンは役に立たなくなります。 これを行うには、AndroidプロジェクトでAndroidManifest XMLファイルを編集し、次の2行のコードを追加する必要があります。
<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>
1行目は、ユーザーがホームボタンを押した場合にアプリを選択できるようにし、2行目は、このアクションが発生するたびにアプリをデフォルトとして設定できるようにします。
これで、あとはフィールドエージェントがアプリケーションをクライアントに配信するときにデバイスにインストールするだけで済みました。 ランチャーになる可能性のあるアプリをインストールするたびに、Androidは、別のランチャーを使用するかどうか、およびそのランチャーをデフォルトとして設定するかどうかを尋ねてきます。
したがって、ホームボタンを押した場合、または最近のアプリケーションをすべてクリアした場合、デバイスは自動的に私のアプリケーションに移動します。
戻るボタン
次に、戻るボタンを処理する必要があります。 モバイルアプリは通常、画面を戻るための画面上の方法を提供します。特に、多くのデバイスには専用の「戻る」キーがないためです。
数年前、これはAppleのiOSデバイスの場合であり、画面の下に1つの物理的なボタンがあるすでに象徴的なデザインが特徴でした。 ただし、近年、ほとんどのAndroidデバイスは物理的なホームボタンも削除しています。 最初に、それらは画面上のボタンに移動しましたが、電話メーカーが小さなベゼルとあごを備えた全画面デバイスに移動するにつれて、ジェスチャーを優先して電話が段階的に廃止されるのを目にしています。
これが意味するのは、Androidがデフォルトで提供する[戻る]ボタンは実際には必要ないということです。このボタンを完全に役に立たなくするには、アクティビティに単純なコードブロックを追加するだけです。
@Override public void onBackPressed() { }
これは非常に単純なコードブロックです。メインアクティビティでは、ユーザーが[戻る]ボタンを押すたびにインターセプトできます。 この場合、ユーザーがアプリを終了するためにそのボタンを何度も押したくないので、デフォルトのメソッドを何もしないメソッドで上書きして、戻る場合にアプリに何もしないように指示することができます。ボタンが押されました。

これは、一部のアプリケーションが、何度も戻って誤って終了する前に確認を求める方法です。
最近のボタン
[最近]ボタンを処理する必要がありますが、これは最も難しいボタンです。 また、これは間違いなくベストプラクティスや、Playストアにプッシュする必要のあるものではありませんが、ここでのニッチなケースでは機能します。
メインアクティビティで[戻る]ボタンが押されたときを知ることができるのと同じように、アプリがいつ一時停止したかを知ることもできます。 これは何を意味するのでしょうか? このコードは、アプリがフォアグラウンドアプリケーションからバックグラウンドアプリケーションに切り替わるたびにトリガーされます。
このイベントをインターセプトすると、現在のアプリケーションのタスクIDを取得し、アクティビティマネージャーにこのタスクを最前面に移動するように指示します。 これを行うには、以前に編集したのと同じAndroidマニフェストファイルに1つの特別な権限が必要です。
<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); }
これで、最近のメニューに移動するたびに、アプリケーションは自動的にフォーカスを変更します。 確かに、画面が少しちらつくことがありますが、このアプリケーションを終了することはできません。 そして、もう1つクールなことがあります。通知をクリックするか、通知トレイから直接設定に移動して終了することもできると言ったことを覚えていますか? これらのアクションを実行すると、アプリがバックグラウンドで実行され、コードがトリガーされ、ユーザーはすぐに元に戻されます。
これらはすべて非常に迅速に行われるため、ユーザーはバックグラウンドで何が起こっているかに気付くことはありません。 また、このアプローチのもう1つの優れた点は、クイックトグルが引き続き使用できることです。 たとえば、Wi-Fiネットワークを選択したり、サウンドを無効にしたりすることはできますが、実際の設定アプリにアクセスする必要があるものはすべて許可されていません。
ソリューション
これが最善の方法かどうかはわかりませんが、それでも、私が知らなかったトピックを研究している間、それは本当に興味深いプロセスでした。 そしてそれは動作します! 警告:この時点で、開発者としてアプリケーションを終了する方法は2つしかありません。オペレーティングシステムを再インストールするか、ADBを介してアプリを強制終了/アンインストールします。
どういうわけかデバイスへのADB接続を失った場合、私はあなたを抜け出すことができる簡単な方法を知りません。 それを避けるために、私はPINシステムを構築することになりました。
エッジケース
確実に説明する必要がある状況がいくつかあります。 まず、デバイスが再起動した場合はどうなりますか? 手動で再起動する必要はありません。オペレーティングシステムがクラッシュする可能性もあります。
以前にアプリケーションをデフォルトのランチャーとして設定したため、オペレーティングシステムが起動するとすぐに、アプリケーションが自動的に起動します。 しかし、Androidは起動時にホーム画面をロードすることをどのように知っていますか? これは、基本的にデフォルトのランチャーをロードするだけだからです。 この時点ではデフォルトのランチャーであるため、再起動は問題になりません。 そして、Androidはある時点でアプリケーションを強制終了できますか? 理論的には、RAMメモリがいっぱいになるとアプリが停止する可能性がありますが、実際には、これはほとんど不可能です。 私たちのアプリは閉じられないので、誰も他のアプリを開くことができず、RAMメモリがいっぱいになることはありません。
私がそれがいっぱいになると考える唯一の方法は、アプリケーションに大量のメモリリークがある場合ですが、その場合、ユーザーをアプリケーション内に保持するよりも大きな問題が発生します。 それでも、Androidが何らかの理由でアプリケーションに強制終了信号をトリガーしたとしても、家に帰ろうとすると、OSはデフォルトのランチャーであるため、アプリを再起動しようとします。これにより、ユーザーはロックされたままになります。
バックドアの構築
簡単に説明すると、アプリケーション設定には、PINを入力してアプリのロックを解除できる場所がありました。 PINが正しい場合は、単純な条件ステートメントを実行することにより、onPauseメソッドとonBackPressedメソッドによって設定された制限を無効にします。 そこから、ユーザーはクイックトグルメニューから設定を入力できます。 その後、いつでもデフォルトのランチャーをストックのランチャーに戻すことができます。これにより、アプリを完全に終了できます。 この部分を処理する方法はたくさんありますが、設定したのと同じ制限を無効にするメカニズムがあると便利です。 指紋認証を行ってロックを解除できるかもしれません。 可能性はほぼ無限大です。
まとめ
結局、私は誰も閉じたり殺したりできないアプリケーションを残されました。 デバイスを再起動しても、現在はアプリケーションであるデフォルトのランチャーに直接電源が戻るため、役に立ちません。 それは私たちのプロジェクトにとって有用であることがわかりました、そしてとても奇抜でラインから外れた何かを試すことの満足は確かに素晴らしくそして非常にやる気を起こさせました。
Androidによって開発者の生活が楽になったデバイスやユースケースはたくさんあります。 最近では、Androidアプリケーションの作成は、多くの異なるプラットフォーム固有の言語やツールを使用するよりもはるかに簡単です。 IoTデバイス、キオスクアプリケーション、POSシステム、タクシーのナビゲーションおよび支払いゲートウェイなどを考えてみてください。
これらは、Androidによってアプリ開発が容易になったユースケースですが、この記事で示したのと同様の方法でアクセスを制限したいニッチなユースケースでもあります。