アプリ セキュリティに関するベスト プラクティス

アプリをセキュアにすることで、ユーザーの信頼とデバイスの整合性を保つことができます。

このページでは、アプリのセキュリティに大きなプラスの影響を与えるベスト プラクティスについて説明します。

通信をセキュアにする

アプリと他のアプリ間や、アプリとウェブサイト間で交換されるデータを保護すると、アプリの安定性が向上し、送受信するデータが保護されます。

暗黙的インテントとエクスポートされていないコンテンツ プロバイダを使用する

アプリチューザを表示する

暗黙的インテントがユーザーのデバイス上で少なくとも 2 つのアプリ候補を起動できる場合、アプリチューザを明示的に表示します。このインタラクション方法により、ユーザーは、信頼するアプリに機密情報を送信できるようなります。

Kotlin

    val intent = Intent(ACTION_SEND)
    val possibleActivitiesList: List<ResolveInfo> =
            queryIntentActivities(intent, PackageManager.MATCH_ALL)

    // Verify that an activity in at least two apps on the user's device
    // can handle the intent. Otherwise, start the intent only if an app
    // on the user's device can handle the intent.
    if (possibleActivitiesList.size > 1) {

        // Create intent to show chooser.
        // Title is something similar to "Share this photo with".

        val chooser = resources.getString(R.string.chooser_title).let { title ->
            Intent.createChooser(intent, title)
        }
        startActivity(chooser)
    } else if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
    

Java

    Intent intent = new Intent(Intent.ACTION_SEND);
    List<ResolveInfo> possibleActivitiesList =
            queryIntentActivities(intent, PackageManager.MATCH_ALL);

    // Verify that an activity in at least two apps on the user's device
    // can handle the intent. Otherwise, start the intent only if an app
    // on the user's device can handle the intent.
    if (possibleActivitiesList.size() > 1) {

        // Create intent to show chooser.
        // Title is something similar to "Share this photo with".

        String title = getResources().getString(R.string.chooser_title);
        Intent chooser = Intent.createChooser(intent, title);
        startActivity(chooser);
    } else if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
    

関連情報:

署名ベースのパーミッションを適用する

制御や所有の対象となっている 2 つのアプリ間でデータを共有する場合は、署名ベースのパーミッションを使用してください。署名ベースのパーミッションの場合、ユーザーの確認は不要で、代わりに、データにアクセスするアプリが同じ署名鍵を使用して署名されているかチェックされます。署名ベースのパーミッションにより、効率的でセキュアなユーザー エクスペリエンスを実現できます。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapp">
        <permission android:name="my_custom_permission_name"
                    android:protectionLevel="signature" />
    

関連情報:

アプリのコンテンツ プロバイダに対するアクセスを許可しない

自分のアプリから別の非所有アプリに向けてデータを送信する場合を除き、アプリに含まれる ContentProvider オブジェクトに対して他のデベロッパーのアプリがアクセスすることを明示的に禁止する必要があります。この設定は、Android 4.1.1(API レベル 16)以前を搭載しているデバイスにアプリをインストールできる場合に特に重要です。このような Android バージョンの場合、<provider> 要素の android:exported 属性がデフォルトで true になっています。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapp">
        <application ... >
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.example.myapp.fileprovider"
                ...
                android:exported="false">
                <!-- Place child elements of <provider> here. -->
            </provider>
            ...
        </application>
    </manifest>
    

機密情報を表示する前に認証情報を要求する

ユーザーがアプリ内の機密情報やプレミアム コンテンツにアクセスできるよう、ユーザーに認証情報を要求する場合は、PIN / パスワード / パターンや生体認証情報(顔認証、指紋認識など)を要求するようにします。

生体認証情報をリクエストする方法については、生体認証ガイドをご覧ください。

ネットワーク セキュリティ対策を適用する

以下のセクションでは、アプリのネットワーク セキュリティを改善する方法について説明します。

SSL トラフィックを使用する

信頼できる有名な CA が発行した証明書を持つウェブサーバーとアプリが通信する場合、HTTPS リクエストは非常にシンプルです。

Kotlin

    val url = URL("https://www.google.com")
    val urlConnection = url.openConnection() as HttpsURLConnection
    urlConnection.connect()
    urlConnection.inputStream.use {
        ...
    }
    

Java

    URL url = new URL("https://www.google.com");
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.connect();
    InputStream in = urlConnection.getInputStream();
    

ネットワーク セキュリティ構成を追加する

アプリが新しい CA やカスタム CA を使用する場合は、構成ファイル内でネットワークのセキュリティ設定を宣言します。このプロセスにより、アプリコードを編集することなく、ネットワーク セキュリティ構成を作成できます。

ネットワーク セキュリティ構成ファイルをアプリに追加する手順は次のとおりです。

  1. アプリのマニフェスト内で構成を宣言します。
  2.     <manifest ... >
            <application
                android:networkSecurityConfig="@xml/network_security_config"
                ... >
                <!-- Place child elements of <application> element here. -->
            </application>
        </manifest>
        
  3. res/xml/network_security_config.xml にある XML リソース ファイルを追加します。

    平文を無効にして、対象ドメインに対するすべてのトラフィックが HTTPS を使用するように指定します。

        <network-security-config>
            <domain-config cleartextTrafficPermitted="false">
                <domain includeSubdomains="true">secure.example.com</domain>
                ...
            </domain-config>
        </network-security-config>
        

    開発プロセス中に、<debug-overrides> 要素を使用することで、ユーザーがインストールした証明書を明示的に許可できます。この要素は、アプリのリリース構成に影響を与えることなく、デバッグ中やテスト中にアプリのセキュリティ クリティカル オプションをオーバーライドします。アプリのネットワーク セキュリティ構成 XML ファイル内でこの要素を定義する方法を以下のスニペットに示します。

        <network-security-config>
            <debug-overrides>
                <trust-anchors>
                    <certificates src="user" />
                </trust-anchors>
            </debug-overrides>
        </network-security-config>
        

関連情報: ネットワーク セキュリティ構成

独自のトラスト マネージャーを作成する

SSL チェッカーは、必ずしもすべての証明書を受け入れるべきではありません。次のいずれかの条件が当てはまるユースケースの場合は、トラスト マネージャーをセットアップして、発生するすべての SSL 警告を処理することをおすすめします。

  • 新しい CA やカスタム CA によって署名された証明書を持つウェブサーバーと通信する場合。
  • CA が、使用しているデバイスによって信頼されていない場合。
  • ネットワーク セキュリティ構成を使用できない場合。

各手順を完了する方法については、不明な証明機関の処理に関する説明をご覧ください。

関連情報:

WebView オブジェクトを慎重に使用する

可能な限り、WebView オブジェクト内のホワイトリスト コンテンツだけをロードするようにしてください。デベロッパーが制御できないサイトにユーザーが移動するのを、アプリ内の WebView オブジェクトが許可しないようにする必要があります。

また、アプリの WebView オブジェクト内のコンテンツを完全に制御し、信頼している場合を除いて、JavaScript インターフェース サポートを有効にしないでください。

HTML メッセージ チャネルを使用する

Android 6.0(API レベル 23)以降を搭載しているデバイス上で JavaScript インターフェース サポートを使用する必要があるアプリの場合は、次のコード スニペットに示すように、evaluateJavascript() ではなく、HTML メッセージ チャネルを使用してウェブサイトとアプリ間の通信を行うようにします。

Kotlin

    val myWebView: WebView = findViewById(R.id.webview)

    // messagePorts[0] and messagePorts[1] represent the two ports.
    // They are already tangled to each other and have been started.
    val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

    // Create handler for channel[0] to receive messages.
    channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

        override fun onMessage(port: WebMessagePort, message: WebMessage) {
            Log.d(TAG, "On port $port, received this message: $message")
        }
    })

    // Send a message from channel[1] to channel[0].
    channel[1].postMessage(WebMessage("My secure message"))
    

Java

    WebView myWebView = (WebView) findViewById(R.id.webview);

    // messagePorts[0] and messagePorts[1] represent the two ports.
    // They are already tangled to each other and have been started.
    WebMessagePort[] channel = myWebView.createWebMessageChannel();

    // Create handler for channel[0] to receive messages.
    channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
        @Override
        public void onMessage(WebMessagePort port, WebMessage message) {
             Log.d(TAG, "On port " + port + ", received this message: " + message);
        }
    });

    // Send a message from channel[1] to channel[0].
    channel[1].postMessage(new WebMessage("My secure message"));
    

関連情報:

適切なパーミッションを付与する

アプリは、適切に機能するために必要となる最小限のパーミッションだけをリクエストするようにします。可能であれば、付与されたパーミッションの一部が不要になった場合、アプリはそのパーミッションを放棄するようにします。

インテントを使用してパーミッションを譲る

可能であれば、別のアプリで完了できるアクションの場合、そのアクションを完了するパーミッションを自分のアプリには追加しないでください。代わりに、インテントを使用して、すでに必要なパーミッションを持っている別のアプリにリクエストを譲ります。

READ_CONTACTS パーミッションや WRITE_CONTACTS パーミッションをリクエストするのではなく、インテントを使用して、ユーザーを連絡帳アプリに誘導する方法の例を以下に示します。

Kotlin

    // Delegates the responsibility of creating the contact to a contacts app,
    // which has already been granted the appropriate WRITE_CONTACTS permission.
    Intent(Intent.ACTION_INSERT).apply {
        type = ContactsContract.Contacts.CONTENT_TYPE
    }.also { intent ->
        // Make sure that the user has a contacts app installed on their device.
        intent.resolveActivity(packageManager)?.run {
            startActivity(intent)
        }
    }
    

Java

    // Delegates the responsibility of creating the contact to a contacts app,
    // which has already been granted the appropriate WRITE_CONTACTS permission.
    Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
    insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

    // Make sure that the user has a contacts app installed on their device.
    if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
        startActivity(insertContactIntent);
    }
    

また、ストレージに対するアクセスやファイルの選択など、ファイルベース I/O を実行する必要があるアプリの場合、アプリに代わってシステムが処理を完了することができるため、アプリに特別なパーミッションは必要ありません。ユーザーが特定の URI でコンテンツを選択すると、選択されたリソースに対するパーミッションが呼び出し元のアプリに付与されます。

関連情報:

アプリ間でセキュアにデータを共有する

アプリのコンテンツをセキュアな方法で他のアプリと共有するには、以下のベスト プラクティスを適用してください。

  • 必要に応じて、読み取り専用または書き込み専用のパーミッションを適用します。
  • FLAG_GRANT_READ_URI_PERMISSION フラグや FLAG_GRANT_WRITE_URI_PERMISSION フラグを使用することで、データに対する 1 回限りのアクセス権限をクライアントに付与します。
  • データを共有する際は、「file://」URI ではなく「content://」URI を使用します。デベロッパーの代わりに、FileProvider のインスタンスがこの処理を行います。

URI パーミッション付与フラグとコンテンツ プロバイダ パーミッションを使用することで、アプリの PDF ファイルを別の PDF ビューアアプリ内で表示する方法を、次のコード スニペットに示します。

Kotlin

    // Create an Intent to launch a PDF viewer for a file owned by this app.
    Intent(Intent.ACTION_VIEW).apply {
        data = Uri.parse("content://com.example/personal-info.pdf")

        // This flag gives the started app read access to the file.
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }.also { intent ->
        // Make sure that the user has a PDF viewer app installed on their device.
        intent.resolveActivity(packageManager)?.run {
            startActivity(intent)
        }
    }
    

Java

    // Create an Intent to launch a PDF viewer for a file owned by this app.
    Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
    viewPdfIntent.setData(Uri.parse("content://com.example/personal-info.pdf"));

    // This flag gives the started app read access to the file.
    viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

    // Make sure that the user has a PDF viewer app installed on their device.
    if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
        startActivity(viewPdfIntent);
    }
    

注: 信頼できないアプリが Android 10(API レベル 29)以降をターゲットとしている場合、そのアプリのホーム ディレクトリ内にあるファイルで exec() を呼び出すことはできません。書き込み可能なアプリのホーム ディレクトリからファイルをこのように実行することは、W^X 違反です。アプリがロードするのは、その APK ファイル内に埋め込まれたバイナリコードだけに限定するように設定する必要があります。また、Android 10 以降をターゲットとしているアプリの場合、dlopen() を使用して開いたファイルの実行コードをメモリ内で編集することはできません。たとえば、テキストの再配置を伴うすべての共有オブジェクト ファイル(.so)などが該当します。

関連情報: android:grantUriPermissions

データを安全に保存する

アプリがユーザーの機密情報に対するアクセスを必要とする場合がありますが、ユーザーは、データが適切に保護されると信頼できる場合に限り、機密データに対するアクセスをアプリに付与します。

内部ストレージに個人データを保存する

ユーザーの個人データはすべて、アプリごとにサンドボックス化されているデバイスの内部ストレージ内に保存します。このファイルを表示する際、アプリがパーミッションをリクエストする必要はなく、他のアプリはファイルにアクセスできません。また、追加のセキュリティ対策として、ユーザーがアプリをアンインストールすると、デバイスは、アプリが内部ストレージに保存したすべてのファイルを削除します。

内部ストレージにデータを書き込む方法の例を次のコード スニペットに示します。

Kotlin

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    val FILE_NAME = "sensitive_info.txt"
    val fileContents = "This is some top-secret information!"
    File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
        writer.write(fileContents)
    }
    

Java

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    final String FILE_NAME = "sensitive_info.txt";
    String fileContents = "This is some top-secret information!";
    try (BufferedWriter writer =
                 new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
        writer.write(fileContents);
    } catch (IOException e) {
        // Handle exception.
    }
    

内部ストレージからデータを読み取る逆向きの処理を次のコード スニペットに示します。

Kotlin

    val FILE_NAME = "sensitive_info.txt"
    val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
        lines.fold("") { working, line ->
            "$working\n$line"
        }
    }
    

Java

    final String FILE_NAME = "sensitive_info.txt";
    StringBuffer stringBuffer = new StringBuffer();
    try (BufferedReader reader =
                 new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {

        String line = reader.readLine();
        while (line != null) {
            stringBuffer.append(line).append('\n');
            line = reader.readLine();
        }
    } catch (IOException e) {
        // Handle exception.
    }
    

関連情報:

外部ストレージを慎重に使用する

デフォルトでは、Android システムは、外部ストレージ内にあるデータに対してセキュリティ制限を適用しません。また、ストレージ メディア自体がデバイスに接続された状態を維持するかどうかも保証されません。したがって、外部ストレージ内の情報に対する安全なアクセスを実現するには、下記のセキュリティ対策を適用する必要があります。

特定ディレクトリ アクセス権限を使用する

アプリがデバイスの外部ストレージ内の特定のディレクトリに限りアクセスする必要がある場合、特定ディレクトリ アクセス権限を使用することで、デバイスの外部ストレージに対するアプリのアクセスを制限できます。ユーザーの利便性を考えると、アプリはディレクトリ アクセス URI を保存する必要があります。これにより、アプリがディレクトリにアクセスしようとするたびに、ディレクトリに対するアクセス権限をユーザーが承認する必要がなくなります。

注: 外部ストレージ内の特定のディレクトリを対象にして特定ディレクトリ アクセス権限を使用する場合、アプリの実行中にユーザーがこのストレージを含むメディアを取り外す可能性がある点に注意してください。このユーザー行動が引き起こす Environment.getExternalStorageState() の戻り値に対する変更を適切に処理するロジックを組み込んでおく必要があります。

デバイスのプライマリ共有ストレージ内の pictures ディレクトリを対象に特定ディレクトリ アクセス権限を使用する例を次のコード スニペットに示します。

Kotlin

    private const val PICTURES_DIR_ACCESS_REQUEST_CODE = 42

    ...

    private fun accessExternalPicturesDirectory() {
        val intent: Intent = (getSystemService(Context.STORAGE_SERVICE) as StorageManager)
                .primaryStorageVolume.createAccessIntent(Environment.DIRECTORY_PICTURES)
        startActivityForResult(intent, PICTURES_DIR_ACCESS_REQUEST_CODE)
    }

    ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
        if (requestCode == PICTURES_DIR_ACCESS_REQUEST_CODE && resultCode == Activity.RESULT_OK) {

            // User approved access to scoped directory.
            if (resultData != null) {
                val picturesDirUri: Uri = resultData.data

                // Save user's approval for accessing this directory
                // in your app.
                contentResolver.takePersistableUriPermission(
                        picturesDirUri,
                        Intent.FLAG_GRANT_READ_URI_PERMISSION
                )
            }
        }
    }
    

Java

    private static final int PICTURES_DIR_ACCESS_REQUEST_CODE = 42;

    private void accessExternalPicturesDirectory() {
      StorageManager sm =
              (StorageManager) getSystemService(Context.STORAGE_SERVICE);
      StorageVolume volume = sm.getPrimaryStorageVolume();
      Intent intent =
              volume.createAccessIntent(Environment.DIRECTORY_PICTURES);
      startActivityForResult(intent, PICTURES_DIR_ACCESS_REQUEST_CODE);
    }

    ...

    @Override
    public void onActivityResult(int requestCode, int resultCode,
            Intent resultData) {
        if (requestCode == PICTURES_DIR_ACCESS_REQUEST_CODE &&
                resultCode == Activity.RESULT_OK) {

            // User approved access to scoped directory.
            if (resultData != null) {
                Uri picturesDirUri = resultData.getData();

                // Save user's approval for accessing this directory
                // in your app.
                ContentResolver myContentResolver = getContentResolver();
                myContentResolver.takePersistableUriPermission(picturesDirUri,
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
        }
    }
    

警告: 不必要に nullcreateAccessIntent() に渡さないでください。StorageManager がアプリ用に見つけたボリューム全体に対するアクセス権限がアプリに付与されることになります。

関連情報:

データの有効性をチェックする

アプリが外部ストレージのデータを使用する場合、データの内容に破損や変更がないことを確認する必要があります。また、安定した形式ではなくなったファイルを処理するロジックもアプリに組み込む必要があります。

ファイルの有効性をチェックするパーミッションとロジックを以下の例に示します。

AndroidManifest.xml

    <manifest ... >
        <!-- Apps on devices running Android 4.4 (API level 19) or higher cannot
             access external storage outside their own "sandboxed" directory, so
             the READ_EXTERNAL_STORAGE (and WRITE_EXTERNAL_STORAGE) permissions
             aren't necessary. -->
        <uses-permission
              android:name="android.permission.READ_EXTERNAL_STORAGE"
              android:maxSdkVersion="18" />
        ...
    </manifest>

    

MyFileValidityChecker

Kotlin

    private val UNAVAILABLE_STORAGE_STATES: Set<String> =
            setOf(MEDIA_REMOVED, MEDIA_UNMOUNTED, MEDIA_BAD_REMOVAL, MEDIA_UNMOUNTABLE)
    ...
    val ringtone = File(getExternalFilesDir(DIRECTORY_RINGTONES), "my_awesome_new_ringtone.m4a")
    when {
        isExternalStorageEmulated(ringtone) -> {
            Log.e(TAG, "External storage is not present")
        }
        UNAVAILABLE_STORAGE_STATES.contains(getExternalStorageState(ringtone)) -> {
            Log.e(TAG, "External storage is not available")
        }
        else -> {
            val fis = FileInputStream(ringtone)

            // available() determines the approximate number of bytes that
            // can be read without blocking.
            val bytesAvailable: Int = fis.available()
            val fileBuffer = ByteArray(bytesAvailable)
            StringBuilder(bytesAvailable).apply {
                while (fis.read(fileBuffer) != -1) {
                    append(fileBuffer)
                }
                // Implement appropriate logic for checking a file's validity.
                checkFileValidity(this)
            }
        }
    }
    

Java

    File ringtone = new File(getExternalFilesDir(DIRECTORY_RINGTONES,
            "my_awesome_new_ringtone.m4a"));
    if (isExternalStorageEmulated(ringtone)) {
        Logger.e(TAG, "External storage is not present");
    } else if (getExternalStorageState(ringtone) == MEDIA_REMOVED
            | MEDIA_UNMOUNTED | MEDIA_BAD_REMOVAL | MEDIA_UNMOUNTABLE) {
        Logger.e(TAG, "External storage is not available");
    } else {
        FileInputStream fis = new FileInputStream(ringtone);

        // available() determines the approximate number of bytes that
        // can be read without blocking.
        int bytesAvailable = fis.available();
        StringBuilder fileContents = new StringBuilder(bytesAvailable);
        byte[] fileBuffer = new byte[bytesAvailable];
        while (fis.read(fileBuffer) != -1) {
            fileContents.append(fileBuffer);
        }

        // Implement appropriate logic for checking a file's validity.
        checkFileValidity(fileContents);
    }
    

関連情報:

キャッシュ ファイルに保存するのは機密性の低いデータだけに限定する

機密性の低いアプリデータに対する迅速なアクセスを実現するには、そのようなデータをデバイスのキャッシュ内に保存します。サイズが 1 MB を超えるキャッシュの場合は、getExternalCacheDir() を使用します。超えていない場合は、getCacheDir() を使用します。各メソッドは、アプリのキャッシュ データを格納する File オブジェクトを提供します。

アプリが最近ダウンロードしたファイルをキャッシュする方法を次のコード スニペットに示します。

Kotlin

    val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
        File(cacheDir.path, fileToCache.name)
    }
    

Java

    File cacheDir = getCacheDir();
    File fileToCache = new File(myDownloadedFileUri);
    String fileToCacheName = fileToCache.getName();
    File cacheFile = new File(cacheDir.getPath(), fileToCacheName);
    

注: getExternalCacheDir() を使用して共有ストレージ内にアプリのキャッシュを配置した場合、アプリの実行中に、ユーザーがこのストレージを含むメディアを取り外す可能性がある点に注意してください。このユーザー行動が引き起こすキャッシュミスを適切に処理するロジックを組み込んでおく必要があります。

注: このようなファイルには、セキュリティ対策が適用されません。そのため、WRITE_EXTERNAL_STORAGE パーミッションを持つアプリはすべて、このキャッシュのコンテンツにアクセスすることができます。

関連情報: キャッシュ ファイルを保存する

SharedPreferences をプライベート モードで使用する

getSharedPreferences() を使用してアプリの SharedPreferences オブジェクトの作成やアクセスを行う場合は、MODE_PRIVATE を使用します。これにより、共有環境設定ファイル内の情報にアクセスできるのが、デベロッパーのアプリだけになります。

アプリ間でデータを共有する場合は、SharedPreferences オブジェクトを使用しないでください。代わりに、アプリ間でデータをセキュアに共有するために必要な手順を行ってください。

関連情報: 共有環境設定を使用する

サービスと依存関係を最新の状態に保つ

ほとんどのアプリは、外部ライブラリとデバイス システム情報を使用して、専用のタスクを完了します。アプリの依存関係を最新の状態に保つことにより、このような通信ポイントをセキュアにすることができます。

Google Play 開発者サービスのセキュリティ プロバイダをチェックする

注: このセクションが当てはまるのは、Google Play 開発者サービスがインストールされているデバイスをターゲットとするアプリに限られます。

Google Play 開発者サービスを使用するアプリの場合、アプリがインストールされているデバイス上で Google Play 開発者サービスが更新されているか確認してください。このチェックは、UI スレッドとは非同期で実行する必要があります。デバイスが最新の状態でない場合、アプリは承認エラーをトリガーする必要があります。

アプリがインストールされているデバイス上で Google Play 開発者サービスが最新の状態かどうかを判断するには、セキュリティ プロバイダを更新して SSL エクスプロイトから保護するで説明されている手順を行います。

関連情報:

アプリの依存関係をすべて更新する

アプリをデプロイする前に、ライブラリや SDK、その他すべての依存関係が最新の状態であるか確認してください。

  • Android SDK など、ファースト パーティ依存関係については、SDK Manager など、Android Studio 内にある更新ツールを使用してください。
  • サードパーティ依存関係については、アプリが使用するライブラリのウェブサイトをチェックして、利用可能なアップデートやセキュリティ パッチをインストールします。

関連情報: ビルド依存関係を追加する

詳細情報

アプリをセキュアにする方法については、以下の参考リンクをご覧ください。

参考リンク

アプリをセキュアにする方法については、以下の参考リンクをご覧ください。

コードラボ

ブログ