Android's share sheet lets your app send content to other apps, and receive content from them. Custom share targets and Direct Share let you surface frequently-used contacts directly in the sheet.
Sending Content (Sharing Out)
// Share plain text
fun shareText(context: Context, text: String, title: String? = null) {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, text)
title?.let { putExtra(Intent.EXTRA_TITLE, it) }
}
context.startActivity(Intent.createChooser(intent, "Share via"))
}
// Share an image (URI — never a file path)
fun shareImage(context: Context, imageUri: Uri, message: String? = null) {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "image/*"
putExtra(Intent.EXTRA_STREAM, imageUri)
message?.let { putExtra(Intent.EXTRA_TEXT, it) }
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(Intent.createChooser(intent, "Share image"))
}
// Share multiple images
fun shareMultipleImages(context: Context, uris: List<Uri>) {
val intent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
type = "image/*"
putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(uris))
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(Intent.createChooser(intent, "Share images"))
}
// Share from Compose
@Composable
fun ShareButton(text: String) {
val context = LocalContext.current
IconButton(onClick = {
shareText(context, text)
}) {
Icon(Icons.Default.Share, contentDescription = "Share")
}
}
FileProvider: Safe URI Sharing
Never share file:// URIs — they're blocked since Android 7.0. Use FileProvider:
<!-- AndroidManifest.xml -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- res/xml/file_paths.xml -->
<paths>
<cache-path name="shared_images" path="share/" />
<files-path name="documents" path="documents/" />
</paths>
fun getShareUri(context: Context, file: File): Uri {
return FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
}
Receiving Content (Share Targets)
// In AndroidManifest.xml — declare your activity as a share target
// (in the activity element)
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
// Handle incoming share in Activity
class ShareReceiverActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIncomingShare()
}
private fun handleIncomingShare() {
when (intent?.action) {
Intent.ACTION_SEND -> {
if (intent.type == "text/plain") {
val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return
// Handle text
} else if (intent.type?.startsWith("image/") == true) {
val imageUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM) ?: return
// Handle image
}
}
Intent.ACTION_SEND_MULTIPLE -> {
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM) ?: return
// Handle multiple
}
}
}
}
Direct Share (API 29+)
// Publish share targets for contacts — these appear in the sharesheet
class DirectShareService : ChooserTargetService() {
// ChooserTargetService is deprecated; use ShortcutInfo for API 29+
}
// Preferred: ShortcutInfo-based direct share
fun publishShareTargets(context: Context, conversations: List<Conversation>) {
val shortcutManager = context.getSystemService(ShortcutManager::class.java)
val shortcuts = conversations.take(4).map { conv ->
ShortcutInfo.Builder(context, conv.id)
.setShortLabel(conv.name)
.setIcon(Icon.createWithBitmap(conv.avatar))
.setIntent(Intent(context, ShareReceiverActivity::class.java).apply {
action = Intent.ACTION_DEFAULT
putExtra("conversation_id", conv.id)
})
.setCategories(setOf("com.myapp.category.SHARE_TARGET"))
.setLongLived(true)
.build()
}
shortcutManager.pushDynamicShortcut(shortcuts.first())
}
Key Takeaways
| Pattern | Rule |
|---|---|
ACTION_SEND | Single file/text share; ACTION_SEND_MULTIPLE for batch |
| FileProvider | Always use for file:// → content:// conversion; never share raw file paths |
FLAG_GRANT_READ_URI_PERMISSION | Required when sharing URIs to other apps |
| Share target intent-filter | Declare MIME types your app can receive |
| ShortcutInfo for Direct Share | API 29+; use dynamic shortcuts with a share category |