ユーザーは、画像や動画などの表現力豊かなコンテンツを好むものですが、アプリにこうしたコンテンツを挿入したり移動したりすることは必ずしも容易ではありません。Android 12(API レベル 31)では、アプリがリッチ コンテンツを簡単に受信できるように、任意のソース(クリップボード、キーボード、ドラッグ)からコンテンツを受け取れるようにする Unified API が導入されています。
OnReceiveContentListener
などのインターフェースを UI コンポーネントにアタッチし、なんらかのメカニズムを通じてコンテンツが挿入されたときにコールバックを取得できます。コードでは、このコールバック 1 か所で、プレーン テキストや書式付きテキストからマークアップ、画像、動画、音声ファイルまで、あらゆるコンテンツの受信を処理できるようになります。
以前の Android バージョンとの下位互換性を維持するため、この API は Core 1.7 と Appcompat 1.4 以降、AndroidX でも利用可能です。この機能を実装する際は、これらを使用することをおすすめします。
概要
他の既存の API では、UI メカニズム(長押しメニューやドラッグなど)ごとに、それぞれ対応する API があります。これは、コンテンツを挿入するメカニズムごとに類似のコードを追加して、各 API を個別に統合する必要があることを意味します。
OnReceiveContentListener
API は実装する API を 1 つにし、このさまざまなコードパスを統合します。これにより、デベロッパーはアプリ固有のロジックに集中し、それ以外の処理はプラットフォームに委ねることができます。
このアプローチは、コンテンツを挿入する新しい方法がプラットフォームに追加されたときに、アプリでサポートを有効にするためにコードを変更する必要がないことも意味します。また、アプリが特定のユースケース向けに完全なカスタマイズを実装する必要がある場合は、既存の API を引き続き使用できます。これらの API は、引き続き同じように機能します。
実装
この API は、単一メソッド OnReceiveContentListener
とのリスナー インターフェースです。古いバージョンの Android プラットフォームをサポートするには、それに対応する AndroidX Core ライブラリの OnReceiveContentListener
インターフェースの使用をおすすめします。
API を使用するには、アプリが処理できるコンテンツのタイプを指定してリスナーを実装します。
Kotlin
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
Java
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
アプリがサポートするすべてのコンテンツ MIME タイプを指定した後、リスナーの残りの部分を実装します。
Kotlin
class MyReceiver : OnReceiveContentListener { override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat { val split = contentInfo.partition { item: ClipData.Item -> item.uri != null } val uriContent = split.first val 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 } companion object { val MIME_TYPES = arrayOf("image/*", "video/*") } }
Java
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; @Override public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) { Pairsplit = 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 要素でリスナーを設定します。
Kotlin
class MyActivity : Activity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... val myInput = findViewById(R.id.my_input) ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver()) } }
Java
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
のときに super にデリゲートします。
Keyboard Image API との比較
OnReceiveContentListener
API は、既存の Keyboard Image API の次期バージョンと考えることができます。この Unified API は、Keyboard Image API の機能に加えて、いくつかの追加機能をサポートします。デバイスと機能の互換性は、Jetpack ライブラリを使用するか、Android SDK のネイティブ API を使用するかによって異なります。
アクションまたは機能 | Keyboard Image API によるサポート | Unified API によるサポート |
---|---|---|
キーボードからの挿入 | あり(API レベル 13 以上) | あり(API レベル 13 以上) |
長押しメニューから貼り付けを使用して挿入します | なし | あり |
ドラッグ&ドロップで挿入する | なし | あり(API レベル 24 以上) |
アクションまたは機能 | Keyboard Image API によるサポート | Unified API によるサポート |
---|---|---|
キーボードからの挿入 | あり(API レベル 25 以上) | あり(Android 12 以降) |
長押しメニューから貼り付けを使用して挿入します | なし | |
ドラッグ&ドロップによる挿入 | なし |