androidengineers.Book a session

Core Android Components Deep Dive

Exercise: Build a Share-Target Flow

exercise45 minMedium

Making your app a share target lets users send content from other apps directly into yours. This exercise implements a complete share-target flow: receive text and images, then add Direct Share shortcuts.

Step 1: Declare the Intent Filter

<!-- AndroidManifest.xml -->
<activity android:name=".ShareActivity" android:exported="true">
    <!-- Receive plain text (URLs, notes) -->
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>

    <!-- Receive a single image -->
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>

    <!-- Receive multiple images -->
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

Step 2: Handle the Incoming Intent

class ShareActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_share)
        handleSharedContent(intent)
    }

    private fun handleSharedContent(intent: Intent) {
        when {
            // Single text/URL
            intent.action == Intent.ACTION_SEND &&
            intent.type?.startsWith("text/") == true -> {
                val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return
                val sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
                displaySharedText(sharedText, sharedSubject)
            }

            // Single image
            intent.action == Intent.ACTION_SEND &&
            intent.type?.startsWith("image/") == true -> {
                val imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
                } else {
                    @Suppress("DEPRECATION")
                    intent.getParcelableExtra(Intent.EXTRA_STREAM) as? Uri
                }
                imageUri?.let { displaySharedImage(it) }
            }

            // Multiple images
            intent.action == Intent.ACTION_SEND_MULTIPLE &&
            intent.type?.startsWith("image/") == true -> {
                val imageUris = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)
                } else {
                    @Suppress("DEPRECATION")
                    intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
                }
                imageUris?.forEach { displaySharedImage(it) }
            }
        }
    }

    private fun displaySharedText(text: String, subject: String?) {
        binding.titleText.text = subject ?: "Shared Link"
        binding.contentText.text = text
    }

    private fun displaySharedImage(uri: Uri) {
        // Grant temporary read permission before loading
        binding.imageView.load(uri)  // Coil handles URI permissions
    }
}

Step 3: Add Direct Share Targets (ChooserTarget API)

Direct Share shows contact shortcuts directly in the share sheet. Implement ChooserTargetService (legacy) or the modern ShortcutManager approach:

// Modern approach: publish sharing shortcuts via ShortcutManager
class ShareShortcutManager(private val context: Context) {

    fun publishShareTargets(contacts: List<Contact>) {
        val shortcuts = contacts.take(4).map { contact ->
            ShortcutInfoCompat.Builder(context, "contact_${contact.id}")
                .setShortLabel(contact.name)
                .setIcon(IconCompat.createWithBitmap(contact.avatar))
                .setIntent(
                    Intent(context, ShareActivity::class.java).apply {
                        action = Intent.ACTION_SEND
                        putExtra("recipient_id", contact.id)
                    }
                )
                .setCategories(setOf("com.example.myapp.directshare"))
                .setLongLived(true)  // Required for share targets
                .build()
        }
        ShortcutManagerCompat.pushDynamicShortcut(context, shortcuts.first())
        ShortcutManagerCompat.addDynamicShortcuts(context, shortcuts)
    }
}
<!-- Declare share target in shortcuts.xml -->
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <share-target android:targetClass="com.example.ShareActivity">
        <data android:mimeType="*/*" />
        <category android:name="com.example.myapp.directshare" />
    </share-target>
</shortcuts>
<!-- Reference in AndroidManifest activity -->
<activity android:name=".MainActivity">
    <meta-data
        android:name="android.app.shortcuts"
        android:resource="@xml/shortcuts" />
</activity>

Step 4: Test with adb

# Test text sharing
adb shell am start \
  -a android.intent.action.SEND \
  -t text/plain \
  --es android.intent.extra.TEXT "https://example.com" \
  -n com.example.myapp/.ShareActivity

# Verify your app appears in the share sheet
# Open any app → Share → check for your app

Common Pitfalls

ProblemFix
getParcelableExtra deprecated warningUse Build.VERSION.SDK_INT >= TIRAMISU branch with typed version
Image not loading — permission deniedDon't store the URI; load immediately before Activity is destroyed
App not appearing in share sheetCheck android:exported="true" and intent filter MIME types
Direct Share contacts not showingCall pushDynamicShortcut after user selects contacts; set setLongLived(true)
Crash on null intentAlways null-check EXTRA_STREAM and EXTRA_TEXT

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Exercise: Build a Share-Target Flow | Android System Design | Android Engineers