他のアプリからシンプルなデータを受信する

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

Compose Navigation を使用するアプリで、別のアプリから送信されたデータを受信するには、次の 2 つのステップが必要です。

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

  2. Compose ナビゲーション グラフで navDeepLink を定義する: Activity の onCreate メソッドまたは onNewIntent メソッド内で Intent を手動でインターセプトして解析する代わりに、Compose ナビゲーションのディープリンク サポートを使用します。アクションと MIME タイプに一致する navDeepLink を、コンテンツを表示するコンポーザブル デスティネーションに直接追加します。NavController は、Intent を自動的にインターセプトし、ユーザーをその画面に直接ルーティングします。

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

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 公式レジストリを参照してください。

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

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

アクティビティでデータを受け取る

アクティビティでデータを受信するには、マニフェストを更新し、受信したコンテンツを処理して、ユーザーがアプリを認識できるようにする必要があります。

マニフェストを更新する

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

<activity android:name=".ui.MyActivity" >
    <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 内でコンテンツを適切に処理するのはユーザーの責任となります。

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

Intent によって配信されたコンテンツを処理するには、getIntent() を呼び出して Intent オブジェクトを取得します。オブジェクトを取得したら、その内容を調べて、次の操作を決定できます。このアクティビティがシステムの他の部分(ランチャーなど)から開始できる場合は、インテントを調べる際にこの点を考慮してください。

他のアプリケーションから何が送られてくるかわからないため、受信データは慎重に確認してください。たとえば、MIME タイプが誤って設定されている場合や、送信された画像が極端に大きい場合などがあります。また、バイナリデータはメイン(「UI」)スレッドではなく、別のスレッドで処理してください。

@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
    }
}

データを受信した後に 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 タグで設定されたアイコンを無視します。