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

アプリは、他のアプリにデータを送信できるだけでなく、他のアプリからデータを受信することもできます。ユーザーがアプリケーションをどのように操作するか、他のアプリケーションからどのようなデータタイプを受け取るかを検討します。たとえば、ソーシャル ネットワーキング アプリは、別のアプリからテキスト コンテンツ(興味深いウェブ 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 操作を通じてリッチ コンテンツ(画像、動画、音声ファイル、スタイル付きテキストなど)を受信することもできます。このようなメカニズムには、以下が含まれます。

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

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

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