Androidの3rd Partyアプリでキオスク端末化する方法
目次
Androidキオスク端末化の背景
Android端末で特定のアプリ以外は一切使えないように制限したい、という場合、自作のアプリであれば、下記の記事のような作り方で実現できますが、
Kioskアプリと端末の作り方 ~DroidKaigi2018発表内容の要約+α~
ソースコードのいじれないGoogle Play Storeで公開されているアプリの場合、上記では対応できないため工夫が必要です。
そこで今回は、3rd Partyアプリでキオスク端末化する方法を紹介します。
概要としては、独自ホームアプリから特定のアプリ以外は起動できないようにします。 また、端末の設定変更もできないようにします。
キオスク端末とは?
特定の機能に絞り込んだ情報端末機器のことで、コンビニのチケット発券機や、家電量販店の写真プリント機、回転寿司屋さんなどのタッチパネルなど操作できるものもあれば、単に情報を流すだけの機能に特化したものもあります。
キオスク端末化の手順
それでは、肝となるホームアプリの作り方を順に説明していきます。
アプリをDeviceOwnerに指定できるようにする
ユーザの操作無しでアプリから他アプリの無効化などを制御するためには、DeviceOwner権限が必要になります。 DeviceOwner権限をアプリに指定するためには、アプリ内にDeviceAdminReceiverが必要になります。
下記のようにandroid.app.admin.DeviceAdminReceiverを継承して作成します。 DeviceOwner権限をアプリに指定できるようにするだけなら、onEnabledなどで特に処理をする必要はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[sourcecode lang="java"]package com.testkiosk.receiver; public class DeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver { @Override public void onEnabled(Context context, Intent intent) { super.onEnabled(context, intent); Log.d("TAG_KIOSK", "DeviceAdminReceiver onEnabled"); } @Override public void onDisabled(Context context, Intent intent) { super.onDisabled(context, intent); Log.d("TAG_KIOSK", "DeviceAdminReceiver onDisabled"); } } [/sourcecode] |
AndroidManifest.xmlにも忘れずにreceiverを追加しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[sourcecode lang="html"] <receiver android:name=".receiver.DeviceAdminReceiver" android:label="device admin" android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_receiver" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver> [/sourcecode] |
不要なアプリの無効化
DeviceOwner権限がある状態で下記のコードが実行されると、指定したアプリを無効化できます。 無効化したアプリは、他のアプリから呼び出されても起動しなくなくなります。 また、最近使用したアプリの履歴からも消えます。
PackageManagerから端末内のアプリのパッケージ名一覧を取得して、自身のアプリ以外はすべて無効化します。 今回は適当にActivityのonCreateなどで実行しておき。
1 2 3 4 5 |
[sourcecode lang="java"] ComponentName adminComponentName = new ComponentName(context.getApplicationContext(), DeviceAdminReceiver.class); DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); devicePolicyManager.setApplicationHidden(adminComponentName, app.packageName, true); [/sourcecode] |
クイック設定パネルの無効化
DeviceOwner権限がある状態で下記のコードを実行されると、クイック設定パネルを無効化できます。 クイック設定パネルを無効化することで、クイック設定パネルからの設定変更をできないようにします。
こちらも適当にActivityのonCreateなどで実行しておきます。
1 2 3 4 5 |
[sourcecode lang="java"] ComponentName adminComponentName = new ComponentName(context.getApplicationContext(), DeviceAdminReceiver.class); DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); devicePolicyManager.setStatusBarDisabled(adminComponentName, true); [/sourcecode] |
自身をホームアプリとして登録
DeviceOwner権限がある状態で下記のコードを実行することで、自身をホームアプリとして登録します。 ホームアプリとして登録することで、常にこのアプリが起動するようになります。 端末を再起動しても、このアプリが最初に起動します。
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="java"] IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN); intentFilter.addCategory(Intent.CATEGORY_DEFAULT); intentFilter.addCategory(Intent.CATEGORY_HOME); ComponentName adminComponentName = new ComponentName(activity.getApplicationContext(), DeviceAdminReceiver.class); DevicePolicyManager devicePolicyManager = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName homeComponentName = new ComponentName(activity.getApplicationContext(), activity.getClass()); devicePolicyManager.addPersistentPreferredActivity(adminComponentName, intentFilter, homeComponentName); [/sourcecode] |
アプリをDirectBoot対応にする
Android7.0以上で設定アプリを無効化すると端末が起動できなくなるため、DirectBootを有効にします。
Android7.0以上では、DirectBootMode対応していないホームアプリは、設定アプリのcom.android.settings/.FallbackHome経由で起動されるようになっており、設定アプリを無効化した状態では端末の起動に失敗します。 DirectBootMode対応することで直接ホームアプリが起動できるため、設定アプリを無効化しても端末の起動ができるようになります。
AndroidManifest.xmlのActivityにdirectBootAwareの設定を追加します。
1 2 3 4 5 6 7 |
[sourcecode lang="html"] <activity ... android:directBootAware="true" ... > [/sourcecode] |
ホームアプリの起動時に3rd Partyアプリを起動する
ホームアプリとして登録したActivityのonResumeで3rd Partyのアプリを起動するようにします。 今回はGoogleMapを起動するようにします。
1 2 3 4 5 6 7 |
[sourcecode lang="swift"]override fun onResume() { super.onResume() Intent intent = mPackageManager.getLaunchIntentForPackage("com.google.android.apps.maps"); context.startActivity(intent); } [/sourcecode] |
ホームアプリとして登録したActivityのonResumeで3rd Partyのアプリを起動するようにします。 今回はGoogleMapを起動するようにします。
端末にホームアプリをインストール
Android Studioなどから端末に作成したホームアプリをインストールします。
Device Ownerを有効にする
下記のDeviceAdminReceiverを指定して、DeviceOwnerの権限を与えるには、
1 2 3 4 5 6 |
[sourcecode lang="java"]package com.testkiosk.receiver; public class DeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver { ... } [/sourcecode] |
このようなコマンドを実行します。
1 2 3 |
[sourcecode lang="php"] adb shell dpm set-device-owner com.testkiosk/.receiver.DeviceAdminReceiver [/sourcecode] |
DeviceOwnerの権限が付与できると下記のような表示になります。
1 2 3 4 |
[sourcecode lang="php"] Success: Device owner set to package ComponentInfo{com.testkiosk/com.testkiosk.receiver.DeviceAdminReceiver} Active admin set to component {com.testkiosk/com.testkiosk.receiver.DeviceAdminReceiver} [/sourcecode] |
Googleアカウントが設定されていたり、deviceOwnerに指定するDeviceAdminReceiverの指定を間違えていたりすると下記のように失敗します。 その場合は、端末を一旦初期化するなどして、できる限り端末を設定していない状態でやるとうまくはずです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[sourcecode lang="php"] $ adb shell dpm set-device-owner com.testkiosk/.receiver/DeviceAdminReceiver usage: dpm [subcommand] [options] usage: dpm set-active-admin [ --user <USER_ID> | current ] <COMPONENT> usage: dpm set-device-owner [ --user <USER_ID> | current *EXPERIMENTAL* ] [ --name <NAME> ] <COMPONENT> usage: dpm set-profile-owner [ --user <USER_ID> | current ] [ --name <NAME> ] <COMPONENT> usage: dpm remove-active-admin [ --user <USER_ID> | current ] [ --name <NAME> ] <COMPONENT> dpm set-active-admin: Sets the given component as active admin for an existing user. dpm set-device-owner: Sets the given component as active admin, and its package as device owner. dpm set-profile-owner: Sets the given component as active admin and profile owner for an existing user. dpm remove-active-admin: Disables an active admin, the admin must have declared android:testOnly in the application in its manifest. This will also remove device and profile owners [/sourcecode] |
完成
以上で、GoogleMapしか起動できない端末の出来上がりです。
試しに再起動してもGoogleMapしか起動しません。
ステータスバーや他のアプリも無効になっているため設定画面を開いて設定を変えることもできません。
ただし、ホームボタンなどを押すとホームアプリのActivityが少し見えてしまいます。
これは適当に背景色を真っ黒にでもしたlayoutにしておけば、ユーザには気づかれないようにできるでしょう。
まとめ
今回は3rd Partyのアプリでキオスク端末化する方法をまとめてみました。
なかなかこういう要件は無いかもしれませんが、お役に立てれば幸いです。