그림 1. 통합 API는 터치 & 홀드 메뉴에서 붙여넣기 또는 드래그 앤 드롭 사용과 같은 특정 UI 메커니즘과 상관없이 수신 콘텐츠를 처리하는 단일 장소를 제공합니다.
사용자는 이미지, 동영상, 기타 생생한 콘텐츠를 좋아하지만 앱에 이러한 콘텐츠를 삽입하고 이동하는 것은 어려울 수 있습니다. 앱에서 리치 콘텐츠를 더 쉽게 수신할 수 있도록 Android 12 (API 수준 31)에서는 앱이 클립보드, 키보드 또는 드래그 등 모든 소스의 콘텐츠를 수락할 수 있는 통합 API를 도입했습니다.
OnReceiveContentListener과 같은 인터페이스를 UI 구성요소에 연결하여 콘텐츠가 메커니즘을 통해 삽입될 때 콜백을 받을 수 있습니다. 콜백은 일반 텍스트와 스타일이 지정된 텍스트부터 마크업, 이미지, 동영상, 오디오 파일 등에 이르기까지 코드에서 모든 콘텐츠 수신을 처리하는 단일 장소가 됩니다.
이전 Android 버전과의 호환성을 위해 이 API는 Core 1.7 및 Appcompat 1.4부터 AndroidX에서도 사용할 수 있으며 이 기능을 구현할 때 사용하면 좋습니다.
개요
기존 API를 사용하면 터치 앤 홀드 메뉴나 드래그와 같은 각 UI 메커니즘에 상응하는 자체 API가 있습니다. 즉, 각 API와 별도로 통합하여 콘텐츠를 삽입하는 각 메커니즘에 유사한 코드를 추가해야 합니다.
그림 2. 이전에는 앱에서 콘텐츠 삽입을 위해 각 UI 메커니즘에 다른 API를 구현했습니다.
OnReceiveContentListener API는 구현할 단일 API를 만들어 이러한 다양한 코드 경로를 통합하므로 개발자는 앱별 로직에 집중하고 나머지는 플랫폼에서 처리하도록 할 수 있습니다.
그림 3. 통합 API를 사용하면 모든 UI 메커니즘을 지원하는 단일 API를 구현할 수 있습니다.
이 접근 방식은 플랫폼에 콘텐츠를 삽입하는 새로운 방법이 추가될 때 앱에서 지원을 사용 설정하기 위해 추가 코드 변경을 하지 않아도 된다는 의미이기도 합니다. 앱에서 특정 사용 사례에 맞게 전체 맞춤설정을 구현해야 하는 경우 기존 API를 계속 사용할 수 있으며, 기존 API는 동일한 방식으로 계속 작동합니다.
classMyReceiver:OnReceiveContentListener{overridefunonReceiveContent(view:View,contentInfo:ContentInfoCompat):ContentInfoCompat{valsplit=contentInfo.partition{item:ClipData.Item->item.uri!=null}valuriContent=split.firstvalremaining=split.secondif(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.returnremaining}companionobject{valMIME_TYPES=arrayOf("image/*","video/*")}}
자바
publicclassMyReceiverimplementsOnReceiveContentListener{publicstaticfinalString[]MIME_TYPES=newString[]{"image/*","video/*"};@OverridepublicContentInfoCompatonReceiveContent(Viewview,ContentInfoCompatcontentInfo){Pair<ContentInfoCompat,ContentInfoCompat>split=contentInfo.partition(item->item.getUri()!=null);ContentInfouriContent=split.first;ContentInforemaining=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.returnremaining;}}
앱에서 이미 인텐트 공유를 지원하면 콘텐츠 URI 처리에 앱별 로직을 재사용할 수 있습니다. 남아 있는 데이터를 반환하여 이 데이터의 처리를 플랫폼에 위임합니다.
OnReceiveContentListener API는 기존 키보드 이미지 API의 다음 버전으로 생각할 수 있습니다. 이 통합 API는 키보드 이미지 API의 기능과 일부 추가 기능을 지원합니다. 기기 및 기능 호환성은 Jetpack 라이브러리를 사용하는지 Android SDK의 네이티브 API를 사용하는지에 따라 다릅니다.
표 1. Jetpack의 지원되는 기능과 API 수준을 확인하세요.
작업 또는 기능
키보드 이미지 API에서 지원
통합 API에서 지원
키보드에서 삽입
예(API 수준 13 이상)
예(API 수준 13 이상)
길게 터치 메뉴에서 붙여넣기를 사용하여 삽입
아니요
예
드래그 앤 드롭을 사용하여 삽입
아니요
예(API 수준 24 이상)
표 2. 네이티브 API의 지원되는 기능과 API 수준
작업 또는 기능
키보드 이미지 API에서 지원
통합 API에서 지원
키보드에서 삽입
예(API 수준 25 이상)
예(Android 12 이상)
길게 터치 메뉴에서 붙여넣기를 사용하여 삽입
아니요
드래그 앤 드롭을 사용하여 삽입
아니요
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-08-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-08-27(UTC)"],[],[],null,["# Receive rich content\n\n**Figure 1.** The unified API provides a single place to handle incoming content regardless of the specific UI mechanism, such as pasting from the touch \\& hold menu or using drag-and-drop.\n\nUsers love images, videos, and other expressive content, but inserting and\nmoving this content in apps isn't always easy. To make it simpler for apps to\nreceive rich content, Android 12 (API level 31) introduces a unified API that\nlets your app accept content from any source: clipboard, keyboard, or dragging.\n\nYou can attach an interface, such as\n[`OnReceiveContentListener`](/reference/android/view/OnReceiveContentListener),\nto UI components and get a callback when content is inserted through any\nmechanism. The callback becomes the single place for your code to handle\nreceiving all content, from plain and styled text to markup, images, videos,\naudio files, and others.\n\nFor backward compatibility with previous Android versions, this API is also\navailable in AndroidX, starting from\n[Core 1.7](/jetpack/androidx/releases/core#1.7.0) and\n[Appcompat 1.4](/jetpack/androidx/releases/appcompat#1.4.0),\nwhich we recommend you use when implementing this functionality.\n\nOverview\n--------\n\nWith other existing APIs, each UI mechanism---such as the touch \\& hold menu\nor dragging---has its own corresponding API. This means that you have to\nintegrate with each API separately, adding similar code for each mechanism that\ninserts content:\n**Figure 2.** Previously, apps implemented a different API for each UI mechanism for inserting content.\n\nThe `OnReceiveContentListener` API consolidates these different code paths by\ncreating a single API to implement, so you can focus on your app-specific logic\nand let the platform handle the rest:\n**Figure 3.** The unified API lets you implement a single API that supports all UI mechanisms.\n\nThis approach also means that when new ways of inserting content are added to\nthe platform, you don't need to make additional code changes to enable support\nin your app. And if your app needs to implement full customization for a\nparticular use case, you can still use the existing APIs, which continue to work\nthe same way.\n\nImplementation\n--------------\n\n| **Note:** See the [Drag and Drop sample](https://github.com/android/platform-samples/tree/main/samples/user-interface/draganddrop) for a complete implementation of [`DropHelper`](/reference/kotlin/androidx/draganddrop/DropHelper), which implements `OnReceiveContentListener`. For more details, see the guide on [Enabling drag and drop](/develop/ui/views/touch-and-input/drag-drop).\n\nThe API is a listener interface with a single method,\n[`OnReceiveContentListener`](/reference/android/view/OnReceiveContentListener).\nTo support older versions of the Android platform, we recommend using the\nmatching\n[`OnReceiveContentListener`](/reference/androidx/core/view/OnReceiveContentListener)\ninterface in the AndroidX Core library.\n\nTo use the API, implement the listener by specifying what types of content your\napp can handle: \n\n### Kotlin\n\n```kotlin\nobject MyReceiver : OnReceiveContentListener {\n val MIME_TYPES = arrayOf(\"image/*\", \"video/*\")\n \n // ...\n \n override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {\n TODO(\"Not yet implemented\")\n }\n}\n```\n\n### Java\n\n```java\npublic class MyReceiver implements OnReceiveContentListener {\n public static final String[] MIME_TYPES = new String[] {\"image/*\", \"video/*\"};\n // ...\n}\n```\n\nAfter specifying all the content MIME types that your app supports, implement\nthe rest of the listener: \n\n### Kotlin\n\n```kotlin\nclass MyReceiver : OnReceiveContentListener {\n override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat {\n val split = contentInfo.partition { item: ClipData.Item -\u003e item.uri != null }\n val uriContent = split.first\n val remaining = split.second\n if (uriContent != null) {\n // App-specific logic to handle the URI(s) in uriContent.\n }\n // Return anything that your app didn't handle. This preserves the\n // default platform behavior for text and anything else that you aren't\n // implementing custom handling for.\n return remaining\n }\n\n companion object {\n val MIME_TYPES = arrayOf(\"image/*\", \"video/*\")\n }\n}\n```\n\n### Java\n\n```java\n public class MyReceiver implements OnReceiveContentListener {\n public static final String[] MIME_TYPES = new String[] {\"image/*\", \"video/*\"};\n\n @Override\n public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {\n Pair\u003cContentInfoCompat, ContentInfoCompat\u003e split = contentInfo.partition(\n item -\u003e item.getUri() != null);\n ContentInfo uriContent = split.first;\n ContentInfo remaining = split.second;\n if (uriContent != null) {\n // App-specific logic to handle the URI(s) in uriContent.\n }\n // Return anything that your app didn't handle. This preserves the\n // default platform behavior for text and anything else that you aren't\n // implementing custom handling for.\n return remaining;\n }\n }\n```\n\nIf your app already supports sharing with intents, you can reuse your\napp-specific logic for handling content URIs. Return any remaining data to\ndelegate handling of that data to the platform.\n\nAfter implementing the listener, set it on the appropriate UI elements in\nyour app: \n\n### Kotlin\n\n```kotlin\nclass MyActivity : Activity() {\n public override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n // ...\n val myInput = findViewById(R.id.my_input)\n ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver())\n }\n}\n```\n\n### Java\n\n```java\npublic class MyActivity extends Activity {\n @Override\n public void onCreate(Bundle savedInstanceState) {\n // ...\n\n AppCompatEditText myInput = findViewById(R.id.my_input);\n ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());\n }\n}\n```\n\nURI permissions\n---------------\n\nRead permissions are granted and released automatically by the platform for any\n[content URIs](/reference/android/content/ContentResolver#SCHEME_CONTENT) in the\npayload passed to the `OnReceiveContentListener`.\n\nNormally, your app processes content URIs in a service or activity. For\nlong-running processing, use\n[WorkManager](/topic/libraries/architecture/workmanager). When you implement\nthis, extend permissions to the target service or activity by passing the\ncontent using\n[`Intent.setClipData`](/reference/android/content/Intent#setClipData(android.content.ClipData))\nand [setting](/reference/android/content/Intent#addFlags(int)) the flag\n[`FLAG_GRANT_READ_URI_PERMISSION`](/reference/android/content/Intent#FLAG_GRANT_READ_URI_PERMISSION).\n\nAlternatively, you can use a background thread within the current context to\nprocess the content. In this case, you must maintain a reference to the\n`payload` object received by the listener to help ensure that permissions aren't\nrevoked prematurely by the platform.\n\nCustom views\n------------\n\nIf your app uses a custom `View` subclass, take care to ensure that the\n`OnReceiveContentListener` isn't bypassed.\n\nIf your `View` class overrides the\n[`onCreateInputConnection`](/reference/android/widget/TextView#onCreateInputConnection(android.view.inputmethod.EditorInfo))\nmethod, use the Jetpack API\n[`InputConnectionCompat.createWrapper`](/reference/androidx/core/view/inputmethod/InputConnectionCompat#createWrapper(android.view.View,%20android.view.inputmethod.InputConnection,%20android.view.inputmethod.EditorInfo))\nto configure the `InputConnection`.\n\nIf your `View` class overrides the\n[`onTextContextMenuItem`](/reference/android/widget/TextView#onTextContextMenuItem(int))\nmethod, delegate to super when the menu item is\n[`R.id.paste`](/reference/android/R.id#paste) or\n[`R.id.pasteAsPlainText`](/reference/android/R.id#pasteAsPlainText).\n\nComparison with the keyboard image API\n--------------------------------------\n\nYou can think of the `OnReceiveContentListener` API as the next version of the\nexisting [keyboard image API](/guide/topics/text/image-keyboard). This unified\nAPI supports the functionality of the keyboard image API as well as some\nadditional features. Device and feature compatibility varies depending on\nwhether you use the Jetpack library or the native APIs from the Android SDK.\n\n| Action or feature | Supported by keyboard image API | Supported by unified API |\n|------------------------------------------------|---------------------------------|-------------------------------|\n| Insert from the keyboard | Yes (API level 13 and higher) | Yes (API level 13 and higher) |\n| Insert using paste from the touch \\& hold menu | No | Yes |\n| Insert using drag-and-drop | No | Yes (API level 24 and higher) |\n[**Table 1.** Supported features and API levels for\nJetpack.]\n\n| Action or feature | Supported by keyboard image API | Supported by unified API |\n|------------------------------------------------|---------------------------------|-----------------------------|\n| Insert from the keyboard | Yes (API level 25 and higher) | Yes (Android 12 and higher) |\n| Insert using paste from the touch \\& hold menu | No | Yes (Android 12 and higher) |\n| Insert using drag and drop | No | Yes (Android 12 and higher) |\n[**Table 2.** Supported features and API levels for native\nAPIs.]"]]