사용자는 이미지, 동영상, 기타 생생한 콘텐츠를 좋아하지만 앱에 이러한 콘텐츠를 삽입하고 이동하는 것이 항상 쉽지만은 않습니다. 앱에서 리치 콘텐츠를 더 쉽게 수신할 수 있도록 Android 12 (API 수준 31)에서는 앱이 클립보드, 키보드 또는 드래그 등 모든 소스의 콘텐츠를 수락할 수 있는 통합 API를 도입했습니다.
OnReceiveContentListener
와 같은 인터페이스를 UI 구성요소에 연결하고 콘텐츠가 메커니즘을 통해 삽입될 때 콜백을 받을 수 있습니다. 콜백은 일반 텍스트와 스타일이 지정된 텍스트부터 마크업, 이미지, 동영상, 오디오 파일 등에 이르기까지 코드에서 모든 콘텐츠 수신을 처리하는 단일 장소가 됩니다.
이전 Android 버전과의 호환성을 위해 이 API는 Core 1.7 및 Appcompat 1.4부터 AndroidX에서도 사용할 수 있으며 이 기능을 구현할 때 사용하면 좋습니다.
개요
기존 API를 사용하면 길게 터치 메뉴나 드래그와 같은 각 UI 메커니즘에 상응하는 자체 API가 있습니다. 즉, 각 API와 별도로 통합하여 콘텐츠를 삽입하는 각 메커니즘에 유사한 코드를 추가해야 합니다.
OnReceiveContentListener
API는 구현할 단일 API를 만들어 이러한 다양한 코드 경로를 통합하므로 개발자는 앱별 로직에 집중하고 나머지는 플랫폼에서 처리하도록 할 수 있습니다.
또한 이 접근 방식을 사용하면 새로운 콘텐츠 삽입 방법이 플랫폼에 추가될 때 앱에서 지원을 사용 설정하기 위해 코드를 추가로 변경할 필요가 없습니다. 또한 앱에서 특정 사용 사례에 맞게 전체 맞춤설정을 구현해야 하는 경우에도 동일한 방식으로 작동하는 기존 API를 계속 사용할 수 있습니다.
구현
API는 단일 메서드 OnReceiveContentListener
가 있는 리스너 인터페이스입니다.
이전 버전의 Android 플랫폼을 지원하려면 AndroidX Core 라이브러리에서 일치하는 OnReceiveContentListener
인터페이스를 사용하는 것이 좋습니다.
API를 사용하려면 앱에서 처리할 수 있는 콘텐츠 유형을 지정하여 리스너를 구현합니다.
Kotlin
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
자바
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
앱에서 지원하는 콘텐츠 MIME 유형을 모두 지정한 후 나머지 리스너를 구현합니다.
Kotlin
class MyReceiver : OnReceiveContentListener { override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat { val split = contentInfo.partition { item: ClipData.Item -> item.uri != null } val uriContent = split.first val remaining = split.second if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining } companion object { val MIME_TYPES = arrayOf("image/*", "video/*") } }
자바
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; @Override public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) { Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition( item -> item.getUri() != null); ContentInfo uriContent = split.first; ContentInfo remaining = split.second; if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining; } }
앱에서 이미 인텐트 공유를 지원하면 콘텐츠 URI 처리에 앱별 로직을 재사용할 수 있습니다. 남아 있는 데이터를 반환하여 이 데이터의 처리를 플랫폼에 위임합니다.
리스너를 구현한 후 앱의 적절한 UI 요소에서 리스너를 설정합니다.
Kotlin
class MyActivity : Activity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... val myInput = findViewById(R.id.my_input) ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver()) } }
자바
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { // ... AppCompatEditText myInput = findViewById(R.id.my_input); ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver()); } }
URI 권한
OnReceiveContentListener
에 전달되는 페이로드의 콘텐츠 URI에 대해 읽기 권한은 플랫폼에서 자동으로 부여 및 해제됩니다.
일반적으로 앱은 서비스 또는 활동에서 콘텐츠 URI를 처리합니다. 장기 실행 처리의 경우 WorkManager를 사용하세요. 이를 구현할 때는 Intent.setClipData
를 사용하여 콘텐츠를 전달하고 FLAG_GRANT_READ_URI_PERMISSION
플래그를 설정하여 대상 서비스 또는 활동으로 권한을 확장하세요.
또는 현재 컨텍스트 내에서 백그라운드 스레드를 사용하여 콘텐츠를 처리할 수 있습니다. 이 경우 플랫폼에서 권한을 조기 취소하지 않도록 하려면 리스너가 수신한 payload
객체 참조를 유지해야 합니다.
맞춤 보기
앱에서 맞춤 View
서브클래스를 사용하는 경우 OnReceiveContentListener
가 우회되지 않도록 주의하세요.
View
클래스가 onCreateInputConnection
메서드를 재정의하면 Jetpack API InputConnectionCompat.createWrapper
를 사용하여 InputConnection
를 구성합니다.
View
클래스가 onTextContextMenuItem
메서드를 재정의하는 경우 메뉴 항목이 R.id.paste
또는 R.id.pasteAsPlainText
인 경우 슈퍼에 위임합니다.
키보드 이미지 API와 비교
OnReceiveContentListener
API는 기존 키보드 이미지 API의 다음 버전으로 생각할 수 있습니다. 이 통합 API는 키보드 이미지 API의 기능과 일부 추가 기능을 지원합니다. 기기 및 기능 호환성은 Jetpack 라이브러리를 사용하는지 Android SDK의 네이티브 API를 사용하는지에 따라 다릅니다.
작업 또는 기능 | 키보드 이미지 API에서 지원 | 통합 API에서 지원 |
---|---|---|
키보드에서 삽입 | 예(API 수준 13 이상) | 예(API 수준 13 이상) |
길게 터치 메뉴에서 붙여넣기를 사용하여 삽입 | 아니요 | 예 |
드래그 앤 드롭을 사용하여 삽입 | 아니요 | 예(API 수준 24 이상) |
작업 또는 기능 | 키보드 이미지 API에서 지원 | 통합 API에서 지원 |
---|---|---|
키보드에서 삽입 | 예(API 수준 25 이상) | 예(Android 12 이상) |
길게 터치 메뉴에서 붙여넣기를 사용하여 삽입 | 아니요 | |
드래그 앤 드롭을 사용하여 삽입 | 아니요 |