相片挑選工具

顯示相片挑選工具對話方塊,其中顯示了裝置上的媒體檔案。選取要與應用程式分享的相片。
圖 1. 相片挑選工具提供直覺易用的使用者介面,方便您與應用程式分享相片。

相片挑選工具會提供可瀏覽的介面,向使用者顯示媒體庫,並由新到舊為檔案排序。如「隱私權最佳做法程式碼研究室」所示,相片挑選工具內建安全的權限授予方式,可讓使用者僅授予所選圖片和影片的存取權,不必將整個媒體庫的存取權授予應用程式。

如果使用者在裝置上使用符合資格的雲端媒體服務供應商,也可以從遠端儲存的相片和影片中選取內容。進一步瞭解雲端媒體供應商

這項工具會自動更新,讓應用程式使用者持續享有更多新推出的功能,不必變更任何程式碼。

使用 Jetpack Activity 合約

如要簡化相片挑選工具整合功能,請加入 1.7.0 以上版本的 androidx.activity 程式庫。

使用下列活動結果合約啟動相片挑選工具:

如果裝置上沒有相片挑選工具,資料庫會改為自動叫用 ACTION_OPEN_DOCUMENT 意圖動作。搭載 Android 4.4 (API 級別 19) 以上版本的裝置支援這個意圖。您可以呼叫 isPhotoPickerAvailable(),確認特定裝置是否支援相片挑選工具。

選取單一媒體項目

如要選取單一媒體項目,請使用 PickVisualMedia 活動結果合約,如以下程式碼片段所示:

View

// Registers a photo picker activity launcher in single-select mode.
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: $uri")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

// Launch the photo picker and let the user choose only images.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))

檢視畫面

// Registers a photo picker activity launcher in single-select mode.
ActivityResultLauncher<PickVisualMediaRequest> pickMedia =
        registerForActivityResult(new PickVisualMedia(), uri -> {
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: " + uri);
    } else {
        Log.d("PhotoPicker", "No media selected");
    }
});

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only images.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageOnly.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.VideoOnly.INSTANCE)
        .build());

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
String mimeType = "image/gif";
pickMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(new PickVisualMedia.SingleMimeType(mimeType))
        .build());

Compose

// Registers a photo picker activity launcher in single-select mode.
val pickMedia = rememberLauncherForActivityResult(PickVisualMedia()) { uri ->
    // Callback is invoked after the user selects a media item or closes the
    // photo picker.
    if (uri != null) {
        Log.d("PhotoPicker", "Selected URI: $uri")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// Include only one of the following calls to launch(), depending on the types
// of media that you want to let the user choose from.

// Launch the photo picker and let the user choose images and videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

// Launch the photo picker and let the user choose only images.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

// Launch the photo picker and let the user choose only videos.
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))

// Launch the photo picker and let the user choose only images/videos of a
// specific MIME type, such as GIFs.
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))

選取多個媒體項目

如要選取多個媒體項目,請設定可選取的媒體檔案數量上限,如以下程式碼片段所示。

View

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
val pickMultipleMedia =
        registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (uris.isNotEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

檢視畫面

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
ActivityResultLauncher<PickVisualMediaRequest> pickMultipleMedia =
        registerForActivityResult(new PickMultipleVisualMedia(5), uris -> {
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (!uris.isEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: " + uris.size());
    } else {
        Log.d("PhotoPicker", "No media selected");
    }
});

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(new PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE)
        .build());

Compose

// Registers a photo picker activity launcher in multi-select mode.
// In this example, the app lets the user select up to 5 media files.
val pickMultipleMedia =
        rememberLauncherForActivityResult(PickMultipleVisualMedia(5)) { uris ->
    // Callback is invoked after the user selects media items or closes the
    // photo picker.
    if (uris.isNotEmpty()) {
        Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
    } else {
        Log.d("PhotoPicker", "No media selected")
    }
}

// For this example, launch the photo picker and let the user choose images
// and videos. If you want the user to select a specific type of media file,
// use the overloaded versions of launch(), as shown in the section about how
// to select a single media item.
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

平台會限制使用者可在相片挑選工具中選取的檔案數目上限。如要使用這項限制,請呼叫 getPickImagesMaxLimit()。在不支援相片挑選工具的裝置上,系統會忽略此項限制。

適用裝置

裝置必須符合以下條件,才能使用相片挑選工具:

搭載 Android 4.4 (API 級別 19) 至 Android 10 (API 級別 29) 版本的舊型裝置,以及搭載 Android 11 或 12 版本且支援 Google Play 服務的 Android Go 裝置,皆可安裝相片挑選工具的向後移植版本。如要透過 Google Play 服務自動安裝向後移植的相片挑選工具模組,請在應用程式資訊清單檔案中的 <application> 標記加入以下內容:

<!-- Trigger Google Play services to install the backported photo picker module. -->
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
         android:enabled="false"
         android:exported="false"
         tools:ignore="MissingClass">
    <intent-filter>
        <action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
    </intent-filter>
    <meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>

保留媒體檔案存取權

根據預設,系統會授予應用程式對媒體檔案的存取權,直到裝置重新啟動或應用程式停止為止。如果應用程式執行的是長時間執行的工作 (例如在背景上傳大型檔案),則可能需要延長此存取權的保留時間。如要延長,請呼叫 takePersistableUriPermission() 方法:

Kotlin

val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)

Java

int flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;
context.contentResolver.takePersistableUriPermission(uri, flag);

透過轉碼處理 HDR 影片

Android 13 (API 33) 推出了高動態範圍 (HDR) 影片擷取功能。雖然 HDR 可提供更豐富的視覺體驗,但部分舊版應用程式可能無法處理這些新格式,導致播放時出現不自然的色彩呈現 (例如臉部呈現綠色) 等問題。為解決這個相容性差距,相片挑選工具提供轉碼功能,可自動將 HDR 影片轉換為 標準動態範圍 (SDR) 格式,再提供給要求的應用程式。

相片挑選器轉碼的主要目標,是確保在更廣泛的應用程式中,提供一致且視覺精準的媒體體驗,即使是尚未明確支援 HDR 的應用程式也一樣。相片挑選工具會將 HDR 影片轉碼為 SDR,以改善應用程式相容性,並提供流暢的使用者體驗。

相片挑選工具轉碼的運作方式

根據預設,相片挑選器 HDR 轉碼功能不會啟用。如要啟用這項功能,應用程式在啟動相片挑選器時,必須明確宣告其媒體格式處理功能。

應用程式會將媒體處理功能提供給相片挑選工具。您可以透過將 mediaCapabilities 新增至 PickVisualMediaRequest.Builder,在使用 AndroidX Activity 程式庫啟動相片挑選工具時執行此操作。為此,我們已在 PickVisualMediaRequest.Builder 中新增了 setMediaCapabilitiesForTranscoding(capabilities: MediaCapabilities?) API。

您可以使用 MediaCapabilities 類別控制 HDR 轉碼行為。提供 MediaCapabilities 物件,具體指定應用程式支援的 HDR 類型 (例如TYPE_HLG10TYPE_HDR10TYPE_HDR10_PLUSTYPE_DOLBY_VISION)。

如要完全停用轉碼功能,請將 null 傳遞給 MediaCapabilities。系統會將你提供的功能中「未」明確列出的 HDR 類型視為不支援。這個 API 支援 Android 13 (API 級別 33) 以上版本,並以 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 標註。

import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
import androidx.annotation.RequiresApi
import android.os.Build
import android.util.Log
import android.provider.MediaStore

// Registers a photo picker activity launcher.
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
    // Callback invoked after media selected or picker activity closed.
    if (uri != null) {
        Log.d("photo picker", "Selected URI: $uri")
    } else {
        Log.d("photo picker", "No media selected")
    }
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun launchPhotoPickerWithTranscodingSupport() {
    val mediaCapabilities = MediaCapabilities.Builder()
        .addSupportedHdrType(MediaCapabilities.HdrType.TYPE_HLG10)
        .build()

    // Launch the photo picker and let the user choose only videos with
    // transcoding enabled.
    pickMedia.launch(PickVisualMediaRequest.Builder()
        .setMediaType(PickVisualMedia.VideoOnly)
        .setMediaCapabilitiesForTranscoding(mediaCapabilities)
        .build())
}

相片挑選工具的轉碼作業會根據應用程式的媒體功能和所選影片進行。如果執行轉碼作業,系統會傳回轉碼影片的 URI。

HDR 轉碼的重要注意事項

  • 效能和儲存空間:轉碼需要處理時間,並且會建立新檔案,因此會耗用儲存空間。
  • 影片長度限制:為了平衡使用者體驗和儲存空間限制,影片長度上限為 1 分鐘。
  • 快取檔案管理:系統會在閒置維護期間定期清除快取的轉碼檔案,避免儲存空間用量過高。
  • 裝置適用性:Android 13 (API 級別 33) 以上版本支援相片挑選工具轉碼功能。
  • AndroidX 活動整合:請確認您使用的是 1.11.0-alpha01 以上版本的 AndroidX Activity 程式庫,因為這類版本包含必要的 setMediaCapabilitiesForTranscoding API。