アプリの休止(App hibernation)の管理ページを開く

投稿日:  更新日:

数ヶ月にわたってアプリが操作されなかった時に、アプリは休止状態(アプリの休止)になり、自動的にRuntime Permissionがリセット(削除)されます。

この機能はデフォルトで有効(On)です。

しかし、このPermissionのリセットを、良しとしないアプリが存在するかも知れません。

そのようなアプリのために、管理ページからユーザによって機能を無効(Off)にできます。

また、プログラム中から管理ページへユーザを誘導できます。

この「管理ページへユーザを誘導する方法」を紹介します。デベロッパーブログにも紹介されています。

スポンサーリンク

休止の判定解除

自動的なPermissionのリセットは「アプリの休止」になることで行われます。

ですので、「アプリの休止」に成らないように、休止の判定を解除します。つまり、「アプリの休止」を無効(Off)にします。

管理ページからユーザの手によって切り替えが可能です。

API23~29API30API31
アプリの休止の判定解除
アプリの休止の判定解除
アプリの休止の判定解除
スポンサーリンク

管理ページの場所

管理ページの場所は端末で稼働しているAndroidのバージョンと、アプリがビルドされた時のtargetSDKの関係により異なります。

端末のOStargetSDK休止の影響管理ページ 
≧Android12
(API31)
≧31Permissionの取得をリセット
一時データ(キャッシュ)のクリア
「アプリ情報」
Android11
(API30)
 30Permissionの取得をリセット
Android6~10
(API23~29)
「Playプロテクト」
※休止の仕様をAPI<30へバックポート(移植)、Google Play Service+Play Storeで実現
スポンサーリンク

環境設定

管理ページを開くための関数・メソッド(後述)が用意されています。

この関数・メソッドを利用するために、次のライブラリをdependenciesへ追加します。

dependencies {
          :
    implementation "androidx.concurrent:concurrent-futures-ktx:1.1.0"
//  implementation "androidx.concurrent:concurrent-futures:1.1.0"
          :     ↑↑上記の2つのどちらか
}

concurrent-futuresはGuavaライブラリのListenableFutureをAndroid用に実装したものです。※Guava:Googleが開発しているJava向けのライブラリ群

ListenableFutureは非同期処理を効率的に記述するための関数です。非同期処理の結果をコールバックで返すことが出来ます。

スポンサーリンク

休止の状態を確認

「アプリの休止」が無効(Off)の状態であれば、管理ページを開く意味はありません。無効にするために管理ページを開くからです。

ですので、先に現在の状態を確認します。

PackageManagerCompat#getUnusedAppRestrictionsStatus( )が確認するメソッドです。このメソッドは次のようなパラメータを返します。

パラメータ休止の状態概要
ERROR無効(Off)状態を取得できない
・targetSDK<30
・ユーザロック中(パターン、PINなどにより)
FEATURE_NOT_AVAILABLEサポートされていない
・API23~29の端末でバックポートされた環境にない
DISABLEDサポートされている
API_30_BACKPORT有効(On)サポートされている
・API23~29の端末でバックポートされた環境にある
API_30サポートされている
・API30で導入
(Permissionの自動リセット)
API_31サポートされている
・API31で導入
(Permissionの自動リセット、キャッシュのクリア)
※パラメータ:UnusedAppRestrictionsConstants.XXX
※API23~29はバックポートされた環境で「アプリの休止」を実現

以下の例は、有効(On)の時のみ管理ページを開く処理(Dialogの表示)を行っています。

                      :
            val future: ListenableFuture<Int> = getUnusedAppRestrictionsStatus(this)
            future.addListener({
                val _appRestrictionsStatus = future.get()
                when (_appRestrictionsStatus) {
                    ERROR -> { }
                    FEATURE_NOT_AVAILABLE -> { }
                    DISABLED -> { }
                    API_30_BACKPORT, API_30, API_31 -> {
                        showHibernationDialog(this@MainActivity)
                    }
                }
            }, ContextCompat.getMainExecutor(this@MainActivity)) // Mainスレッドで処理
			          :

ListenableFutureを利用して、状態の確認が非同期で行われている点に注意してください。

API23~29の端末ではGoogle Play Serviceが「アプリの休止」の動作を担っています。

ですので、状態を取得するために、Google Play Serviceとアプリ間の通信(コンポーネントの呼出⇒処理に時間がかかる)が必要になるためです。

スポンサーリンク

管理ページを開く

突然、管理ページを開いても、ユーザは理由を理解できない可能性があります。

ですので、管理ページを開く前に無効化する理由をダイアログで表示し、説明します。

IntentCompat#createManageUnusedAppRestrictionsIntent( )が管理ページのIntentを作成してくれます。

後は、Intentを発行するだけで、管理ページが開きます。

    fun showHibernationDialog(context: Context) {
        AlertDialog.Builder(context).apply {
            setTitle(R.string.hibernation_dialog_title)
            setMessage(R.string.hibernation_dialog_text)
            setPositiveButton(R.string.hibernation_dialog_pos) { dialog, which ->
                val _intent = IntentCompat.createManageUnusedAppRestrictionsIntent(
                    context, packageName)
                startActivity(_intent)
            }
            setNegativeButton(R.string.hibernation_dialog_neg) { dialog, which ->
                dialog.dismiss()
            }
        }.create().show()
    }
API23~29API30API31
管理ページを開く
管理ページを開く
管理ページを開く

デベロッパーブログは「startActivityForResult( )を使う必要がある!」と書かれていますが、ここでは無視してstartActivity( )を用いました。ブログの発言の理由が不明ですし、そもそも、startActivityForResult( )は非推奨です。

スポンサーリンク

関連記事:

Androidは携帯端末のOSで、スマートフォンに適しています。 スマート(Smart)とは「賢い・洗練された」といった意味を持つ形容詞です。 Androidはこの「スマート」をユーザ自身の手で育てることが出来ます。 どのように育てるのか! それは世界中の開発者からリリースされているアプリをインストールして育てます。 より高機能なアプリ、より使い勝手の良いアプリを探してインストールすれば、あなたのスマートフォンはもっと「スマート」になるでしょう! しかし、アプリは良心的なものばかりではありません。中には悪意を持ったアプリも存在します。 悪意を持ったアプリから、ユーザを守る仕組みの1つがPermissionです。 ここまではユーザ目線でした。 逆にアプリの開発者目線で言えば、Permissionはアプリの安全性をユーザにアピールする手段でもありあます。 今回は、このPermissionについてまとめます。 ...
続きを読む
Install-time(Normal)Permissionの取得方法についてまとめます。 Permissionの詳細は「Permissionとその一覧」を参照してください。 ...
続きを読む
Runtime(Dangerous)Permissionの取得方法についてまとめます。 現在、Runtime Permissoinの取得方法は2つあります。 ここで紹介するのはRuntime Permission(API≧23)が登場した当初から存在している方法です。 この方法は、リクエスト(Permissionの申請)の結果を共用のコールバックAppCompatActivity#onRequestPermissionsResult( )で受け取ります。複数のリクエスト行うと、複数の結果を一つのコールバックで受けることになり、コールバック内でRequestCodeによる分岐が必要になります。 つまり、「開発者がリクエストを管理」しなければなりません。 Permissionの詳細は「Permissionとその一覧」を参照してください。 ...
続きを読む
Runtime(Dangerous)Permissionの取得方法についてまとめます。 現在、Runtime Permissoinの取得方法は2つあります。 ここで紹介するのは、ActivityResultContracts(※)を使う方法です。 この方法は、リクエスト(Permissionの申請)と結果を受け取る専用のコールバックが1対1に対応しています。ですので、複数のリクエストを行っても、RequestCodeによる分岐処理は必要ありません。システムが結果を各コールバックへ割り振ってくれます。 つまり、「システムがリクエストを管理」してくれます。 ドキュメントで推奨されている方法です。 Permissionの詳細は「Permissionとその一覧」を参照してください。 ※ライブラリandroidx.activity:activity≧1.20が必要 ...
続きを読む
パーミッションシステムの仕様変更がAPI≧30で行われています。  (1)1回だけアクセス許可  (2)“今後表示しない”の非表示  (3)アプリの休止 ここでは、「(1)1回だけアクセス許可」について説明します。 ...
続きを読む
パーミッションシステムの仕様変更がAPI≧30で行われています。  (1)1回だけアクセス許可  (2)“今後表示しない”の非表示  (3)アプリの休止 ここでは、「(2)“今後表示しない”の非表示」について説明します。 ...
続きを読む
パーミッションシステムの仕様変更がAPI≧30で行われています。  (1)1回だけアクセス許可  (2)“今後表示しない”の非表示  (3)アプリの休止 ここでは、「(3)アプリの休止」について説明します。 ...
続きを読む
「アプリの休止(App hibernation)」は発動までの期間が長いので、端末上で実際にその動作を確認しようとすると、待機時間が長くなってしまい、効率が悪いです。 ですので、テストでは「アプリの休止」を手動で発動させます。 今回は、この手動で発動させる方法を説明します。 ...
続きを読む
スポンサーリンク