他のアプリからデータを受信する

アプリは、他のアプリにデータを送信できるだけでなく、他のアプリからデータを受信することもできます。ユーザーがアプリケーションをどのように操作するか、他のアプリケーションからどのようなデータタイプを受け取るかを検討します。たとえば、ソーシャル ネットワーキング アプリケーションは、別のアプリから興味深いウェブ URL などのテキスト コンテンツを受け取ることを望んでいる可能性があります。

Compose Navigation を使用するアプリで、別のアプリから送信されたデータを受信するプロセスは、次の 3 つのステップで構成されます。

  1. マニフェストで <intent-filter> を宣言する: AndroidManifest.xml ファイルでアクティビティにインテント フィルタを追加する必要があります。これにより、アプリが特定のアクション(ACTION_SEND など)と MIME タイプ(text/plain など)を受信できることを Android OS に通知します。

  2. Compose Navigation グラフで navDeepLink を定義します。アクションと MIME タイプに一致する navDeepLink を、コンテンツを表示するコンポーザブル デスティネーションに直接アタッチします。NavController は、受信したインテントを自動的にインターセプトし、ユーザーをその画面に直接ルーティングします。

  3. 受信したデータ ペイロードを抽出する: 宛先画面で、インテント エクストラ(EXTRA_TEXT や EXTRA_STREAM など)にアクセスして、共有コンテンツを取得し、UI の状態を更新します。

ダイレクト シェア ターゲットは、アプリ内の特定のアクティビティへのディープリンクです。多くの場合、個人またはグループを表し、Android Sharesheet に表示されます。たとえば、メッセージ アプリは、ユーザーとの会話に直接ディープリンクするユーザーの Direct Share ターゲットを提供できます。詳しい手順については、Direct Share ターゲットを提供するをご覧ください。

MIME タイプをサポートする

理想的には、アプリは可能な限り幅広い MIME タイプを受信できる必要があります。たとえば、テキスト、画像、動画の送信用に設計されたメッセージ アプリは、text/*、image/*、video/* の受信をサポートすることが理想的です。Android でデータを送受信するための一般的な MIME タイプをいくつか紹介します。

受信者が登録する 送信者が送信する
text/*
  • text/plain
  • text/rtf
  • text/html
  • text/json
image/*
  • image/jpg
  • image/png
  • image/gif
video/*
  • video/mp4
  • video/3gp
サポートされているファイル拡張子 application/pdf

MIME メディアタイプの IANA 公式レジストリをご覧ください。

優れた共有ターゲットを作成する

ユーザーが特定のアクティビティに関連付けられた共有ターゲットをタップした場合は、アプリが共有コンテンツを使用する前に、ユーザーが共有コンテンツを確認して編集できるようにします。これは、テキストデータで特に重要です。

アプリでデータを受け取る

Compose を使用するアプリで共有データを受信するには、マニフェストでインテント フィルタを宣言し、受信したインテントをディープリンクで適切な画面にルーティングして、インテントからペイロードを抽出して UI を更新します。

マニフェストを更新する

インテント フィルタは、アプリ コンポーネントが受け入れるインテントをシステムに通知します。他のアプリにデータを送信するレッスンで ACTION_SEND アクションを含むインテントを作成したのと同様に、このアクションを含むインテントを受信するためのインテント フィルタを作成します。インテント フィルタは、<intent-filter> 要素を使用してマニフェストで定義します。たとえば、アプリがテキスト コンテンツの受信を処理する場合、任意のタイプの画像を 1 つ以上含むマニフェストは、次のスニペットのようになります。

<activity android:name=".ui.MyActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <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_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

別のアプリがインテントを作成して startActivity() に渡すことで、これらのいずれかを共有しようとすると、アプリが Android Sharesheet またはインテント リゾルバにオプションとして表示されます。ユーザーがアプリを選択すると、対応するアクティビティ(上記の例では .ui.MyActivity)が開始されます。その後、コードと UI 内でコンテンツを適切に処理するのはユーザーの責任となります。

Compose Navigation では、コンテンツを表示するコンポーザブル デスティネーションに navDeepLink を直接アタッチします。別のアプリがインテント フィルタに一致するデータを共有すると、Compose Navigation はユーザーをこの宛先に直接ルーティングします。

navDeepLink は、受信インテントのアクションと MIME タイプを照合して、正しいデスティネーション画面に移動します。そのデスティネーションに到達すると、ハンドラはインテントを検査して、受信したペイロード(単一の画像と複数の画像など)を特定し、対応するエクストラを抽出します。

受信コンテンツを処理する

Intent によって配信されたコンテンツを取得するには、コンポーズ可能な関数内の LocalActivity.current から現在のアクティビティを読み取り、インテントを調べて次に何を行うかを決定します。このアクティビティをシステムの他の部分(ランチャーなど)から開始できる場合は、インテントを調べるときにこの点を考慮してください。

受信データのチェックには特に注意してください。間違った MIME タイプが設定されている場合や、送信される画像が非常に大きい場合があります。バイナリデータや負荷の高い I/O オペレーション(大きな画像のデコードやファイルの書き込みなど)は、メイン UI スレッドではなく、コルーチン(Dispatchers.IO など)を使用して非同期で処理します。

@Composable
fun SharesheetHandler() {
    val activity = LocalActivity.current
    val intent = activity?.intent

    when (intent?.action) {
        Intent.ACTION_SEND -> {
            if (intent.type == "text/plain") {
                handleSendText(intent) // Handle text being sent
            } else if (intent.type?.startsWith("image/") == true) {
                handleSendImage(intent) // Handle single image being sent
            }
        }

        Intent.ACTION_SEND_MULTIPLE -> {
            if (intent.type?.startsWith("image/") == true) {
                handleSendMultipleImages(intent) // Handle multiple images being sent
            }
        }

        else -> {
            // Handle other intents, such as being started from the home screen
        }
    }
}

private fun handleSendText(intent: Intent) {
    intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
        // Update UI state with the shared text
    }
}

private fun handleSendImage(intent: Intent) {
    val imageUri = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUri?.let {
        // Update UI state with the shared image
    }
}

private fun handleSendMultipleImages(intent: Intent) {
    val imageUris =
        IntentCompat.getParcelableArrayListExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUris?.let {
        // Update UI state with the shared images
    }
}

インテント エクストラ(EXTRA_STREAM など)からバイナリデータまたは URI を抽出する場合は、上記の handleSendImage 関数と handleSendMultipleImages 関数に示すように、AndroidX Core ライブラリの IntentCompat.getParcelableExtra() または IntentCompat.getParcelableArrayListExtra() を使用します。Android 13(API レベル 33)では、パラメータ化されていない Intent.getParcelableExtra(String) メソッドが非推奨となり、想定されるクラスタイプを受け取るタイプセーフなメソッドが推奨されます。

データを受信した後に UI を更新する処理は、TextField にデータを入力するために状態を更新するような単純なものから、画像にフィルタを適用するような複雑なものまでさまざまです。次に何が起こるかはアプリ次第です。

スクリーンショットの URL の共有

スクリーンショットを撮影すると、スクリーンショットと関連する URL を共有できます。 これにより、より充実したユーザー エクスペリエンスが実現します。URL を受け取るときは、次の例に示すように、インテントから EXTRA_TEXT フィールドを取得してください。

IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java).let {
    // Handle the EXTRA_TEXT as well
    val extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)
    // Update UI state with the shared image and the EXTRA_TEXT if available
}

アプリがユーザーに認識されるようにする

アプリは、Android Sharesheet とインテント リゾルバでアイコンとラベルによって表されます。これらは両方ともマニフェストで定義されています。アクティビティまたはインテント フィルタのラベルを設定して、より多くのコンテキストを提供できます。

Android 10(API レベル 29)以降、Android Sharesheet は、マニフェストの application タグで設定されたアイコンのみを使用します。Android は、intent-filter タグと activity タグで設定されたアイコンを無視します。

リッチ コンテンツを受信する

ACTION_SEND インテントを使用すると、アクティビティまたはナビゲーション レベルで Android Sharesheet とインテント リゾルバからデータを受け取ることができますが、アプリは直接 UI 操作を通じてリッチ コンテンツ(画像、動画、音声ファイル、スタイル付きテキストなど)を受け取ることもできます。このようなメカニズムには、以下が含まれます。

  • クリップボードから貼り付ける(長押しメニュー)
  • ソフトウェア キーボード(IME)からステッカーや GIF などのメディアを直接挿入する
  • マルチ ウィンドウ モードまたは分割画面モードで別のアプリからコンテンツをドラッグ&ドロップする

ビューベースの UI では、Android 12(API レベル 31)と AndroidX Core 1.7 で、統合された OnReceiveContentListener API が導入されています。このリスナーは、クリップボード、キーボード、ドラッグ&ドロップからのコンテンツ処理を 1 つのコールバックに統合します。ビューにこれを実装する詳細な手順については、リッチ コンテンツを受信するをご覧ください。

Jetpack Compose では、Modifier.contentReceiver 修飾子またはドラッグ&ドロップ修飾子を使用して、UI コンポーネント(テキスト フィールドなど)に挿入されたリッチ コンテンツの受信を処理できます。