Android에서는 사용자가 두 가지 방식으로 앱 간에 데이터를 공유할 수 있습니다.
- Android Sharesheet는 주로 앱 외부나 다른 사용자에게 직접 콘텐츠를 보내도록 설계되었습니다. 예를 들어, 친구와 URL을 공유합니다.
- Android 인텐트 리졸버는 데이터를 잘 정의된 작업의 다음 단계로 전달하는 데 가장 적합합니다. 예를 들어 앱에서 PDF를 열고 사용자가 선호하는 뷰어를 선택하도록 합니다.
Android Sharesheet를 사용하는 이유
Android Sharesheet를 사용하여 앱 전반에서 사용자에게 일관성을 제공합니다. 앱의 공유 대상 목록을 표시하거나 자체 Sharesheet 변형을 만들지 마세요.
Android Sharesheet를 사용하면 사용자가 한 번의 탭으로 관련 앱 추천과 함께 적절한 사람과 정보를 공유할 수 있습니다. Sharesheet는 맞춤 솔루션에 사용할 수 없는 대상을 제안할 수 있으며 일관된 순위 지정을 사용합니다. 이는 Sharesheet가 시스템에서만 사용할 수 있는 앱 및 사용자 활동에 관한 정보를 고려할 수 있기 때문입니다.
또한 Android Sharesheet에는 개발자를 위한 여러 가지 편리한 기능이 있습니다. 예를 들어 다음과 같은 작업이 가능합니다.
- 사용자가 공유를 완료한 시기와 위치 확인
- 맞춤 타겟팅 및 앱 대상 추가
- Android 10 (API 수준 29)부터 서식 있는 텍스트 콘텐츠 미리보기 제공
- 특정 구성요소 이름과 일치하는 대상 제외
Android Sharesheet 사용
모든 유형의 공유에서 인텐트를 만들고 작업을 Intent.ACTION_SEND로 설정합니다.
Android Sharesheet를 표시하려면
Intent.createChooser(),
호출하여 Intent 객체를 전달합니다.
항상 Android Sharesheet를 표시하는 인텐트 버전을 반환합니다.
텍스트 콘텐츠 전송
Android Sharesheet의 가장 간단하고 일반적인 사용은 한 활동에서 다른 활동으로 텍스트 콘텐츠를 전송하는 것입니다. 예를 들어 대부분의 브라우저는 현재 표시된 페이지의 URL을 텍스트로 다른 앱과 공유할 수 있습니다. 이는 이메일이나 소셜 네트워킹을 통해 친구와 기사나 웹사이트를 공유하는 데 유용합니다. Jetpack Compose에서 LocalContext.current를 사용하여 현재 컨텍스트를 가져오고 context.startActivity()를 호출합니다.
다음은 그 방법을 보여주는 예입니다.
fun shareText(context: Context) { val sendIntent: Intent = Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "This is my text to send.") type = "text/plain" } val shareIntent = Intent.createChooser(sendIntent, null) context.startActivity(shareIntent) }
선택적으로 이메일 수신자(EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC) 또는 이메일 제목(EXTRA_SUBJECT)과 같은 추가 정보를 포함하도록 추가 항목을 추가할 수 있습니다.
참고: Gmail과 같은 일부 이메일 앱은 EXTRA_EMAIL 및 EXTRA_CC와 같은 추가 항목에 String[]을 예상합니다. putExtra(String, String[])를 사용하여 인텐트에 추가합니다.
바이너리 콘텐츠 전송
ACTION_SEND 작업을 사용하여 바이너리 데이터를 공유합니다.
다음 예와 같이 적절한 MIME 유형을 설정하고 추가 항목 EXTRA_STREAM에 데이터의 URI를 배치합니다.
이는 흔히 사용되는 이미지를 공유하는 데 사용되지만 모든 유형의 바이너리 콘텐츠를 공유하는 데 사용할 수 있습니다.
fun shareBinaryContent(context: Context) { val shareIntent: Intent = Intent().apply { action = ACTION_SEND // Example: content://com.google.android.apps.photos.contentprovider/... val imageUri: Uri = Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1") putExtra(Intent.EXTRA_STREAM, imageUri) type = "image/jpeg" } context.startActivity(Intent.createChooser(shareIntent, null)) }
수신 애플리케이션에는 Uri가 가리키는 데이터에 액세스할 수 있는 권한이 필요합니다. 이를 위한 두 가지 권장 방법은 다음과 같습니다.
- 다른 앱에 제공자에 액세스할 수 있는 올바른 권한이 있는지 확인하면서 자체
ContentProvider에 데이터를 저장합니다. 액세스 권한을 제공하는 기본 메커니즘은 일시적이며 수신 애플리케이션에만 액세스 권한을 부여하는 URI별 권한을 사용하는 것입니다. 이와 같은ContentProvider를 만들려면FileProvider도우미 클래스를 사용합니다. - 시스템
MediaStore를 사용합니다.MediaStore는 주로 동영상, 오디오, 이미지 MIME 유형에 사용됩니다. 하지만 Android 3.0 (API 수준 11)부터 미디어가 아닌 유형도 저장할 수 있습니다. 자세한 내용은MediaStore.Files를 참고하세요. 파일은scanFile()을 사용하여MediaStore에 삽입할 수 있으며, 그 후 공유에 적합한content://-스타일Uri가 제공된onScanCompleted()콜백에 전달됩니다. 시스템MediaStore에 추가되면 기기의 모든 앱에서 콘텐츠에 액세스할 수 있습니다.
올바른 MIME 유형 사용
전송하는 데이터에 사용할 수 있는 가장 구체적인 MIME 유형을 제공합니다. 예를 들어 일반 텍스트를 공유할 때는 text/plain을 사용합니다. 다음은 Android에서 데이터를 전송할 때의 몇 가지 일반적인 MIME 유형입니다.
| 수신자가 등록하는 항목 | 발신자가 전송하는 항목 |
|---|---|
text/* |
|
image/* |
|
video/* |
|
| 지원되는 파일 확장자 | application/pdf |
하드 코딩하는 대신 런타임에 MIME 유형을 동적으로 결정하려면 다음 메서드를 사용하세요.
content://URI (FileProvider또는MediaStore에서 제공하는 URI)의 경우ContentResolver.getType()을 호출합니다.- 파일 확장자의 경우
MimeTypeMap.getSingleton().getMimeTypeFromExtension()을 호출합니다. - Storage Access Framework를 사용하는 경우
DocumentFile.getType()을 쿼리할 수도 있습니다.
특정 MIME 유형을 결정할 수 없는 경우 일반 바이너리 데이터에는 application/octet-stream을 사용하고 최후의 수단으로 */*를 사용합니다.
MIME 유형에 관한 자세한 내용은 IANA 공식 MIME 미디어 유형 레지스트리를 참고하세요.
제공된 MIME 유형에 따라 Android Sharesheet에 콘텐츠 미리보기가 표시될 수 있습니다. 일부 미리보기 기능은 특정 유형에만 사용할 수 있습니다.
여러 콘텐츠 공유
여러 콘텐츠를 공유하려면 콘텐츠를 가리키는 URI 목록과 함께 ACTION_SEND_MULTIPLE 작업을 사용합니다. MIME 유형은 공유하는 콘텐츠의 조합에 따라 다릅니다. 예를 들어 JPEG 이미지 세 개를 공유하는 경우 "image/jpg" 유형을 사용합니다. 이미지 유형이 혼합된 경우 "image/*"를 사용하여 모든 유형의 이미지를 처리하는 활동과 일치시킵니다. 유형을 혼합하여 공유할 수 있지만 수신자에게 전송하려는 항목이 명확하지 않으므로 이렇게 하지 않는 것이 좋습니다. 여러 유형을 전송해야 하는 경우 "*/*"를 사용합니다. 데이터를 파싱하고 처리하는 것은 수신 애플리케이션에 달려 있습니다. 다음은 그 예입니다.
fun shareMultiple(context: Context) { val imageUris: ArrayList<Uri> = arrayListOf( Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1"), Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/2") ) val shareIntent = Intent().apply { action = Intent.ACTION_SEND_MULTIPLE putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris) type = "image/*" } context.startActivity(Intent.createChooser(shareIntent, null)) }
제공된 Uri 객체가 수신 애플리케이션에서 액세스할 수 있는 데이터를 가리키는지 확인합니다.
텍스트 미리보기에 리치 콘텐츠 추가
Android 10 (API 수준 29)부터 Android Sharesheet에 공유되는 텍스트의 미리보기가 표시됩니다. 경우에 따라 공유 중인 텍스트를 이해하기 어려울 수 있습니다. https://www.google.com/search?ei=2rRVXcLkJajM0PEPoLy7oA4와 같은 복잡한 URL을 공유하는 것을 고려해 보세요. 더 풍부한 미리보기를 통해 사용자는 공유되는 항목을 확인할 수 있습니다.
텍스트를 미리 보는 경우 제목, 썸네일 이미지 또는 둘 다 설정할 수 있습니다. Intent.createChooser()를 호출하기 전에 Intent.EXTRA_TITLE에 설명을 추가하고 ClipData를 사용하여 관련 썸네일을 추가합니다.
참고: 이미지 콘텐츠 URI는
FileProvider에서 제공되며 일반적으로 구성된 <cache-path>에서 제공됩니다.
자세한 내용은 파일 공유를 참고하세요. 썸네일로 사용하려는 이미지를 읽을 수 있는 올바른 권한을 Sharesheet에 부여해야 합니다. 자세한 내용은 Intent.FLAG_GRANT_READ_URI_PERMISSION을 참고하세요.
다음은 그 예입니다.
fun richContentToTextPreviewShares(context: Context) { val share = Intent.createChooser( Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/") // (Optional) Here you're setting the title of the content putExtra(Intent.EXTRA_TITLE, "Introducing content previews") // (Optional) Here you're passing a content URI to an image to be displayed data = Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/A123456789") flags = Intent.FLAG_GRANT_READ_URI_PERMISSION }, null ) context.startActivity(share) }
미리보기는 다음과 같습니다.
Sharesheet에 맞춤 작업 추가
Android 14 (API 수준 34) 및 이후 버전에서는 앱이 Android Sharesheet에 맞춤 액션을 추가할 수 있습니다.
맞춤 액션은 Android Sharesheet 상단에 작은 작업 아이콘으로 표시되며 앱은 아이콘을 클릭할 때 호출되는 작업으로 Intent를 지정할 수 있습니다.
Android Sharesheet에 맞춤 액션을 추가하려면 먼저
ChooserAction를 ChooserAction.Builder 사용하여 만듭니다.
아이콘을 클릭할 때 호출되는 작업으로 PendingIntent를 지정할 수 있습니다. 모든 맞춤 액션이 포함된 배열을 만들고 공유 Intent의 EXTRA_CHOOSER_CUSTOM_ACTIONS로 지정합니다.
fun sharesheetCustomActions(context: Context, previewText: String) { val sendIntent = Intent(ACTION_SEND) .setType("text/plain") .putExtra(Intent.EXTRA_TEXT, previewText) val shareIntent = Intent.createChooser(sendIntent, null) val customActions = arrayOf( ChooserAction.Builder( Icon.createWithResource(context, R.drawable.ic_logo), "Custom", PendingIntent.getBroadcast( context, 1, Intent(Intent.ACTION_VIEW), PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT ) ).build() ) shareIntent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, customActions) context.startActivity(shareIntent) }
맞춤 타겟팅 추가
Android Sharesheet를 사용하면 Intent.EXTRA_INITIAL_INTENTS를 사용하여 앱 추천 전에 나열되는 최대 두 개의 맞춤 활동 인텐트를 지정할 수 있습니다.
직접 공유 대상 (예: 대화 또는 연락처)의 경우
ShortcutManagerCompat 대신
`ShortcutManagerCompat`를 사용하여 동적 바로가기를 게시합니다(직접 공유 대상 제공 참고).
Intent.createChooser()를 호출한 후 공유 인텐트에 Intent.EXTRA_INITIAL_INTENTS를 추가합니다.
val sendIntent = Intent(ACTION_SEND).apply { type = "text/plain" putExtra(Intent.EXTRA_TEXT, previewText) } val customIntent = Intent().apply { component = ComponentName(context.packageName, "${context.packageName}.CustomActivity") } val shareIntent = Intent.createChooser(sendIntent, null).apply { putExtra( Intent.EXTRA_INITIAL_INTENTS, arrayOf(customIntent) ) } context.startActivity(shareIntent)
이 기능은 주의해서 사용하세요. 추가하는 모든 맞춤 Intent는 시스템에서 추천하는 수를 줄입니다. 일반적으로 맞춤 타겟팅을 추가하지 않는 것이 좋습니다. Intent.EXTRA_INITIAL_INTENTS를 추가하는 일반적인 적절한 예는 사용자가 공유 콘텐츠에 대해 취할 수 있는 추가 작업을 제공하는 것입니다. 예를 들어 사용자가 이미지를 공유하고 Intent.EXTRA_INITIAL_INTENTS를 사용하여 대신 링크를 보낼 수 있습니다.
구성요소별로 특정 대상 제외
Intent.EXTRA_EXCLUDE_COMPONENTS를 제공하여 특정 대상을 제외할 수 있습니다.
이 작업은 제어할 수 있는 대상을 삭제하는 경우에만 실행하세요. 일반적인 사용 사례는 사용자가 앱 내에서 공유할 때 앱의 공유 대상을 숨기는 것입니다. 이는 사용자가 앱 외부에서 공유하려는 의도일 가능성이 높기 때문입니다.
Intent.createChooser()를 호출한 후 인텐트에 Intent.EXTRA_EXCLUDE_COMPONENTS를 추가합니다.
fun excludeSpecificTargets(context: Context) { val share = Intent.createChooser(Intent(ACTION_SEND), null).apply { // Only use for components you have control over val excludedComponentNames = arrayOf(ComponentName("com.example.android", "ExampleClass")) putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames) } context.startActivity(share) }
공유에 관한 정보 가져오기
사용자가 공유하는 시점과 선택하는 대상을 파악하는 것이 유용할 수 있습니다. Android Sharesheet를 사용하면 IntentSender를 사용하여 사용자가 선택한 대상의 ComponentName을 제공하여 이 정보를 가져올 수 있습니다.
먼저 BroadcastReceiver의 PendingIntent를 만들고 Intent.createChooser()에 IntentSender를 제공합니다.
fun infoAboutSharing(context: Context, requestCode: Int) { var share = Intent(ACTION_SEND) // ... val pi = PendingIntent.getBroadcast( context, requestCode, Intent(context, ShareBroadcastReceiver::class.java), PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) share = Intent.createChooser(share, null, pi.intentSender) context.startActivity(share) }
MyBroadcastReceiver에서 콜백을 수신하고 Intent.EXTRA_CHOOSER_RESULT를 확인합니다.
override fun onReceive(context: Context?, intent: Intent) { val TAG = ShareBroadcastReceiver::class.simpleName val chooserResult: ChooserResult? = IntentCompat.getParcelableExtra( intent, Intent.EXTRA_CHOOSER_RESULT, ChooserResult::class.java, ) chooserResult?.let { Log.i(TAG, "Share callback: isShortcut: ${it.isShortcut}, type: ${typeToString(it.type)}, componentName: ${it.selectedComponent}", ) } ?: Log.i(TAG, "chooserResult is null") }
자세한 내용은 플랫폼 공유 샘플을 참고하세요.
Android 인텐트 리졸버 사용
ACTION_SEND 인텐트 리졸버Android 인텐트 리졸버는 잘 정의된 작업 흐름의 일부로 데이터를 다른 앱에 전송할 때 가장 적절하게 사용할 수 있습니다.
Android 인텐트 리졸버를 사용하려면 인텐트를 만들고 Android Sharesheet를 호출할 때와 같이 추가 항목을 추가합니다. 하지만 호출하지 마세요
Intent.createChooser().
ACTION_SEND 및 MIME 유형과 일치하는 필터가 있는 설치된 애플리케이션이 여러 개 있는 경우 시스템은 사용자가 공유할 대상을 선택할 수 있는 인텐트 리졸버 라는 명확성 대화상자를 표시합니다. 일치하는 애플리케이션이 하나인 경우 실행됩니다.
다음은 Android 인텐트 리졸버를 사용하여 텍스트를 전송하는 방법을 보여주는 예입니다.
fun intentResolver(context: Context) { val sendIntent: Intent = Intent().apply { action = ACTION_SEND putExtra(Intent.EXTRA_TEXT, "This is my text to send.") type = "text/plain" } context.startActivity(sendIntent) }
자세히 알아보기
데이터 전송에 관한 자세한 내용은 인텐트 및 인텐트 필터를 참고하세요.