Android では、ユーザーがアプリ間でデータを共有するのに、2 つの方法があります。
- 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 タイプを設定し、次の例に示すように、データの URI をエクストラ EXTRA_STREAM に配置します。
これは通常、画像を共有するために使用されますが、あらゆるタイプのバイナリ コンテンツを共有するために使用できます。
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 が指すデータにアクセスする権限が必要です。これを行うには、次の 2 つの方法をおすすめします。
- 独自の
ContentProviderにデータを保存し、他のアプリがプロバイダにアクセスするための適切な権限を持っていることを確認します。アクセス権を付与する推奨メカニズムは、URI ごとの権限を使用することです。これは 一時的なものであり、受信側のアプリケーションにのみアクセス権を付与します。このようなContentProviderを作成するには、FileProviderヘルパークラスを使用します。 - システム
MediaStoreを使用します。MediaStoreは本来、動画、音声、画像の MIME タイプのためのものです。ただし、Android 3.0(API レベル 11)以降では、メディア以外のタイプも保存できます。詳細については、MediaStore.Filesをご覧ください。scanFile()を使用してファイルをMediaStoreに挿入でき、その後、与えられたonScanCompleted()コールバックに、共有に適したcontent://スタイルのUriが渡されます。システム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 メディアタイプの公式レジストリをご覧ください。
Android Sharesheet には、指定された MIME タイプに応じてコンテンツのプレビューが表示されることがあります。一部の プレビュー機能は、特定のタイプでのみ使用できます。
複数のコンテンツを共有する
複数のコンテンツを共有するには、ACTION_SEND_MULTIPLE アクションと、コンテンツを指す URI のリストを組み合わせて使用します。MIME タイプは、共有するコンテンツの組み合わせによって異なります。たとえば、3 つの 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 を使用して、アプリの候補の前に表示されるカスタム アクティビティ インテントを最大 2 つ指定できます。
直接共有ターゲット(会話や連絡先など)の場合は、代わりに
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 を作成し、その IntentSender を Intent.createChooser() に指定します。
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 タイプが一致するフィルタを持つアプリケーションが複数インストールされている場合、システムは、インテント リゾルバと呼ばれる曖昧さ回避のダイアログを表示して、ユーザーが共有先を選択できるようにします。一致するアプリケーションが 1 つであれば、そのアプリケーションが実行されます。
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) }
詳細
データの送信について詳しくは、 インテントとインテント フィルタをご覧ください。