Implementing the New Approach
In effect, Android 10 allows dynamic shortcuts to serve as share targets, in lieu of using a ChooserTargetService
.
However, it will be years before Android 10 and higher devices become dominant. Google is making available an AndroidX library that uses the new Android 10 solution on compatible devices and falls back to ChooserTargetService
for older ones.
The ShareTargets
sample module in the book’s sample project demonstrates how this works.
Add the Dependency
The AndroidX dependency that lets Android 10 share targets work on older devices is androidx.sharetarget
:
implementation "androidx.sharetarget:sharetarget:$sharetarget_version"
sharetarget_version = "1.0.0-beta02"
This library provides a ChooserTargetService
implementation called androidx.sharetarget.ChooserTargetServiceCompat
. We get its <service>
manifest element automatically through the manifest merger process. However, we have to add an android.service.chooser.chooser_target_service
<meta-data>
element to the <activity>
element that represents our ACTION_SEND
implementation, where the <meta-data>
points to this supplied service:
<activity android:name=".ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
<meta-data
android:name="android.service.chooser.chooser_target_service"
android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
</activity>
Declare Share Targets
We then need to have an XML resource (res/xml/
) that contains our share targets. For projects that already use static shortcuts, you can add a <share-target>
element to your existing static shortcuts resource. Otherwise, you will need to create one.
So, our sample module has a res/xml/share_targets.xml
resource to fulfill this requirement:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<share-target android:targetClass="com.commonsware.android.q.sharetargets.ShareActivity">
<data android:mimeType="*/*" />
<category android:name="com.commonsware.android.q.sharetargets.CUSTOM_SHARE_TARGET" />
</share-target>
</shortcuts>
Your <share-target>
element will need an android:targetClass
attribute, containing the fully-qualified class name of the ACTION_SEND
activity. You also need:
- A
<data>
element identifying the MIME type pattern that you wish to receive - A
<category>
element with a unique “category” name
In this case, the category is not an <intent-filter>
category. Rather, it is simply an identifier that we will use to connect this <share-target>
element with some corresponding dynamic shortcuts.
You can have as many <share-target>
elements as needed, though a typical app will not need more than one ACTION_SEND
activity. An individual <share-target>
element can have as many <data>
and <category>
elements as needed, and in this case, more than one <data>
element may be needed to match the desired roster of MIME types.
As with regular static shortcuts, this XML resource needs to be identified by a android.app.shortcuts
<meta-data>
element on the LAUNCHER
<activity>
element:
<activity
android:name=".MainActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="${applicationId}.ACTION_WHATEVER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/share_targets" />
</activity>
(we will discuss that odd second <intent-filter>
shortly)
Register Dynamic Shortcuts
We then need to register dynamic shortcuts using ShortcutManager
(or the AndroidX ShortcutManagerCompat
). These represent the actual entries that should show up in the “share sheet” UI. And, in particular, they need to have a category that matches a category used in a <share-target>
element from the shortcuts XML resource.
The app’s MainActivity
will create those dynamic shortcuts in onCreate()
, if they have not already been registered:
package com.commonsware.android.q.sharetargets
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
data class ShareTarget(
val id: String,
@StringRes val shortLabelRes: Int,
@DrawableRes val iconRes: Int
)
private val SHARE_CATEGORIES =
setOf("com.commonsware.android.q.sharetargets.CUSTOM_SHARE_TARGET")
private val TARGETS = listOf(
ShareTarget("one", R.string.tag_one, R.drawable.ic_looks_one_black_24dp),
ShareTarget("two", R.string.tag_two, R.drawable.ic_looks_two_black_24dp),
ShareTarget("five", R.string.tag_five, R.drawable.ic_looks_5_black_24dp)
)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (ShortcutManagerCompat.getDynamicShortcuts(this).size == 0) {
val intent = Intent("$packageName.ACTION_WHATEVER")
ShortcutManagerCompat.addDynamicShortcuts(this, TARGETS.map { tag ->
ShortcutInfoCompat.Builder(this, tag.id)
.setShortLabel(getString(tag.shortLabelRes))
.setIcon(IconCompat.createWithResource(this, tag.iconRes))
.setIntent(intent)
.setLongLived(true)
.setCategories(SHARE_CATEGORIES)
.build()
})
Toast.makeText(this, "Share targets ready!", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(this, "${intent.action} received!", Toast.LENGTH_LONG).show()
}
finish()
}
}
Here, we iterate over a TARGETS
list of ShareTarget
objects. Those simply aggregate some metadata that we need for the dynamic shortcuts: an ID, an icon, and a label. We convert those to ShortcutInfoCompat
objects via ShortcutInfoCompat.Builder
. Each of those ShortcutInfoCompat
objects also gets:
- A set of categories (
CATEGORIES
) that includes the category that we used in the<share-target>
element - An
Intent
for a custom action (ACTION_WHATEVER
in the namespace of the application), and thatIntent
will be used if the user actually uses this dynamic shortcut
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.