新しい機能に加えて、Android 7.0 では、さまざまなシステムおよび API の動作が変更されています。このドキュメントでは、アプリ開発において把握しておくべき主な変更点について説明します。
過去に Android 向けのアプリを公開したことがある場合は、そのアプリが今回のプラットフォームの変更による影響を受ける可能性があることに注意してください。
バッテリーとメモリ
Android 7.0 では、端末の電池寿命を改善したり、RAM の使用量を削減したりするために、システムの動作がいくつか変更されています。これらの変更は、特定の暗黙的インテントを介してアプリが他のアプリとやり取りする方法に加え、システム リソースへのアプリのアクセスに影響する可能性があります。
Doze
Android 6.0(API レベル 23)で導入された Doze モードは、ユーザーがデバイスを電源に接続せず、静止していて、画面がオフのときに、CPU とネットワーク アクティビティを保留してバッテリー寿命を改善します。Android 7.0 では、デバイスが電源から外され、画面がオフの状態で移動しているが、必ずしもハンドセットが静止しているとは限らない状態で、CPU とネットワークの制限のサブセットを適用することで、Doze モードをさらに強化します。
デバイスがバッテリー駆動中で、画面が一定時間オフの状態になると、デバイスは Doze モードに入り、最初の制限サブセット(アプリのネットワーク アクセスを遮断し、ジョブと同期を先送りする)を適用します。デバイスが Doze モードに切り替わった後、しばらくの間静止状態である場合、PowerManager.WakeLock
、AlarmManager
アラーム、GPS、Wi-Fi スキャンに残りの Doze 制限が適用されます。Doze 制限の一部またはすべてが適用されているかどうかに関係なく、短時間のメンテナンス時間枠のためにデバイスが復帰します。この間はアプリにネットワーク アクセスが許可され、遅延したジョブや同期を実行できます。
画面をオンにするか、端末を電源に接続すると、Doze モードは解除され、これらの処理の制限は適用されなくなります。 Doze とアプリ スタンバイ用に最適化するで説明したように、今回追加された動作は、Android 6.0(API レベル 23)で導入された以前のバージョンの Doze にアプリを対応させるための推奨事項とベスト プラクティスに影響するものではありません。Firebase Cloud Messaging(FCM)を使用してメッセージを送受信するなど、これらの推奨事項に沿いつつ、追加の Doze 動作に対応するための更新を計画してください。
Project Svelte: バックグラウンド処理の最適化
Android 7.0 では、メモリ使用量と消費電力を最適化するために、3 つの暗黙的なブロードキャストが削除されています。この変更が必要になったのは、暗黙的なブロードキャストが行われると、バックグラウンドでブロードキャストをリッスンするように登録されているアプリが頻繁に起動されるためです。これらのブロードキャストを削除すると端末のパフォーマンスとユーザー エクスペリエンスが大幅に向上します。
モバイル デバイスでは、Wi-Fi とモバイルデータの間を移動するときなど、接続が頻繁に変更されます。現在、アプリは、マニフェストで暗黙的な CONNECTIVITY_ACTION
ブロードキャストのレシーバを登録することで、接続の変化をモニタリングできます。多くのアプリがこのブロードキャストを受信するよう登録しているため、1 回のネットワーク スイッチですべてが復帰し、ブロードキャストが同時に処理されます。
同様に、旧バージョンの Android では、暗黙的な ACTION_NEW_PICTURE
ブロードキャストと ACTION_NEW_VIDEO
ブロードキャストをカメラなどの他のアプリから受信するよう登録できました。ユーザーがカメラアプリで写真を撮ると、これらのアプリがアクティブになり、ブロードキャストが処理されます。
Android 7.0 では、こういった問題を軽減するために、以下の最適化手法が適用されます。
- Android 7.0(API レベル 24)以降を対象とするアプリは、マニフェストでブロードキャスト レシーバを宣言している場合は、
CONNECTIVITY_ACTION
ブロードキャストを受信しません。BroadcastReceiver
をContext.registerReceiver()
に登録し、そのコンテキストがまだ有効な場合、アプリは引き続きCONNECTIVITY_ACTION
ブロードキャストを受信します。 - システムは
ACTION_NEW_PICTURE
ブロードキャストまたはACTION_NEW_VIDEO
ブロードキャストを送信しなくなりました。この最適化は、Android 7.0 を対象とするアプリだけでなく、すべてのアプリに影響します。
アプリでこれらのインテントのいずれかを使用する場合は、Android 7.0 端末でも適切に動作するように、可能な限りインテントとの依存性を削除する必要があります。Android フレームワークでは、非明示的ブロードキャストの必要性を緩和する方法がいくつかあります。たとえば、JobScheduler
API は、従量制ではないネットワークへの接続など、指定された条件のときに、ネットワーク操作をスケジュールするための堅牢なメカニズムを提供します。JobScheduler
を使用して、コンテンツ プロバイダの変更に対応することもできます。
Android 7.0(API レベル 24)でのバックグラウンド処理の最適化と、アプリで必要となる対応の詳細については、バックグラウンド処理の最適化をご覧ください。
権限の変更
Android 7.0 では、アプリに影響を及ぼす可能性のあるパーミッションが変更されています。
ファイル システムのパーミッションの変更
プライベート ファイルのセキュリティを強化するために、Android 7.0 以降をターゲットとするアプリのプライベート ディレクトリにはアクセス制限があります(0700
)。この設定により、サイズや存在など、プライベート ファイルのメタデータの漏洩を防ぐことができます。この権限の変更には、次のような複数の副作用があります。
-
プライベート ファイルの所有者はこのファイル パーミッションを緩和することができず、
MODE_WORLD_READABLE
やMODE_WORLD_WRITEABLE
を使用してこれを実行しようとすると、SecurityException
がトリガーされます。注: 現在のところ、この制限は完全には適用されていません。アプリはネイティブ API や
File
API を使用して、プライベート ディレクトリのパーミッションを変更できる場合があります。ただし、プライベート ディレクトリのパーミッションを緩和できないようにすることを強くおすすめします。 -
パッケージ ドメイン外の
file://
URI を渡すと、レシーバーがアクセスできないパスになる可能性があります。そのため、file://
URI を渡そうとすると、FileUriExposedException
がトリガーされます。プライベート ファイルのコンテンツを共有するには、FileProvider
を使用することをおすすめします。 -
DownloadManager
では、ファイル名でプライベートに保存されたファイルを共有することはできなくなりました。以前のアプリでCOLUMN_LOCAL_FILENAME
にアクセスした場合、このパスにアクセスできないことがあります。Android 7.0 以降を対象とするアプリが、COLUMN_LOCAL_FILENAME
にアクセスしようとすると、SecurityException
がトリガーされます。ダウンロードの場所をDownloadManager.Request.setDestinationInExternalFilesDir()
またはDownloadManager.Request.setDestinationInExternalPublicDir()
を使用してパブリックな場所に設定する以前のアプリは、COLUMN_LOCAL_FILENAME
でこのパスにアクセスできますが、このメソッドは使用しないことを強くおすすめします。DownloadManager
で公開されているファイルにアクセスする場合は、ContentResolver.openFileDescriptor()
を使用することをおすすめします。
アプリ間のファイルの共有
Android 7.0 をターゲットとするアプリの場合、Android フレームワークはアプリ外への file://
URI の公開を禁止する StrictMode
API ポリシーを適用します。ファイル URI を含むインテントがアプリから離れると、アプリは FileUriExposedException
例外で失敗します。
アプリ間でファイルを共有するには、content://
URI を送信して、この URI に一時的なアクセス パーミッションを付与する必要があります。この権限を付与する最も簡単な方法は、FileProvider
クラスを使用することです。権限とファイルの共有の詳細については、ファイルの共有をご覧ください。
ユーザー補助機能の改善
Android 7.0 には、低視力のユーザーまたは視覚障害のあるユーザー向けのプラットフォームのユーザビリティを改善するための変更がいくつか追加されています。通常は、これらの変更によってアプリのコードを変更する必要はありませんが、この機能について理解し、アプリでテストして、ユーザー エクスペリエンスに与える潜在的な影響を評価する必要があります。
画面のズーム
Android 7.0 では、ディスプレイ サイズを設定して、画面上のすべての要素を拡大または縮小することができるので、視覚障害のあるユーザーに対する端末のユーザー補助機能が向上しています。ユーザーは、一般的な中くらいのサイズの携帯端末 Nexus 4 の幅である sw320dp の画面最小幅を超えて画面をズームできません。
端末の画面密度が変更されると、以下の方法で実行中のアプリに通知されます。
- アプリが API レベル 23 以前をターゲットにしている場合は、すべてのバックグラウンド処理が自動的に強制終了します。つまり、ユーザーがそのようなアプリから切り替えて設定画面を開き、[表示サイズ] の設定を変更すると、メモリ不足の場合と同じようにアプリが強制終了されます。アプリになんらかのフォアグラウンド処理がある場合は、実行時の変更の処理に記載されている設定変更の処理が通知されます。これは、端末の画面の向きが変わったときの処理と同様です。
- Android 7.0 をターゲットとするアプリの場合、実行時の変更の処理で説明されているように、アプリのすべてのプロセス(フォアグラウンドとバックグラウンド)に構成の変更が通知されます。
Android のベスト プラクティスに従っているほとんどのアプリでは、この機能をサポートするための変更を加える必要はありません。具体的な確認事項は次のとおりです。
- 画面幅
sw320dp
の端末でアプリをテストして、適切に機能することを確認します。 - デバイスの構成が変更された場合、キャッシュ済みのビットマップやネットワークから読み込まれるリソースなど、画面密度に依存するキャッシュ情報を更新してください。また、アプリが一時停止状態から再開された場合は、設定変更をチェックしてください。
注: 設定に依存したデータをキャッシュに保存する場合は、そのデータ用の適切な画面サイズやピクセル密度など、関連するメタデータを含めることをお勧めします。このメタデータを保存しておくと、設定を変更した後、キャッシュ データを更新する必要があるかどうかを決定できます。
- ピクセル単位は画面密度に対応しないため、ピクセル単位で寸法を指定することは避けてください。代わりに、密度非依存ピクセル(
dp
)単位で寸法を指定します。
セットアップ ウィザードの [Vision Settings]
Android 7.0 のウェルカム画面のビジョン設定では、ユーザーは新しいデバイスで拡大操作、フォントサイズ、表示サイズ、TalkBack のユーザー補助設定をセットアップできます。この変更により、さまざまな画面設定に関連するバグが顕在化する可能性があります。この機能が及ぼす影響を評価するには、これらの設定を有効にしてアプリをテストする必要があります。設定は [設定] > [ユーザー補助] にあります。
プラットフォーム ライブラリにリンクした NDK アプリ
Android 7.0 以降では、アプリが非 NDK ライブラリに対して動的にリンクできなくなるため、アプリがクラッシュする可能性があります。この動作の変更は、プラットフォームが更新されたり、さまざまな端末で使用したときでもアプリの操作感に一貫性を持たせるためです。自作のコードでプライベート ライブラリにリンクしていなくても、アプリ内のサードパーティの静的ライブラリで NDK 以外のライブラリにリンクしている可能性があります。そのため、すべてのデベロッパーは Android 7.0 を搭載している端末でアプリがクラッシュしないことを確認する必要があります。アプリがネイティブ コードを使用している場合は、パブリック NDK API のみを使用するようにしてください。
アプリがプライベート プラットフォーム API にアクセスする場合、次の 3 つの方法があります。
- アプリで直接プライベート プラットフォーム ライブラリにアクセスしている。目的のライブラリをコピーして含めるか、パブリック NDK API を使用するようにアプリを更新する必要があります。
- アプリが、プライベート プラットフォーム ライブラリにアクセスするサードパーティ ライブラリを使用している。プライベート ライブラリに直接アクセスしていないという確信があっても、この状況を想定してアプリをテストする必要があります。
- APK に含まれていないライブラリをアプリが参照している。たとえば、OpenSSL を独自にコピーして使用するつもりで、このライブラリをアプリの APK にバンドルするのを忘れていた場合などが考えられます。このようなアプリは、
libcrypto.so
が含まれているバージョンの Android プラットフォームでは問題なく実行できる可能性があります。ただし、このライブラリを含まない Android の新しいバージョン(Android 6.0 以降など)では、アプリがクラッシュする可能性があります。この問題を修正するには、NDK 以外のすべてのライブラリを APK にバンドルしてください。
NDK に含まれていないネイティブ ライブラリは使用しないでください。Android のバージョンが変わると、変更または削除される可能性があります。OpenSSL から BoringSSL への切り替えは、そのような変更の一例です。また、NDK に含まれていないプラットフォーム ライブラリには互換性要件がないため、端末によって互換性レベルが異なる場合があります。
現在リリースされているアプリに対するこの制限の影響を軽減するため、よく使われているライブラリ(libandroid_runtime.so
、libcutils.so
、libcrypto.so
、libssl.so
など)は、API レベル 23 以下を対象とするアプリ向けに、Android 7.0(API レベル 24)で一時的にアクセス可能になっています。アプリがこのようなライブラリを読み込むと、logcat で警告が生成され、対象の端末でトースト通知が表示されます。このような警告が表示されたら、目的のライブラリをコピーして含めるか、パブリック NDK API のみを使用するようにアプリを更新する必要があります。Android プラットフォームの今後のリリースではプライベート ライブラリの使用がすべて制限され、アプリがクラッシュする可能性があります。
パブリック ライブラリではなく一時的なアクセスもできない API を呼び出すと、必ずアプリでランタイムエラーが生成されます。そのため、System.loadLibrary
と dlopen(3)
はどちらも NULL
を返し、アプリのクラッシュを引き起こす可能性があります。アプリのコードを確認して、プライベート プラットフォーム API の使用を削除し、Android 7.0(API レベル 24)を搭載したデバイスまたはエミュレータを使用して、アプリを十分にテストしてください。アプリでプライベート ライブラリを使用しているか不明な場合は、logcat を確認してランタイム エラーを特定できます。
次の表は、プライベート ネイティブ ライブラリの使用状況と対象 API レベル(android:targetSdkVersion
)に応じて、アプリで想定される動作を示しています。
ライブラリ | 対象 API レベル | 動的リンカーからのランタイム アクセス | Android 7.0(API レベル 24)の動作 | 将来の Android プラットフォームの動作 |
---|---|---|---|---|
NDK パブリック | 任意 | アクセス可能 | 想定どおりに動作します | 想定どおりに動作 |
非公開(一時的にアクセス可能なプライベート ライブラリ) | 23 以下 | 一時的にアクセス可能 | 想定どおりに動作するが、logcat 警告が表示される。 | ランタイム エラー |
非公開(一時的にアクセス可能なプライベート ライブラリ) | 24 以上 | 制限付き | ランタイム エラー | ランタイム エラー |
非公開(その他) | 任意 | 制限付き | ランタイム エラー | ランタイム エラー |
アプリのプライベート ライブラリの使用状況を確認する
プライベート ライブラリの読み込みに関する問題を特定できるように、logcat で警告またはランタイムエラーが生成されます。たとえば、アプリのターゲット API レベルが 23 以下で、Android 7.0 を搭載している端末でプライベート ライブラリへのアクセスを試みると、次のような警告が表示される場合があります。
03-21 17:07:51.502 31234 31234 W linker : library "libandroid_runtime.so" ("/system/lib/libandroid_runtime.so") needed or dlopened by "/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible for the namespace "classloader-namespace" - the access is temporarily granted as a workaround for http://b/26394120
このような logcat の警告によって、プライベート プラットフォーム API にアクセスしようとしたもののアプリがクラッシュしなかったライブラリを特定できます。ただしアプリのターゲット API レベルが 24 以上の場合は、logcat で次のランタイムエラーが生成され、アプリがクラッシュする可能性があります。
java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so" ("/system/lib/libcutils.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace" at java.lang.Runtime.loadLibrary0(Runtime.java:977) at java.lang.System.loadLibrary(System.java:1602)
プライベート プラットフォーム API に動的にリンクするサードパーティ ライブラリをアプリが使用している場合も、logcat でこのように出力される場合があります。次のコマンドを実行して、Android 7.0DK の readelf ツールを使用すると、指定した .so
ファイルの共有ライブラリのうち動的にリンクされているものをすべてリストアップできます。
aarch64-linux-android-readelf -dW libMyLibrary.so
アプリを更新する
このようなエラーを修正し、今後のプラットフォーム アップデートでアプリがクラッシュしないようにする手順は次のとおりです。
- アプリでプライベート プラットフォーム ライブラリを使用している場合は、目的のライブラリをコピーして含めるか、パブリック NDK API を使用するようにアプリを更新する必要があります。
- プライベート シンボルにアクセスするサードパーティ ライブラリをアプリで使用している場合は、ライブラリの作成者に連絡してライブラリの更新を依頼してください。
- すべての NDK 以外のライブラリを必ず APK にパッケージ化してください。
libandroid_runtime.so
のgetJavaVM
とgetJNIEnv
の代わりに、標準の JNI 関数を使用します。AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h> AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or JavaVM::AttachCurrentThread from <jni.h>.
libcutils.so
のプライベートproperty_get
シンボルの代わりに__system_property_get
を使用します。これを行うには、次の include 文とともに__system_property_get
を使用します。#include <sys/system_properties.h>
注: システム プロパティの可用性およびコンテンツについては、CTS でテストされません。これを修正するには、これらのプロパティをまったく使用しないようにすることをおすすめします。
libcrypto.so
のSSL_ctrl
シンボルのローカル バージョンを使用します。たとえば、.so
ファイルでlibcyrpto.a
を静的にリンクするか、BoringSSL/OpenSSL のlibcrypto.so
のダイナミック リンク バージョンを含めて APK にパッケージ化します。
Android for Work
Android 7.0 には、証明書のインストール、パスワードの再設定、セカンダリ ユーザーの管理、端末識別子へのアクセスなど、Android for Work をターゲットにしているアプリに対する変更が含まれています。Android for Work 環境向けのアプリをビルドしている場合、これらの変更点を確認し、変更に応じてアプリを修正する必要があります。
- DPC が委任証明書のインストーラを設定するには、そのインストーラをインストールする必要があります。Android 7.0(API レベル 24)をターゲットとするプロファイル アプリとデバイス オーナー アプリの両方について、デバイス ポリシー コントローラ(DPC)が
DevicePolicyManager.setCertInstallerPackage()
を呼び出す前に代理証明書インストーラをインストールする必要があります。インストーラがインストールされていない場合、IllegalArgumentException
がスローされます。 - デバイス管理者向けのパスワードの再設定制限がプロファイル オーナーに適用されます。デバイス管理者は、
DevicePolicyManager.resetPassword()
を使用してパスワードを消去したり、すでに設定されているパスワードを変更したりできなくなります。デバイス管理者は、デバイスにパスワード、PIN、またはパターンが設定されていない場合のみ、パスワードを設定できます。 - デバイス オーナーとプロファイル オーナーは、制限が設定されている場合でもアカウントを管理することができます。デバイス オーナーとプロファイル オーナーは、
DISALLOW_MODIFY_ACCOUNTS
ユーザー制限が適用されている場合でも Account Management API を呼び出すことができます。 - デバイス オーナーによるセカンダリ ユーザーの管理がさらに簡単になりました。デバイスがデバイス所有者モードで実行されている場合は、
DISALLOW_ADD_USER
制限が自動的に設定されます。これにより、管理対象外のユーザーが作成されることを防ぐことができます。また、CreateUser()
メソッドとcreateAndInitializeUser()
メソッドは非推奨となり、新しいDevicePolicyManager.createAndManageUser()
メソッドに置き換えられました。 - デバイスの所有者はデバイス ID にアクセスできます。デバイスの所有者は、
DevicePolicyManager.getWifiMacAddress()
を使用してデバイスの Wi-Fi MAC アドレスにアクセスできます。デバイスで Wi-Fi が有効になっていない場合、このメソッドは値null
を返します。 - ワークモード設定により、仕事用アプリへのアクセスが制御されます。ワークモードがオフになると、システム ランチャーは仕事用アプリをグレーアウトしてこれらが利用できないことを示します。ワークモードが再度有効になると、通常の動作に戻ります。
- [Settings] UI から、クライアント証明書チェーンと対応するプライベート キーを含む PKCS #12 ファイルをインストールすると、それ以降、チェーン内の CA 証明書は信頼される認証情報ストレージにインストールされません。これによって、後でアプリがクライアント証明書チェーンを取得しようとしたとき、
KeyChain.getCertificateChain()
の結果に影響することはありません。必要に応じて、設定 UI から信頼できる認証情報ストレージに CA 証明書を別途インストールする必要があります。その際は、.crt または .cer のファイル拡張子で DER エンコード形式を使用します。 - Android 7.0 以降、指紋の登録と保存はユーザー単位で管理されます。Android 7.0(API レベル 24)を搭載したデバイスで、プロファイル所有者のデバイス ポリシー クライアント(DPC)が API レベル 23 以前をターゲットとしている場合、ユーザーはデバイスで指紋を設定できますが、仕事用アプリはデバイスの指紋にアクセスできません。DPC が API レベル 24 以上をターゲットにしている場合、ユーザーは [設定] > [セキュリティ] > [仕事用プロファイルのセキュリティ] にアクセスして、仕事用プロファイル専用の指紋を設定できます。
DevicePolicyManager.getStorageEncryptionStatus()
によって新しい暗号化ステータスENCRYPTION_STATUS_ACTIVE_PER_USER
が返されます。これは、暗号化が有効で、暗号鍵がユーザーに関連付けられていることを示します。この新しいステータスは、DPC ターゲット API レベルが 24 以上の場合にのみ返されます。それ以前の API レベルをターゲットとするアプリは、暗号化キーがユーザーまたはプロファイル固有である場合でもENCRYPTION_STATUS_ACTIVE
が返されます。- Android 7.0 の一部のメソッドは、通常は端末全体に影響するはずですが、仕事用プロファイルが専用のセキュリティ確認画面でインストールされていると、そのメソッドの動作が異なります。これらの方法は、デバイス全体に影響を与えるのではなく、仕事用プロファイルにのみ適用されます。(対象となるメソッドの完全なリストは、
DevicePolicyManager.getParentProfileInstance()
ドキュメントをご覧ください)。たとえば、DevicePolicyManager.lockNow()
は端末全体をロックするのではなく、仕事用プロファイルのみをロックします。これらのメソッドはそれぞれ、DevicePolicyManager
の親インスタンスでメソッドを呼び出すと、以前のように動作させることができます。この親インスタンスを取得するには、DevicePolicyManager.getParentProfileInstance()
を呼び出します。たとえば、親インスタンスのlockNow()
メソッドを呼び出すと、デバイス全体がロックされます。
アノテーションの保持
Android 7.0 では、アノテーションの表示が無視されていたバグが修正されました。この問題によって、ランタイムがこれまでできなかったアノテーションへのアクセスが可能になっていました。対象となるアノテーションは以下のとおりです。
VISIBILITY_BUILD
: ビルド時にのみ表示されます。VISIBILITY_SYSTEM
: 実行時に表示されますが、基幹システムにのみ表示されます。
アプリがこの動作に依存している場合は、実行時に使用可能にする必要があるアノテーションに保持ポリシーを追加してください。これを行うには、@Retention(RetentionPolicy.RUNTIME)
を使用します。
TLS/SSL のデフォルトの構成の変更
Android 7.0 では、HTTPS やその他の TLS/SSL トラフィックでアプリが使用するデフォルトの TLS/SSL 構成が次のように変更されています。
- RC4 暗号スイートが無効になりました。
- CHACHA20-POLY1305 暗号スイートが有効になりました。
RC4 がデフォルトで無効になっていると、サーバーが最新の暗号スイートをネゴシエートしない場合、HTTPS または TLS/SSL 接続の互換性が損なわれる可能性があります。推奨される修正方法は、サーバーの構成を改善して、より強力で最新の暗号スイートとプロトコルを有効にすることです。理想的には、TLSv1.2 と AES-GCM を有効にして、Forward Secrecy 暗号スイート(ECDHE)を有効化および優先してください。
代わりに、カスタムの SSLSocketFactory
を使用してサーバーと通信するようにアプリを修正する方法もあります。このファクトリーは、デフォルトの暗号スイートに加えて、サーバーで必要になる暗号スイートを有効にする SSLSocket
インスタンスを作成するように設計する必要があります。
注: これらの変更は WebView
には適用されません。
Android 7.0 をターゲットとするアプリ
これらの動作の変更は、Android 7.0(API レベル 24)以降をターゲットとするアプリにのみ適用されます。Android 7.0 を対象にしてコンパイルするアプリ、または targetSdkVersion
を Android 7.0 以降に設定するアプリの場合、必要に応じてアプリを修正して、これらの変更点に適切に対応する必要があります。
シリアル化の変更
Android 7.0(API レベル 24)では、デフォルトの serialVersionUID の計算で仕様に一致しないバグが修正されました。
Serializable
を実装し、明示的な serialVersionUID
フィールドを指定しない場合、デフォルトの serialVersionUID が変更される可能性があります。これにより、以前のバージョンでシリアル化されたクラスのインスタンスの逆シリアル化を試行する際に、例外がスローされる可能性があります。次のようなエラー メッセージが表示されます。
local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567
これらの問題を修正するには、影響を受けるクラスに、エラー メッセージから取得した stream classdesc
serialVersionUID
の値を持つ serialVersionUID
フィールドを追加する必要があります(この場合は 1234
)。この変更は、シリアル化コードの記述に関するすべてのベスト プラクティスの推奨事項に準拠しており、すべてのバージョンの Android で動作します。
修正された具体的なバグは、静的初期化メソッド(<clinit>
など)の存在に関連していました。仕様によると、クラスに静的イニシャライザ メソッドが存在するかどうかは、そのクラスに対して計算されるデフォルトの serialVersionUID に影響します。クラスに静的イニシャライザがない場合は、このバグ修正の前に、静的イニシャライザの計算時にスーパークラスもチェックされます。
なお、この変更は、API レベル 23 以前をターゲットとするアプリ、serialVersionUID
フィールドを持つクラス、静的初期化メソッドを持つクラスには影響しません。
その他の重要事項
- Android 7.0 上で低い API レベルをターゲットにしたアプリが実行されている場合、ユーザーがディスプレイ サイズを変更すると、アプリのプロセスは強制終了されます。アプリは、このシナリオを適切に処理する必要があります。適切に処理しないと、ユーザーが [Recents] からアプリを復元したときに、アプリがクラッシュします。
アプリをテストして、この動作が発生しないようにしてください。このテストを行うには、DDMS から手動でアプリを強制終了して、同じクラッシュを発生させます。
Android 7.0(API レベル 24)以降をターゲットにしたアプリは、画面密度の変更時に自動的に強制終了しませんが、設定変更への対応が不十分なままである可能性があります。
- Android 7.0 上のアプリは設定変更を適切に処理し、次回の起動時にクラッシュしないようにする必要があります。フォントサイズを変更して([設定] > [ディスプレイ] > [フォントサイズ])、アプリを [Recents] から復元すると、アプリの動作を確認できます。
-
旧バージョンの Android では、バグにより、メインスレッドの TCP ソケットへの書き込みを厳格モード違反として報告していませんでした。Android 7.0 ではこのバグが修正されました。この動作が発生したアプリは、
android.os.NetworkOnMainThreadException
をスローするようになりました。通常、メインスレッドでネットワーク操作を実行することはお勧めできません。このような操作は一般的に ANR やジャンクを引き起こす大幅なレイテンシが発生するためです。 -
メソッドの
Debug.startMethodTracing()
ファミリーが、SD カードのトップレベルではなく、共有ストレージ上のパッケージ固有のディレクトリの storing output にデフォルト設定されました。つまり、これらの API を使用するためにアプリでWRITE_EXTERNAL_STORAGE
権限をリクエストする必要はありません。 -
多くのプラットフォーム API で、
Binder
トランザクションで送信された大きなペイロードのチェックが開始され、サイレント ロギングや抑制を行うのではなく、TransactionTooLargeExceptions
がRuntimeExceptions
として再スローされるようになりました。一般的な例としては、Activity.onSaveInstanceState()
に大量のデータを格納することです。これにより、アプリが Android 7.0 をターゲットにしている場合は、ActivityThread.StopInfo
でRuntimeException
がスローされます。 -
アプリが
Runnable
タスクをView
に投稿し、View
がウィンドウにアタッチされていない場合、システムはRunnable
タスクをView
とともにキューに入れます。Runnable
タスクは、View
がウィンドウにアタッチされるまで実行されません。この動作は以下のバグを修正します。 -
DELETE_PACKAGES
権限を持つ Android 7.0 上のアプリが、別のアプリがインストールしたパッケージを削除しようとすると、ユーザー確認が要求されます。このシナリオでは、アプリがPackageInstaller.uninstall()
を呼び出した場合は、STATUS_PENDING_USER_ACTION
をリターン ステータスとしてみなす必要があります。 - Crypto という JCA プロバイダは廃止されました。このプロバイダの SHA1PRNG アルゴリズムが暗号学的に脆弱であるためです。このプロバイダが利用できなくなるため、アプリは SHA1PRNG を使用して(危険な方法で)キーを導出できなくなりました。詳細については、ブログ投稿の Android N で廃止されるセキュリティ「Crypto」プロバイダをご覧ください。