インストール済アプリがピックアップできないAndroid 12

2022年7月19日

開発環境
OS:Windows 10
SDK:Android Studio Chipmunk | 2021.2.1

概要

Android 12におけるセキュリティ強化。
それに伴い、権限なしにインストール済アプリをピックアップすることができなくなってました、という話です。

スマホの機種変更

androidアプリ開発をしている以上もちろんAndroid 12での動作検証も行います。

とは言っても検証はもっぱら仮想デバイスでした。

それが最近、スマホを買い替え、ようやくAndroid 12の実機が我が手元に。

生でAndroid 12に触れる機会ができたので早速、アプリを色々と動かしてみたのですが。。。

早々と想定通りに動作していない機能を発見、慌てて改修した次第です。

仮想デバイスでは検証しにくい機能なんです。。。

Android12のセキュリティ強化

想定通りに動作しなかった機能とは何か?

それは、インストール済アプリのピックアップ機能です。

コードで表すと Packagemanager の getInstalledPackages です。

Android 12のセキュリティ強化に伴い、権限、もしくは、<queries>定義なしに

インストール済アプリをピックアップできなくなった、とのこと。

この機能がダメになるとランチャー系のアプリは全滅です。

そこで2パターンの方法で改修を行いました。

パターン1)どうしてもインストール済アプリを全て知りたい

ランチャー系アプリの場合、インストール済アプリを全てピックアップしたいので権限追加で対応します。

AndroidManifest.xmlに以下のパーミションを追加します。

<uses-permission android:name=”android.permission.QUERY_ALL_PACKAGES”/>

対応は以上です。

あとはビルドしてリリースするだけなのですが、なにせ強力な権限です。

Google Play Consoleの「アプリのコンテンツ」において権限の用途を説明する必要があります。

Google Play Console「アプリのコンテンツ」

まずは目的の説明を記載し、そして、用途の選択を行います。

機密情報にかかわる権限とAPI(1)

ランチャーアプリの場合、

目的は「ランチャーアプリ。アプリリストを表示するため」、

用途は「アプリの機能」、と明確です。

そして、最後に求められるのが動画です。

機密情報にかかわる権限とAPI(2)

ざっくりと作ってYouTubeにアップしてみました。

まさか動画を求められるとは。。。

すると、まあ、なんということでしょう。

リリースしてから1時間もしないうちに審査が通り、インストールできるようになりました。

パターン2)必要なアプリだけインストールされていることを知りたい

アプリの連携のため、連携対象のアプリがインストールされているか知りたい。

そのような場合、

AndroidManifest.xmlに以下の定義を追加します。

(アプリ”com.sample.application”がインストールされているか知りたい場合)

<manifest ・・・>

    <queries>
        <package android:name="com.sample.application" />
    </queries>

    <application ・・・

    </application>

</manifest>

これで Packagemanager の getInstalledPackagesまわりは改修しなくても対象アプリをピックアップしてくれるようになります。

あとはビルドしてリリースするだけです。

こちらのパターンの場合、Google Play Consoleで「アプリのコンテンツ」を記載する必要もありません。

Android 12のセキュリティ強化に伴う対応は以上です。

今月のみてみて(2022年6月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseのアクセス動向やアプリの改善を考察する開発記事です。

Realtime Database+Storage構成の投稿アプリ

アプリの新規獲得ユーザー数の変動とともにFirebaseのアクセス動向を確認します。

2022年6月1日~6月30日の新規獲得ユーザー数

(ユーザー数の変動)

1ヶ月の新規獲得ユーザー数

今月もインストール数は伸びています。

先月と比べ、新規獲得ユーザー数は約1.5倍、先々月と比べると2倍です。

ユーザー減少数について述べるのは・・・止めておきます。

(インストールの上位国)

フィリピンのインストールが伸び率が圧倒的です。

フィリピンは英語とフィリピン語が公用語。

アプリとしては多言語化対応(英語、インドネシア語、ロシア語)しているのですが、

GooglePlayのストア表示は日本語、英語の2言語対応のみ。

このあたり、英語に馴染みがあるかどうかがインストール数に影響しているのかもしれないですね。

ストア表示にも対応してみようかと思います。

(Firebaseの変動)

まだ微々たるものですが、それでも先月と比べ、ダウンロード量が約3倍。

実際にアプリの起動が少し遅く感じるようになりました。

今のうちにアプリの起動シーケンスを見直してみようかと思います。

(今週の投稿ピックアップ)

フィリピンの公園(広場?)を投稿してもらいました。

木陰が恋しい時期になってきましたね。

(今後の改善案)

ようやく改修案件も落ち着いてきたので前からの課題、2件に着手したい。。。

①UIの改善。

②ベースアーキテクチャのデファクタリング。

それと今回新たに必要性を感じた2件。

③GoolePlayストアの多言語化対応。

④アプリ起動シーケンスの見直し。

計4件の消化が今月の目標です。

,

Android Studioを更新したら起動しなくなった話

2022年6月13日

開発環境
OS:Windows 10
SDK:Android Studio Bumblebee | 2021.1.1

概要

全ては日本語化パッチに通ずる。

Android Studioを更新する

さて、アプリの改修でも行おう。と、Android Studioを起動するとたまに出る右下のポップアップ。

kotlinのバージョンアップ通知、emulatorのバージョンアップ通知、などなど。

バージョンアップを促してくるわけですが、基本的には見かけたらすぐにバージョンアップしています。

ですが、ただ1つ、Android Studioのバージョンアップだけは慎重になります。

なぜならだいたいバージョンアップをすると問題が発生するからです。

なので、Android Studioのバージョンアップだけは時間的に余裕のあるときに実施するわけです。

そして、今日。

ハチからリスにバージョンアップした結果がこれです。

やはりハマってしまいました。

バージョンアップ時に発生する問題はたいてい日本語化対応による弊害。

対処法は2つ。

①日本語化パッチを当てなおす。

②再インストールする

①を実施、それでも駄目なら②を実施。

今までもこれで乗り切ってきたわけです。

それが今回、①、②、どちらを実行してもエラーが解除されない事態に。。。

そこで “Could not find main class com/intellij/idea/Main” で検索しみると。

stackoverflowなどでも検索結果がヒットするものの、解決策を見ると環境変数JAVA_HOMEの設定が~。

どうやら的外れ。

そこで基本に立ち戻り、日本語化を解除してみました。

C:\Users\~\AppData\Roaming\Google\AndroidStudio2021.2\studio64.exe.vmoptions

上記ファイルの最下段、”-Xverity”と”-javaagent:~plaiades.jar”をコメントアウト。

すると、あっさり起動しました。

日本語化パッチ、またやりおったか。

今月のみてみて(2022年5月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseのアクセス動向やアプリの改善を考察する開発記事です。

Realtime Database+Storage構成の投稿アプリ

アプリの新規獲得ユーザー数の変動とともにFirebaseのアクセス動向を確認します。

2022年5月5日~6月4日の新規獲得ユーザー数

(ユーザー数の変動)

1ヶ月の新規獲得ユーザー数

先月と比べ、新規獲得ユーザー数は約1.5倍となりました。

そして、それに比例して減少数も約1.5倍。。。

この1ヶ月、何も対策をしていないので致し方なし。

(インストールの上位国)

先月に引き続き、フィリピン、そして、インドネシアとランクイン。

なぜインストールしてくれるのか分からないが、ありがたい。

そして、ロシアが圏外となり、トルコ、アメリカが上位ランキングに初登場。

(と言ってもインストール数1人でしょうか。。。

今回も多言語化対応は特に考えておりません。

(Firebaseの変動)

新規インストール数が増えた割にはFirebaseのアクセスは伸びていません。

そう、投稿がほとんどないわけです。

まだ慌てる時じゃあないようです。

(今週の投稿ピックアップ)

韓国料理屋が近所にオープンするみたい。

(楽しみにしてます

海外ユーザーさんもたまに投稿してくれるのですが、なぜか床や壁の投稿。

なぜなんでしょう。。。

(今後の改善案)

先月から引き続き、下記2件の改善を検討。

①UIの改善。

②ベースアーキテクチャのデファクタリング。

ステップ分けしてでも今月中には1度リリースしたい。

,

ファミリーポリシー違反がやって来たヤァ!ヤァ!ヤァ!

概要

神経衰弱を題材にしたミニゲーム”サイキック・パワー”、
このアプリは対象年齢を0歳以上(全ユーザー対象)としており、ファミリーポリシーの遵守が必須です。

ですが、アプリに連携させているAdmobがファミリーポリシー違反をやらかしたそうで。。。

唐突にファミリーポリシー違反通知がメールに送られてきました。

内容としては、アプリがファミリーポリシーに違反しており、Google Playからアプリを削除したとのこと。

このアプリでのポリシー違反指摘は初めてです。

ですが、過去にも何度かファミリーポリシー違反となったことはあります。

その度にAdmobのイニシャル処理とリクエスト処理を改善したり、Admob設定を変更したりと対応してきました。

そして、ファミリーポリシーに則る必要のあるアプリ全てに水平展開もしてきたのですが。

(ファミリーポリシーを遵守するためのAdmobコーディングについてはこちらの記事。)

(ファミリーポリシーを遵守するためのAdmob設定についてはこちらの記事。)

それでは今回の理由は何なのか?

Admobの配信設定を見直す

ファミリーポリシー違反の理由がこちらでした。

審査結果通知

ファミリーポリシー違反の理由は2点。

1つ目は、広告のフォーマット違反。
広告表示から5秒後に広告を閉じることができなかった、とのこと。

2つ目は、広告のコンテンツ違反。
Admobから配信されている広告に子供にふさわしくないコンテンツが含まれていた、とのこと。

そこで配信設定の見直しを行います。

まず1つ目は5秒ルールの遵守。

アプリにはインタースティシャル広告、バナー広告を設置しているのですが、インタースティシャル広告と5秒ルールの相性が悪そうでした。

そこでインタースティシャル広告の配信から動画を削除しました。

そして、2つ目は広告のコンテンツ違反です。

メールに添付されていた違反広告の画像を見るとギャンブル系のゲーム広告のようです。

そこでブロックのコントロール設定を変更することにしました。

Google Admob コンソール

まずはGoogle Admobコンソールを表示して広告配信を制御したいアプリを選びます。
そして、メニューの「ブロックのコントロール」を選択。

Google Admob コンソール

次に一般カテゴリを選択し、ふさわしくないと思われる「レジャー/ギャンブル」の配信をブロックしました。

あとは、再審査を促すため、バージョンのみを変更したアプリを再リリース。

再審査の結果、合格となりました。

しばらくは様子見となりそうです。

今月のみてみて(2022年4月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseのアクセス動向やアプリの改善を考察する開発記事です。

Realtime Database+Storage構成の投稿アプリ

アプリの新規獲得ユーザー数の変動とともにFirebaseのアクセス動向を確認します。

2022年4月1日~4月30日の新規獲得ユーザー数

(ユーザー数の変動)

1ヶ月の新規獲得ユーザー数

先月と変わらず穏やかな波を描いていますが、直近2日ほど1日のインストール数が10人を超える日が続いているのでこの後の動向に注視したいところです。

ただし、ユーザー減少数の波とインストール数の波がシンクロしており、アプリの魅力を伝えられていないというのは相変わらず。

(インストールの上位国)

先月に引き続きフィリピン、インドネシアと続き、ロシアが再び、ランクイン。

リリース初期のインストール上位3ヵ国で継続してインストールしてもらっているようです。

そして、新たにブラジルがランクインです。

来月もインストール数が伸びるようなら多言語化対応としてポルトガル語を対応したいと思います。

(Firebaseの変動)

ようやくMBの領域になってきましたが、いかんせん投稿数が少ないのでなんとも言えないですね。

まだしばらくはFireBaseのアクセスに関して懸念すべき点はなさそうです。

(今週の投稿ピックアップ)

各国の投稿を増やしたいとの思いで国旗を各国の
日本大使館近くに投稿してみました。

(今のところ反応は薄いです。。。

(今後の改善案)

基本的なコミュニケーション機能は一通り実装してみたのであとは如何に投稿してもらえるようにするかが考え所です。

①世界中の投稿数を増やす。

②UIの改善。

③ベースアーキテクチャのデファクタリング。

改善案として3点あげましたが、③は少し大掛かりになりそうなので、まずは①と②を少しずつ進めていこうと思います。

,

ファミリーポリシーを遵守するためのAdmob設定

概要

ヒットアンドブローを題材にしたミニゲーム”サムライロード”、
このアプリは対象年齢を10歳以上としており、ファミリーポリシーの遵守が必須です。

そのため、Admobのイニシャル処理とリクエスト処理に子供向け設定を入れていたのですが、アプリの更新審査のタイミングでファミリーポリシー違反となりました。
(ファミリーポリシーを遵守するためのAdmobコーディングについてはこちらの記事。)

なぜ?

Admobの配信カテゴリを設定する

アプリの更新審査に落ちた理由がこちらです。

審査結果通知

Admobから配信されている広告に子供にふさわしくないコンテンツが含まれていた、とのこと。

テレビ、動画、音楽、その他情報配信系の広告を表示するとファミリーポリシー違反となるようです。

そこで、Admob側の設定を変更することにしました。

Google Admob コンソール

まずはGoogle Admobコンソールを表示して広告配信を制御したいアプリを選びます。
そして、メニューの「ブロックのコントロール」を選択。

Google Admob コンソール

次に一般カテゴリを選択し、ふさわしくないと指摘されたテレビ、動画、音楽の配信をブロックしました。

あとは、再審査を促すため、バージョンのみを変更したアプリを再リリース。

再審査の結果、合格となりました。

今月のみてみて(2022年3月)

Firebase連携アプリ、みてみてエストーク伊勢125社巡り

このうち、みてみてにフォーカスを当て、Firebaseの動きやアプリの改善を考察する開発記事です。

Realtime Database+Storage構成の投稿アプリ

2022年2月21日~3月22日の変動

アプリのユーザー数の変動とともにFirebaseの動きを確認します。

(ユーザー数の変動)

1ヶ月の新規獲得ユーザー数

今月も大きな動きはありません。

OUTよりINが多いのがせめてもの救い。

(インストールの上位国)

引き続きフィリピン、インドネシアが上位となっています。

そして、新たにコロンビア、サウジアラビア、香港がランクインしました。

前回は上位3か国(フィリピン、インドネシア、ロシア)のユーザーへのアプローチとして、インドネシア語、ロシア語の多言語化に取り組みました。
(フィリピンは英語が公用語となっているため、対応済み)

残念ながらロシアへのアプローチは失敗したようです。

今回の多言語化は保留です。

(Firebaseの変動)

今月もユーザー数の伸びがないため、想定内の緩やかな変動となっています。

無料プランで維持できる状況です。

(今週の投稿ピックアップ)

ポケモンのマンホールが伊勢に設置されました!
ポケストップができるのが待ち遠しい。

投稿がないので自身の投稿です。(^^;

(今後の改善案)

前回挙げておいて対応できなかったコミュニケーション機能の追加。

これをなんとか入れたい。

あとは投稿がないなら、まずは自身で投稿してみよう!

ということで世界各地に幾つか投稿してみます。

何を投稿するか?となると写真などは著作権の問題もある。

となると投稿するならあれでしょうか。

世界情勢もあるのでそこも訴えたいですね。

,

Googleマップが表示されない事象の発生から解決まで

概要

2022年3月9日早朝、自作アプリ“みてみて”を起動したところ、Googleマップが表示されないことに気付く。

慌ててGoogleマップを使用している自作アプリを片っ端から起動した結果、全滅でした。

なぜGoogleマップが表示されなくなったのか?

事象の発生から解決までの道のりを記事にしました。

Noアプリ名事象発生当時の最終リリース日
みてみて2022年2月24日
伊勢125社巡り2022年2月5日
伊勢テイクアウトなび2020年6月4日
みまもってね2022年1月15日
Googleマップが表示されなくなったアプリ一覧
伊勢125社巡り
マップ表示(改修前)
みてみて
マップ表示(改修前)

Googleマップの実装

最初に自作アプリにGoogleマップをどう実装しているかをざっくり説明します。

まず始めにデフォルトのMapsActivityを追加します。

ただし、そのままだとフラグメントのみの構成のため、ConstraintLayoutに組み込むようレイアウトを変更します。

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/constraint_map">
        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

Activity側のベースロジックは変更しません。

あとはGoogle Cloud Platformでプロジェクトを作成し、APIの有効化でMaps SDK for Androidを選択。

APIキーを入手後、AndroidManifest.xmlのメタデータにAPIキーを定義します。

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="MAP_API_KEY" />

最後にMapsActivityのタイトルを非表示にするため、Activityにスタイルを設定して完成です。

マップ表示は基本的に”com.google.android.gms.maps.SupportMapFragment”まかせの処理としています。

突然Googleマップが表示されなくなった

自作アプリは随時、改修を行っています。

今回問題が発生したアプリも2022年2月24日に改修してリリースしたものがありました。

もちろんリリース前に動作確認しており、そのときにはマップ表示に問題がなかったのです。

それから約2週間後、突然Googleマップが表示されなくなりました。

つまりアプリに手を加えていないタイミングでマップが表示されなくなったということです。

そうなるとまずはアプリ内部の処理ではなく外部を疑いたくなるものです。

解決までの道のり

まず疑ったのはマップデータが受け取れてないのでは?ということです。

GoogleマップAPIが使えなくなっていないか?

Google Clound Platformでプロジェクトの設定やAPIキーの制限を確認しますが問題ありませんでした。

次にGoogleマップの表示だけを行うサンプルアプリを作成し、APIキーを使ってみます。

するとGoogleマップが表示されました。

GoogleマップAPIは正常に機能していたわけです。

確かにGoogle Clound PlatformでAPIのトラフィックを確認するとアプリではマップが表示されてないにも関わらず、データ通信は発生していました。

伊勢125社巡りのAPI(Map SDK for Android)のトラフィック

マップデータは受け取れている。となると次はアプリ内部の処理を疑わざるおえません。

アプリをデバッグモードで起動し、試しにデフォルトのMapsActivityを追加してみます。

そして、アプリを動かしてみると。。。

デフォルトのMapsActivityにGoogleマップが表示されました。

そうなるとデフォルトのMapsActivityと作り込んだMapsActivityの違いを調べるだけです。

デフォルトのMapsActivityにコードを徐々に追加し、マップが表示されなくなるか確認。

なんと最後までGoogleマップは表示されました。

つまり、MapsActivityのコード内容には問題がなかったわけです。

あと違いがあるのは何か?

ここでスタイル設定に気が付きます。

デフォルトのMapsActivityにタイトル非表示用に定義したスタイルを設定してみると。。。

Googleマップが表示されなくなりました。

そう、原因はスタイル定義だったんです。

ちなみに問題となったスタイルが以下です。

    <style name="AppTheme.NoTitleStatus" parent="@style/Theme.AppCompat.NoActionBar">
        <item name="android:background">@color/colorBackground</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">false</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

このなかで問題を引き起こしたのがバックグランド設定でした。

事象から察するにマップフラグメントがバックグランドの裏に隠れるようになったのではないでしょうか。

今回の改修案としてはバッググランド設定を透明に変更したスタイルを新たに用意。

それをMaspActivityに設定することで解決しました。

それにしてもまさかアプリ内部処理が要因だったとは・・・

伊勢125社巡り
マップ表示(改修後)
みてみて
マップ表示(改修後)

後書き

今回の件で一番驚いたのはアプリ内のライブラリのバージョンを上げたり、コードを変更したりすることなく、Googleマップが表示されなくなったことです。

アプリの更新を行わずにアプリの挙動が変わるとは思っていなかったため、最初は外部要因(マップAPIのIF依存)だとばかり思っていました。

結局、今回の事象の真の要因は何かは分からないですが、アプリ自体を更新しなくてもアプリの挙動が変わってしまうことがあるというのは勉強になりました。

ファミリーポリシーを遵守するためのAdMobコーディング

概要

Google Playでアプリをリリースする際に設定するアプリの対象年齢(ターゲットユーザー)。

今回はアプリの対象年齢に13歳未満を含める場合に必要となるAdMobのコーディングについて記事にしました。

AdMobに子供向け広告をリクエストする

GooglePlayで設定するアプリの対象年齢は以下のように分かれています。

No対象年齢ファミリー向けプログラム
15歳以下必須
26~8歳必須
39~12歳必須
413~15歳任意
516~17歳任意
618歳以上任意
ターゲットユーザー設定

ターゲットユーザーの設定としては13歳以上か、13歳未満かが大きな分岐点となります。

なぜなら13歳未満をターゲットに含める場合は

ファミリーポリシーを遵守するために子供向けの広告を表示することが求められるからです。

では、子供向けの広告を表示するにはどうすればよいのか?

Admobのヘルプを調べると下記のコードが示されていました。

Bundle extras = new Bundle();
extras.putString("max_ad_content_rating", "G");
AdRequest request = new AdRequest.Builder()
 .addNetworkExtrasBundle(AdMobAdapter.class, extras)
 .tagForChildDirectedTreatment(true) .build();

ただし、これを実際にコーディングしようとしても

tagForChildDirectedTreatmentメソッドが見つかりません

どうしたものかとネット検索してみた結果、タグ指定はイニシャル処理にあわせて実行するのがよさそうだという結論に至りました。

通常のAdMobイニシャル処理

MobileAds.initialize(this)

子供向けのAdMobイニシャル処理

val requestConfiguration = MobileAds.getRequestConfiguration().toBuilder()
    .setTagForChildDirectedTreatment(TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE)
    .setMaxAdContentRating(MAX_AD_CONTENT_RATING_G)
    .build()
MobileAds.setRequestConfiguration(requestConfiguration)
MobileAds.initialize(this)

子供向けに実装する場合は、イニシャル処理の前に子供向けタグとレーティングGを設定します。

また、AdMob表示のための広告リクエストでもレーティングGを設定しておきます。

通常のバナー広告リクエストと表示処理

val adView : AdView = findViewById(R.id.adView)
val adRequest = AdRequest.Builder().build()
adView.loadAd(adRequest)

子供向けのバナー広告リクエストと表示処理

val adView : AdView = findViewById(R.id.adView)
val extras = Bundle()
extras.putString("max_ad_content_rating", "G")
val adRequest = AdRequest.Builder().addNetworkExtrasBundle(AdMobAdapter::class.java, extras).build()
adView.loadAd(adRequest)

通常のリクエストにレーティング設定を追加すればOKです。

Admobから配信されるカテゴリを制御する方法は以下の記事を参照ください。