제품 소식

삽입된 사진 선택 도구

전문 길이: 8분

삽입된 사진 선택 도구: 앱에서 비공개로 사진 및 동영상을 요청하는 더 원활한 방법

photopicker.png

Android 사진 선택 도구를 사용하는 흥미로운 새로운 방법으로 앱의 사용자 환경을 개선해 보세요. 새로운 삽입된 사진 선택 도구는 사용자가 앱의 인터페이스 내에서 바로 사진과 동영상을 선택할 수 있는 원활하고 개인 정보 보호 중심의 방법을 제공합니다. 이제 앱에서 클라우드 콘텐츠에 대한 액세스를 비롯하여 사진 선택 도구에서 사용할 수 있는 모든 동일한 이점을 앱 환경에 직접 통합하여 얻을 수 있습니다.

삽입된 사진 선택 도구를 사용하는 이유

Google은 많은 앱에서 사진이나 동영상을 선택할 때 사용자에게 고도로 통합되고 원활한 환경을 제공하고자 한다는 것을 잘 알고 있습니다. 삽입된 사진 선택 도구는 사용자가 앱을 종료하지 않고도 최근 사진에 빠르게 액세스할 수 있도록 설계되었습니다. 또한 사용자는 즐겨찾기, 앨범, 검색 기능을 비롯하여 선호하는 클라우드 미디어 제공업체 (예: Google 포토)에서 전체 라이브러리를 탐색할 수 있습니다. 이렇게 하면 사용자가 앱 간에 전환하거나 원하는 사진이 로컬에 저장되어 있는지 클라우드에 저장되어 있는지 걱정할 필요가 없습니다.

원활한 통합, 강화된 개인 정보 보호

삽입된 사진 선택 도구를 사용하면 사용자가 실제로 항목을 선택할 때까지 앱에서 사용자의 사진이나 동영상에 액세스할 필요가 없습니다. 즉, 사용자에게 더 나은 개인 정보 보호와 더 간소화된 환경을 제공할 수 있습니다. 또한 삽입된 사진 선택 도구는 사용자에게 전체 클라우드 기반 미디어 라이브러리에 대한 액세스 권한을 제공하는 반면, 표준 사진 권한은 로컬 파일로만 제한됩니다.

Google 메시지의 삽입된 사진 선택 도구

Google 메시지는 삽입된 사진 선택 도구의 기능을 보여줍니다. 다음은 Google 메시지에서 삽입된 사진 선택 도구를 통합한 방법입니다.

  • 직관적인 배치:  사진 선택 도구는 카메라 버튼 바로 아래에 있어 사용자가 새 사진을 캡처할지 기존 사진을 선택할지 명확하게 선택할 수 있습니다.
  • 동적 미리보기: 사용자가 사진을 탭하면 바로 큰 미리보기가 표시되어 선택을 쉽게 확인할 수 있습니다. 사진을 선택 해제하면 미리보기가 사라져 환경이 깔끔하고 정리됩니다.
  • 더 많은 콘텐츠를 위해 펼치기: 초기 뷰는 간소화되어 최근 사진에 쉽게 액세스할 수 있습니다. 하지만 사용자는 사진 선택 도구를 쉽게 펼쳐 Google 포토의 클라우드 콘텐츠를 비롯하여 라이브러리의 모든 사진과 동영상을 탐색하고 선택할 수 있습니다.
  • 사용자 선택 존중: 삽입된 사진 선택 도구는 사용자가 선택한 특정 사진 또는 동영상에만 액세스 권한을 부여하므로 사용자는 사진 및 동영상 권한 요청을 완전히 중지할 수 있습니다. 또한 이렇게 하면 사용자가 사진 및 동영상에 대한 제한된 액세스 권한만 부여하는 상황을 메시지에서 처리할 필요가 없습니다.
gif1.gif
gif2.gif

구현

사진 선택 도구 Jetpack 라이브러리를 사용하면 삽입된 사진 선택 도구를 쉽게 통합할 수 있습니다.  

Jetpack Compose

먼저 Jetpack 사진 선택 도구 라이브러리를 종속 항목으로 포함합니다.

implementation("androidx.photopicker:photopicker-compose:1.0.0-alpha01")

EmbeddedPhotoPicker 컴포저블 함수는 Compose 화면 내에 삽입된 사진 선택 도구 UI를 직접 포함하는 메커니즘을 제공합니다. 이 컴포저블은 삽입된 사진 선택 도구 UI를 호스팅하는 SurfaceView를 만듭니다. EmbeddedPhotoPicker 서비스에 대한 연결을 관리하고, 사용자 상호작용을 처리하며, 선택한 미디어 URI를 호출 애플리케이션에 전달합니다.  

  @Composable
fun EmbeddedPhotoPickerDemo() {
    // We keep track of the list of selected attachments
    var attachments by remember { mutableStateOf(emptyList<Uri>()) }

    val coroutineScope = rememberCoroutineScope()
    // We hide the bottom sheet by default but we show it when the user clicks on the button
    val scaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = rememberStandardBottomSheetState(
            initialValue = SheetValue.Hidden,
            skipHiddenState = false
        )
    )

    // Customize the embedded photo picker
    val photoPickerInfo = EmbeddedPhotoPickerFeatureInfo
        .Builder()
        // Set limit the selection to 5 items
        .setMaxSelectionLimit(5)
        // Order the items selection (each item will have an index visible in the photo picker)
        .setOrderedSelection(true)
        // Set the accent color (red in this case, otherwise it follows the device's accent color)
        .setAccentColor(0xFF0000)
        .build()

    // The embedded photo picker state will be stored in this variable
    val photoPickerState = rememberEmbeddedPhotoPickerState(
        onSelectionComplete = {
            coroutineScope.launch {
                // Hide the bottom sheet once the user has clicked on the done button inside the picker
                scaffoldState.bottomSheetState.hide()
            }
        },
        onUriPermissionGranted = {
            // We update our list of attachments with the new Uris granted
            attachments += it
        },
        onUriPermissionRevoked = {
            // We update our list of attachments with the Uris revoked
            attachments -= it
        }
    )

       SideEffect {
        val isExpanded = scaffoldState.bottomSheetState.targetValue == SheetValue.Expanded

        // We show/hide the embedded photo picker to match the bottom sheet state
        photoPickerState.setCurrentExpanded(isExpanded)
    }

    BottomSheetScaffold(
        topBar = {
            TopAppBar(title = { Text("Embedded Photo Picker demo") })
        },
        scaffoldState = scaffoldState,
        sheetPeekHeight = if (scaffoldState.bottomSheetState.isVisible) 400.dp else 0.dp,
        sheetContent = {
            Column(Modifier.fillMaxWidth()) {
                // We render the embedded photo picker inside the bottom sheet
                EmbeddedPhotoPicker(
                    state = photoPickerState,
                    embeddedPhotoPickerFeatureInfo = photoPickerInfo
                )
            }
        }
    ) { innerPadding ->
        Column(Modifier.padding(innerPadding).fillMaxSize().padding(horizontal = 16.dp)) {
            Button(onClick = {
                coroutineScope.launch {
                    // We expand the bottom sheet, which will trigger the embedded picker to be shown
                    scaffoldState.bottomSheetState.partialExpand()
                }
            }) {
                Text("Open photo picker")
            }
            LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 64.dp)) {
                // We render the image using the Coil library
                itemsIndexed(attachments) { index, uri ->
                    AsyncImage(
                        model = uri,
                        contentDescription = "Image ${index + 1}",
                        contentScale = ContentScale.Crop,
                        modifier = Modifier.clickable {
                            coroutineScope.launch {
                                // When the user clicks on the media from the app's UI, we deselect it
                                // from the embedded photo picker by calling the method deselectUri
                                photoPickerState.deselectUri(uri)
                            }
                        }
                    )
                }
            }
        }
    }
}

먼저 Jetpack 사진 선택 도구 라이브러리를 종속 항목으로 포함합니다.

implementation("androidx.photopicker:photopicker:1.0.0-alpha01")

삽입된 사진 선택 도구를 추가하려면 레이아웃 파일에 항목을 추가해야 합니다.  

  <view class="androidx.photopicker.EmbeddedPhotoPickerView"
    android:id="@+id/photopicker"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

활동/프래그먼트에서 초기화합니다.

  // We keep track of the list of selected attachments
private val _attachments = MutableStateFlow(emptyList<Uri>())
val attachments = _attachments.asStateFlow()

private lateinit var picker: EmbeddedPhotoPickerView
private var openSession: EmbeddedPhotoPickerSession? = null

val pickerListener = object EmbeddedPhotoPickerStateChangeListener {
    override fun onSessionOpened (newSession: EmbeddedPhotoPickerSession) {
        openSession = newSession
    }

    override fun onSessionError (throwable: Throwable) {}

    override fun onUriPermissionGranted(uris: List<Uri>) {
        _attachments += uris
    }

    override fun onUriPermissionRevoked (uris: List<Uri>) {
        _attachments -= uris
    }

    override fun onSelectionComplete() {
        // Hide the embedded photo picker as the user is done with the photo/video selection
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_view)
    
    //
    // Add the embedded photo picker to a bottom sheet to allow the dragging to display the full photo library
    //

    picker = findViewById(R.id.photopicker)
    picker.addEmbeddedPhotoPickerStateChangeListener(pickerListener)
    picker.setEmbeddedPhotoPickerFeatureInfo(
        // Set a custom accent color
        EmbeddedPhotoPickerFeatureInfo.Builder().setAccentColor(0xFF0000).build()
    )
}

EmbeddedPhotoPickerSession의 여러 메서드를 호출하여 삽입된 선택 도구와 상호작용할 수 있습니다.

  // Notify the embedded picker of a configuration change
openSession.notifyConfigurationChanged(newConfig)

// Update the embedded picker to expand following a user interaction
openSession.notifyPhotoPickerExpanded(/* expanded: */ true)

// Resize the embedded picker
openSession.notifyResized(/* width: */ 512, /* height: */ 256)

// Show/hide the embedded picker (after a form has been submitted)
openSession.notifyVisibilityChanged(/* visible: */ false)

// Remove unselected media from the embedded picker after they have been
// unselected from the host app's UI
openSession.requestRevokeUriPermission(removedUris)

삽입된 사진 선택 도구 환경은 SDK 확장 프로그램 15 이상이 설치된 Android 14 (API 수준 34) 이상을 실행하는 사용자에게 제공됩니다. 사진 선택 도구 기기 가용성에 관해 자세히 알아보세요.

사용자 개인 정보 보호 및 보안을 강화하기 위해 시스템은 그리기 또는 오버레이를 방지하는 방식으로 삽입된 사진 선택 도구를 렌더링합니다. 이 의도적인 디자인 선택은 UX에서 광고 배너를 계획하는 것과 마찬가지로 사진 선택 도구의 표시 영역을 별도의 전용 요소로 간주해야 함을 의미합니다.

의견이나 제안사항이 있으면 문제 추적기에 티켓을 제출하세요.

계속 읽기