AndroidでViewを他のアプリの上に表示する (APIバージョン別 対応方法まとめ)

  • 6
    Like
  • 0
    Comment

久しぶりにAndroidのコードを書いていたら、ビューを他のアプリに重ねて表示しようとして盛大に躓いたのでメモ。
要点だけ抜き出しているので、細かなコードは参考サイトとして挙げているリンク先を参照のこと。

Android 4.0 ~ 5.0 (APIレベル 14~22)

  • AndroidManifestにパーミッションを記述する
AndroidManifest.xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  • WindowManager#addViewする

LayoutParams生成時のレイヤータイプ(コンストラクタのint _type変数)に、WindowManager.LayoutParams.TYPE_SYSTEM_ALERT を渡す。

参考サイト : 画面上にアプリの情報を常時表示する

Android 6.0 ~ 7.1.1 (APIレベル 23~25)

Android 5.0までの対応に加えて以下の対応が必要。

  • RuntimePermissionに対応させる

APIが更新され、一部のパーミッションは個別にユーザが許可を出すことを求められるようになった。

まずは、Settings#canDrawOverlays を呼び出して、アプリの権限をチェックする。

権限がない場合は、オーバーレイ権限を変更する為の画面を呼び出す。
Intentには Settings.ACTION_MANAGE_OVERLAY_PERMISSION と、自アプリのパッケージ名を指定する。
(ユーザに対して表示して、利用開始時に権限設定を許可してもらう)

権限設定画面から自アプリに制御が戻ったら再度権限を確認し、権限が有効になっていたらAndroid 5.0までと同じ方法でビューを追加する。

参考サイト : MarshmallowでSYSTEM_ALERT_WINDOWの権限の扱いが変わった

Android 8.0 ~ (APIレベル 26~)

Android 7.1.1までの対応に加えて以下の対応が必要。

  • WindowManagerでTYPE_APPLICATION_OVERLAYレイヤーを使う

APIが更新され、TYPE_SYSTEM_ALERTレイヤーは利用できなくなった。
よって、今まで通りのレイヤータイプ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT を使用するとエラーとなる。
(下記の例外が発生する。この例外で検索しても情報が見つからなくて困った)
java.lang.RuntimeException: Unable to start service com.example.app.TestService@57b8b88 with Intent { cmp=com.example.app/.TestService }: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@4938b2b -- permission denied for window type 2003

これを回避する為にはAPIレベルが26以上の場合に、LayoutParams生成時のレイヤータイプに WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY を渡すようにする。

参考サイト : Android O で WindowManager の振る舞いが変わる