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

図 1. Unified API は、特定の UI メカニズムに縛られず、長押しメニューからの貼り付けやドラッグ&ドロップなどで受信コンテンツを処理できる単一の場所を提供します。

ユーザーは画像、動画、およびその他の表現力豊かなコンテンツを好みますが、そうしたコンテンツをアプリに挿入することは必ずしも容易ではありません。Android 12(API レベル 31)には、アプリがリッチ コンテンツをより簡単に受信できるよう、任意のソース(クリップボード、キーボード、ドラッグ&ドロップ)からコンテンツを受け取れる Unified API が導入されました。

OnReceiveContentListener というインターフェースを UI コンポーネントに接続すると、任意のメカニズムを通じてコンテンツが挿入されたときにコールバックを取得できます。コードでは、このコールバック 1 か所で、プレーン テキストや書式付きテキストからマークアップ、画像、動画、音声ファイルまで、あらゆるコンテンツの受信を処理できるようになります。

以前の Android バージョンとの下位互換性を維持するため、この API は AndroidX(Core 1.7 および Appcompat 1.4 以降)でも使用できます。この機能を実装する場合は、AndroidX を使用することをおすすめします。

概要

他の既存の API では、長押しメニューやドラッグ&ドロップなどの UI メカニズムごとに、それに対応する固有の API があります。これは、コンテンツを挿入するメカニズムごとに類似のコードを追加して、各 API を個別に統合する必要があることを意味します。

図 2. 以前は、コンテンツを挿入するための UI メカニズムごとに、異なる API をアプリに実装する必要がありました。

OnReceiveContentListener API は、このようなさまざまなコードパスを、1 つの API の実装を作成することで統合します。これにより、デベロッパーはアプリ固有のロジックに集中し、それ以外の処理はプラットフォームに委ねることができます。

図 3. この Unified API を使用すると、1 つの API の実装ですべての UI メカニズムをサポートできます。

このアプローチでは、コンテンツを挿入する新しい方法をプラットフォームに追加する際に、アプリでサポートを有効にするためにコードを変更する必要がありません。特定のユースケース用のフル カスタマイズをアプリに実装する必要がある場合も、同様に動作する既存の API を引き続き使用できます。

実装

この API は、ただ一つのメソッド OnReceiveContentListener とのリスナー インターフェースです。古いバージョンの Android プラットフォームをサポートするには、AndroidX Core ライブラリの一致する OnReceiveContentListener インターフェースの使用をおすすめします。

API を使用するには、アプリが処理できるコンテンツのタイプを指定して、リスナーの実装を開始します。

public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...

アプリがサポートするすべてのコンテンツ MIME タイプを指定した後、リスナーの残りの部分を実装します。

 public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};

     @Override
     public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
         Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition(
                 item -> item.getUri() != null);
         ContentInfo uriContent = split.first;
         ContentInfo remaining = split.second;
         if (uriContent != null) {
             // App-specific logic to handle the URI(s) in uriContent...
         }
         // Return anything that your app didn't handle. This preserves the default platform
         // behavior for text and anything else that you aren't implementing custom handling for.
         return remaining;
     }
 }

アプリがすでにインテントとの共有をサポートしている場合は、コンテンツ URI を処理するアプリ固有のロジックを再利用できます。残りすべてのデータを結果から取得し、そのデータの処理をプラットフォームに委ねます。

リスナーを実装したら、アプリの適切な UI 要素でリスナーを設定します。

public class MyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // ...

         AppCompatEditText myInput = findViewById(R.id.my_input);
         ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());
     }
}

URI 権限

読み取り権限は、OnReceiveContentListener に渡されたペイロード内のコンテンツ URI に対して、プラットフォームにより自動的に付与、解放されます。

通常、アプリはサービスまたはアクティビティでコンテンツ URI を処理する必要があります。長時間実行処理の場合は、WorkManager を使用します。これを実装する場合は、Intent.setClipData を使用してコンテンツを渡し、FLAG_GRANT_READ_URI_PERMISSION のフラグを設定することで、ターゲット サービスまたはアクティビティに権限を拡張する必要があります。

また、現在のコンテキスト内でバックグラウンド スレッドを使用してコンテンツを処理することもできます。この場合、リスナーが受け取った payload オブジェクトへの参照を維持して、プラットフォームにより権限が早期に取り消されないようにします。

カスタムビュー

アプリでカスタムの View サブクラスを使用する場合は、OnReceiveContentListener がバイパスされないように注意する必要があります。

View クラスで onCreateInputConnection メソッドをオーバーライドする場合は、Jetpack API の InputConnectionCompat.createWrapper を使用して InputConnection を構成してください。

View クラスで onTextContextMenuItem メソッドをオーバーライドする場合は、メニュー アイテムが R.id.paste または R.id.pasteAsPlainText のときはスーパーに委任してください。

Keyboard Image API との比較

OnReceiveContentListener API は、既存の Keyboard Image API の次期バージョンと考えることができます。この Unified API は、Keyboard Image API の機能に加えて、いくつかの追加機能をサポートします。デバイスと機能の互換性は、Jetpack ライブラリを使用するか、Android SDK のネイティブ API を使用するかによって異なります。

サポートされる機能と API レベル: Jetpack

アクションまたは機能 Keyboard Image API によるサポート Unified API によるサポート
キーボードからの挿入 あり(API レベル 13 以上) あり(API レベル 13 以上)
長押しメニューからの貼り付けによる挿入 なし あり
ドラッグ&ドロップによる挿入 なし あり(API レベル 24 以上)

サポートされる機能と API レベル: ネイティブ API

アクションまたは機能 Keyboard Image API によるサポート Unified API によるサポート
キーボードからの挿入 あり(API レベル 25 以上) あり(Android 12 以降)
長押しメニューからの貼り付けによる挿入 なし
ドラッグ&ドロップによる挿入 なし