Android14のSelected Photos Accessについて

問題

AndroidManifest.xmlの下記の行で警告が表示されます。

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

警告メッセージは以下の通りです。

Your app is currently not handling Selected Photos Access introduced in Android 14+ More... (⌘F1) 
Inspection info:Selected Photo Access is a new ability for users to share partial access to their photo library when apps request access to their device storage on Android 14+.  Instead of letting the system manage the selection lifecycle, we recommend you adapt your app to handle partial access to the photo library.

このエラーの原因と対策を調べました。

原因

この警告メッセージは、Android 14(APIレベル 33)で導入された「Selected Photos Access(選択した写真へのアクセス)」に対応していないことを指摘しています。

Android 14以降、ユーザーはアプリがデバイスのストレージにアクセスを要求する際に、写真ライブラリ全体へのアクセスを許可する代わりに、選択した写真への部分的なアクセスを共有する新しい機能を利用できます。

android.permission.READ_MEDIA_IMAGESパーミッションを使用することで、アプリはユーザーのデバイス上の画像にアクセスできますが、Android 14+では、ユーザーが選択した写真へのアクセスのみをアプリに許可するオプションが追加されています。この変更により、ユーザーのプライバシーがさらに強化され、アプリは必要な写真にのみアクセスできるようになります。

この警告に対処するためには、アプリを「Selected Photos Access」に対応させる必要があります。具体的には、アプリが選択した写真への部分的なアクセスを管理し、この新しいアクセス権限に適応するようにする必要があります。

Selected Photos Accessの特徴と動作

  • 部分的なアクセス許可:ユーザーはアプリに対して、写真ライブラリ全体ではなく、選択した写真にのみアクセスを許可できます。これにより、ユーザーはプライバシーを保護しつつ、アプリの機能を利用できます。

  • 動的なアクセス管理: ユーザーはいつでも設定を変更し、アプリがアクセスできる写真を追加または削除できます。アプリは、これらの変更をリアルタイムで反映する必要があります。

  • ユーザーインターフェースの調整: アプリは、選択された写真へのアクセスが許可された場合、ユーザーが新たにアクセスを許可した写真に簡単にアクセスできるようにユーザーインターフェースを調整する必要があります。

対応

Selected Photos Access を利用する

アプリで Selected Photos Access を利用するには、以下の手順が必要です。

  1. アプリのターゲット API レベルを 33 に設定します。
  2. アプリの manifest.xml ファイルに以下の権限を追加します。
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
    
  3. アプリで PhotoPicker クラスを使用して、ユーザーが写真や動画を選択できるようにします。

PhotoPicker クラスの使用

PhotoPicker クラスは、ユーザーが写真や動画を選択するための UI を提供します。このクラスを使用するには、以下の手順が必要です。

  1. PhotoPicker.Builder クラスのインスタンスを作成します。
  2. Builder インスタンスに、ユーザーが選択できる写真や動画の種類を指定します。
  3. Builder インスタンスの build() メソッドを呼び出して、PhotoPicker インスタンスを作成します。
  4. PhotoPicker インスタンスの start() メソッドを呼び出して、写真選択画面を表示します。

ユーザーが選択した写真や動画へのアクセス

ユーザーが写真や動画を選択した後、アプリは PhotoPicker インスタンスの getSelectedPhotos() メソッドを使用して、選択された写真や動画への URI を取得できます。

Selected Photos Access の制限事項

Selected Photos Access には、以下の制限事項があります。

  • ユーザーが選択した写真や動画のみアクセスできる
  • ユーザーがアプリをアンインストールすると、アプリは選択された写真や動画へのアクセス権を失う

SwiftでiOSのバージョン番号を取得するには

Swiftを使ってiOSデバイスのバージョン番号を取得するには、主にUIDeviceクラスのcurrent.systemVersionプロパティと、ProcessInfoクラスのoperatingSystemVersionプロパティの2つの方法があります。

UIDeviceクラスのcurrent.systemVersionプロパティを使用する方法

UIDeviceクラスのcurrent.systemVersionプロパティは、デバイスのOSバージョンを表す文字列を返します。

以下のコードは、iOSのバージョン番号を取得してコンソールに出力します。

let iosVersion = UIDevice.current.systemVersion
print("iOSバージョン: \(iosVersion)") // => iOSバージョン: 17.4

以下は、SwiftUIでiOSのバージョン番号を取得する例です。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("iOSバージョン: \(UIDevice.current.systemVersion)") // => iOSバージョン: 17.4
    }
}

ProcessInfoクラスのoperatingSystemVersionプロパティを使用する方法

ProcessInfoのoperatingSystemVersionプロパティは、OSバージョンをmajorVersion、minorVersion、patchVersionの3つの数値で提供します。
これにより、バージョンの各部分を個別に扱うことが可能になります。

以下のコードは、iOSのバージョン番号を取得してコンソールに出力します。

import Foundation

let osVersion = ProcessInfo().operatingSystemVersion
print("Major version: \(osVersion.majorVersion)") // => Major version: 17
print("Minor version: \(osVersion.minorVersion)") // => Minor version: 4
print("Patch version: \(osVersion.patchVersion)") // => Patch version: 0

以下は、SwiftUIでiOSのバージョン番号を取得する例です。

import SwiftUI

struct ContentView: View {
    var body: some View {
        let osVersion = ProcessInfo().operatingSystemVersion
        VStack {
            Text("Major version: \(osVersion.majorVersion)") // => Major version: 17
            Text("Minor version: \(osVersion.minorVersion)") // => Minor version: 4
            Text("Patch version: \(osVersion.patchVersion)") // => Patch version: 0
        }
    }
}

KotlinでAndroidのバージョン番号を取得するには

Androidのバージョン番号やビルドIDなどの情報は、Buildクラスを通じて取得できます。

以下のコードは、Androidのバージョン番号を取得してログに出力します。

import android.os.Build
import android.util.Log

val releaseVersion = Build.VERSION.RELEASE
val apiLevel = Build.VERSION.SDK_INT
val buildDisplay = Build.DISPLAY
val buildId = Build.ID
val incrementalVersion = Build.VERSION.INCREMENTAL

Log.d("AndroidVersionInfo", "Release Version: $releaseVersion") // => Release Version: 14
Log.d("AndroidVersionInfo", "API Level: $apiLevel") // => API Level: 34
Log.d("AndroidVersionInfo", "Build Display: $buildDisplay") // => Build Display: UE1A.230829.036.A1
Log.d("AndroidVersionInfo", "Build ID: $buildId") // => Build ID: UE1A.230829.036.A1
Log.d("AndroidVersionInfo", "Incremental Version: $incrementalVersion") // => Incremental Version: 11228894

以下は、Jetpack ComposeでAndroidのバージョン番号を取得する例です。

import androidx.compose.foundation.layout.Column
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import android.os.Build

@Composable
fun DisplayAndroidVersion() {
    Column {
        Text("Release Version: ${Build.VERSION.RELEASE}")
        Text("API Level: ${Build.VERSION.SDK_INT}")
        Text("Build Display: ${Build.DISPLAY}")
        Text("Build ID: ${Build.ID}")
        Text("Incremental Version: ${Build.VERSION.INCREMENTAL}")
    }
}

JavaScriptでカウントダウン付き自動リダイレクト

JavaScriptを使用して、10秒間のカウントダウン後に自動的にトップページへリダイレクトする方法を紹介します。

この処理は、例えば404 Not Foundエラーページなどで利用すると効果的です。

HTMLコード

まず、HTMLではカウントダウンタイマーの残り時間を表示する部分を設置します。以下のように書きます。

<p><span id="countdown">10</span>秒後に自動的にトップページに移動します。</p>

JavaScriptコード

次に、JavaScriptを使用してカウントダウン機能を実装します。
以下のスクリプトをページの末尾に配置します。

<script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function () {
        let seconds = 10;
        const countdownElement = document.getElementById('countdown');

        const intervalId = setInterval(function () {
            countdownElement.textContent = seconds;
            if (seconds <= 0) {
                clearInterval(intervalId);
                window.location.href = "/";
            }
            seconds--;
        }, 1000);
    });
</script>

このスクリプトでは、DOMContentLoaded イベントが発生した後、カウントダウンを開始します。

各秒ごとにカウントダウン要素のテキストを更新し、秒数が0以下になったらインターバルをクリアし、トップページにリダイレクトします。