コピーして貼り付け

Android は、コピー&ペースト用の強力なクリップボード ベース フレームワークを備えています。シンプルな テキスト文字列、複雑なデータ構造、テキスト、バイナリ ストリームなどの複雑なデータ型 アプリケーションアセットです。単純なテキストデータはクリップボードに直接保存され、 データが参照として保存され、貼り付け側アプリがコンテンツ プロバイダとの間で解決する。コピーしています と貼り付けは、1 つのアプリ内だけでなく、 説明します。

フレームワークの一部でコンテンツ プロバイダを使用しているため、このドキュメントは、 Android Content Provider API を使用する方法については、 コンテンツ プロバイダ

ユーザーはクリップボードにコンテンツをコピーする際にフィードバックを期待しているため、 コピーと貼り付けの機能。Android 13(API レベル 33)でコピーすると、Android でデフォルトの UI がユーザーに表示されます。 以上です。この機能により、通知が重複するリスクがあります。詳しくは、 このエッジケースは 通知の重複を避ける

Android 13 のクリップボード通知を示すアニメーション
図 1. Android でコンテンツがクリップボードに入るときに表示される UI 13 歳以上。

Android 12L(API レベル 32)以下でコピーする場合は、ユーザーに手動でフィードバックを提供します。詳しくは、 このドキュメントの推奨事項をご覧ください。

クリップボード フレームワーク

クリップボード フレームワークを使用する場合は、データをクリップ オブジェクトに配置してから、クリップ オブジェクトを配置する システム全体のクリップボードにコピーしておけます。クリップ オブジェクトは、次の 3 つの形式のいずれかになります。

テキスト
テキスト文字列。クリップ オブジェクトに文字列を直接配置し、 クリックします。文字列を貼り付けるには、クリップボードからクリップ オブジェクトを取得して、 その文字列をアプリケーションのストレージに書き出します。
URI
イベントを表す Uri オブジェクト。 URI の形式で指定します。これは主に、コンテンツ プロバイダから複雑なデータをコピーする場合に使用します。コピー対象 Uri オブジェクトをクリップ オブジェクトに配置し、そのクリップ オブジェクトを クリックします。データを貼り付けるには、クリップ オブジェクトと Uri オブジェクトを取得します。 それをデータソース(コンテンツ プロバイダなど)に解決し、 アプリのストレージに書き込みます。
インテント
Intent。この では、アプリケーションのショートカットのコピーがサポートされています。データをコピーするには、Intent を作成してから、 作成し、そのクリップ オブジェクトをクリップボードに配置します。データを貼り付けるには、 次に、Intent オブジェクトをアプリケーションの できます。

クリップボードは、一度に 1 つのクリップ オブジェクトしか保持できません。アプリケーションがクリップ オブジェクトを 前のクリップ オブジェクトは消えます。

ユーザーがアプリケーションにデータを貼り付けられるようにしたい場合は、 分析できます貼り付けるオプションをユーザーに提供する前に、クリップボード上のデータを確認できます。 クリップ オブジェクトには、特定のデータ形式のほかに、どの MIME ブロックであるかを示すメタデータも含まれています。 使用できます。このメタデータは、アプリケーションが何か有用なものを実行できるかどうかを判断するのに役立ちます クリップボード データが保持されます。たとえば、主にテキストを処理するアプリケーションでは、 URI またはインテントを含むクリップ オブジェクトを無視できます。

また、クリップボード上にあるデータの形式に関係なく、ユーザーがテキストを貼り付けられるようにすることもできます。宛先 クリップボードのデータを強制的にテキスト表現にして、そのテキストを貼り付けます。これは、 クリップボードをテキストに強制変換するをご覧ください。

クリップボード クラス

このセクションでは、クリップボード フレームワークで使用されるクラスについて説明します。

ClipboardManager

Android システムのクリップボードは、 ClipboardManager クラス。 このクラスを直接インスタンス化しないでください。代わりに、呼び出して参照を取得します。 getSystemService(CLIPBOARD_SERVICE)

ClipData、ClipData.Item、ClipDescription

クリップボードにデータを追加するには、 次を含む ClipData オブジェクト データの説明とデータ自体を表します。クリップボードは、同じ位置に 1 つの ClipData を保持します。 あります。ClipData には、 ClipDescription オブジェクト と 1 つ以上 ClipData.Item オブジェクト。

ClipDescription オブジェクトには、クリップに関するメタデータが含まれます。特に には、クリップのデータで使用可能な MIME タイプの配列が含まれます。また Android 12(API レベル 31)以降では、メタデータに、オブジェクトが 次を含む 定型文オブジェクト内のテキストの種類。 クリップボードにクリップを配置すると、貼り付けアプリでこの情報を利用できます。 クリップデータを処理できるかどうかを検証できます。

ClipData.Item オブジェクトには、テキスト、URI、またはインテント データが含まれます。

テキスト
CharSequence
URI
Uri。これには通常、コンテンツ プロバイダの URI が含まれますが、 できます。データを提供するアプリは、この URI をクリップボードに配置します。アプリケーション クリップボードから URI を取得し、その URI を使用してコンテンツにアクセスする データを取得します。
インテント
Intent。このデータ型を使用すると、アプリケーションのショートカットを クリックします。ユーザーは、後でそのショートカットを別のアプリに貼り付けて使用できます。

1 つのクリップに複数の ClipData.Item オブジェクトを追加できます。これにより、ユーザーは 複数の選択内容を 1 つのクリップとして貼り付けることができます。たとえば、リスト ウィジェットで 一度に複数のアイテムを選択すると、すべてのアイテムを一度にクリップボードにコピーできます。タスク リストアイテムごとに個別の ClipData.Item を作成して、 ClipData.Item オブジェクトを ClipData オブジェクトに追加します。

ClipData コンビニエンス メソッド

ClipData クラスは、静的コンビニエンス メソッドを提供し、 単一の ClipData.Item オブジェクトとシンプルな ClipData オブジェクトを持つ ClipDescription オブジェクト:

newPlainText(label, text)
単一の ClipData.Item オブジェクトを持つ ClipData オブジェクトを返します。 にはテキスト文字列が含まれます。ClipDescription オブジェクトのラベルは次のように設定されます。 labelClipDescription の単一の MIME タイプは次のとおりです。 MIMETYPE_TEXT_PLAIN

newPlainText() を使用して、テキスト文字列からクリップを作成します。

newUri(resolver, label, URI)
単一の ClipData.Item オブジェクトを持つ ClipData オブジェクトを返します。 URI が含まれています。ClipDescription オブジェクトのラベルは次のように設定されます。 label。URI がコンテンツ URI の場合、つまり、 Uri.getScheme() content: を返します。このメソッドは、 ContentResolver resolver で提供されるオブジェクトを使用して、使用可能な MIME タイプを コンテンツ プロバイダを指定します。次に、ClipDescription に保存します。定義されていない URI では、 content: URI の場合、メソッドは MIME タイプを MIMETYPE_TEXT_URILIST

newUri() を使用して、URI(特に content: URI。

newIntent(label, intent)
単一の ClipData.Item オブジェクトを持つ ClipData オブジェクトを返します。 Intent が含まれている。ClipDescription オブジェクトのラベルは次のように設定されます。 label。MIME タイプは MIMETYPE_TEXT_INTENT

newIntent() を使用して Intent オブジェクトからクリップを作成します。

クリップボード データをテキストに強制変換する

テキストを処理するだけのアプリでも、次の方法でクリップボードからテキスト以外のデータをコピーできます。 変換して ClipData.Item.coerceToText() メソッドを呼び出します。

このメソッドは、ClipData.Item のデータをテキストに変換して、 CharSequenceClipData.Item.coerceToText() が返す値は ClipData.Item のデータ形式:

テキスト
ClipData.Item がテキストの場合(つまり、 getText() null でない場合、coerceToText() はテキストを返します。
URI
ClipData.Item が URI の場合、つまり、 getUri() null ではない - coerceToText() はそれをコンテンツ URI として使用しようとします。
  • URI がコンテンツ URI で、プロバイダがテキスト ストリームを返すことができる場合、 coerceToText() はテキスト ストリームを返します。
  • URI がコンテンツ URI で、プロバイダがテキスト ストリームを提供していない場合、 coerceToText() は URI の表現を返します。表現は次のとおりです。 返されるものと同じです。 Uri.toString()
  • URI がコンテンツ URI でない場合、coerceToText() はそのコンテンツの表現を返します。 指定します。この表現は、 Uri.toString()
インテント
ClipData.ItemIntent の場合(つまり、 getIntent() null でない場合 - coerceToText() はこれをインテント URI に変換して返します。 この表現は、 Intent.toUri(URI_INTENT_SCHEME)

クリップボード フレームワークの概要を図 2 に示します。データをコピーする場合、アプリケーションは ClipboardManager グローバル クリップボードの ClipData オブジェクト。「 ClipData には、1 つ以上の ClipData.Item オブジェクトと 1 つのオブジェクトが含まれます。 ClipDescription オブジェクト。データを貼り付ける場合、アプリケーションは ClipData を取得します。 MIME タイプを ClipDescription から取得し、データを ClipData.Item から取得するか、 ClipData.Item

<ph type="x-smartling-placeholder">
</ph> コピー&ペースト フレームワークのブロック図を示す画像 <ph type="x-smartling-placeholder">
</ph> 図 2.Android クリップボード フレームワーク。

クリップボードにコピー

クリップボードにデータをコピーするには、グローバル ClipboardManager オブジェクトに対するハンドルを取得します。 ClipData オブジェクトを作成し、ClipDescription と 1 つ以上の ClipData.Item 個のオブジェクトを追加します。次に、完成した ClipData オブジェクトを ClipboardManager オブジェクト。これについては、次の手順で詳しく説明します。

  1. コンテンツ URI を使用してデータをコピーする場合は、コンテンツ プロバイダを設定します。
  2. システム クリップボードを取得します。

    Kotlin

    when(menuItem.itemId) {
        ...
        R.id.menu_copy -> { // if the user selects copy
            // Gets a handle to the clipboard service.
            val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        }
    }
    

    Java

    ...
    // If the user selects copy.
    case R.id.menu_copy:
    
    // Gets a handle to the clipboard service.
    ClipboardManager clipboard = (ClipboardManager)
            getSystemService(Context.CLIPBOARD_SERVICE);
    
  3. 新しい ClipData オブジェクトにデータをコピーします。

    • テキストの場合

      Kotlin

      // Creates a new text clip to put on the clipboard.
      val clip: ClipData = ClipData.newPlainText("simple text", "Hello, World!")
      

      Java

      // Creates a new text clip to put on the clipboard.
      ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
      
    • URI の場合

      このスニペットは、コンテンツの URI にレコード ID をエンコードすることで URI を構成しています。 必要があります。この手法については、このモジュールの URI で識別子をエンコードするセクション。

      Kotlin

      // Creates a Uri using a base Uri and a record ID based on the contact's last
      // name. Declares the base URI string.
      const val CONTACTS = "content://com.example.contacts"
      
      // Declares a path string for URIs, used to copy data.
      const val COPY_PATH = "/copy"
      
      // Declares the Uri to paste to the clipboard.
      val copyUri: Uri = Uri.parse("$CONTACTS$COPY_PATH/$lastName")
      ...
      // Creates a new URI clip object. The system uses the anonymous
      // getContentResolver() object to get MIME types from provider. The clip object's
      // label is "URI", and its data is the Uri previously created.
      val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
      

      Java

      // Creates a Uri using a base Uri and a record ID based on the contact's last
      // name. Declares the base URI string.
      private static final String CONTACTS = "content://com.example.contacts";
      
      // Declares a path string for URIs, used to copy data.
      private static final String COPY_PATH = "/copy";
      
      // Declares the Uri to paste to the clipboard.
      Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + lastName);
      ...
      // Creates a new URI clip object. The system uses the anonymous
      // getContentResolver() object to get MIME types from provider. The clip object's
      // label is "URI", and its data is the Uri previously created.
      ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
      
    • インテントの場合

      このスニペットは、アプリケーションの Intent を作成し、 次のように指定します。

      Kotlin

      // Creates the Intent.
      val appIntent = Intent(this, com.example.demo.myapplication::class.java)
      ...
      // Creates a clip object with the Intent in it. Its label is "Intent"
      // and its data is the Intent object created previously.
      val clip: ClipData = ClipData.newIntent("Intent", appIntent)
      

      Java

      // Creates the Intent.
      Intent appIntent = new Intent(this, com.example.demo.myapplication.class);
      ...
      // Creates a clip object with the Intent in it. Its label is "Intent"
      // and its data is the Intent object created previously.
      ClipData clip = ClipData.newIntent("Intent", appIntent);
      
  4. 新しいクリップ オブジェクトをクリップボード上に配置します。

    Kotlin

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip)
    

    Java

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip);
    

クリップボードにコピーする際のフィードバックの提供

ユーザーは、アプリがコンテンツをクリップボードにコピーするときに、視覚的なフィードバックを期待します。完了 Android 13 以降では自動的に実装されますが、事前に手動で実装する必要があります。 あります。

Android 13 以降では、コンテンツが追加されると、標準的な確認メッセージが表示されます。 クリップボードにコピーします。この新しい通知機能により、次のことが可能になります。

  • コンテンツが正常にコピーされたことをユーザーに知らせる。
  • コピーされたコンテンツのプレビューを表示する。

Android 13 のクリップボード通知を示すアニメーション
図 3. Android でコンテンツがクリップボードに入るときに表示される UI 13 歳以上。

Android 12L(API レベル 32)以前では、正常にコピーされたかどうかが不明な場合がある またはコピーした内容などです。この機能は、変更後にアプリに表示されるさまざまな通知を標準化します。 ユーザーがクリップボードをコントロールできます。

通知の重複を避ける

Android 12L(API レベル 32)以前では、コピーが正常に完了したらユーザーに通知することをおすすめします。 視覚的でアプリ内フィードバックを送る、Toast のようなウィジェットを使用する、 コピー後、Snackbar

情報の重複表示を避けるために、トーストを削除することを強くおすすめします Android 13 以降のアプリ内コピーの後に表示されるスナックバーです。

アプリ内コピーの後にスナックバーを表示する
図 4. Android 13 でコピー確認のスナックバーを表示する場合、 メッセージが重複して表示されます。
で確認できます。
<ph type="x-smartling-placeholder">
</ph> アプリ内コピーの後にトーストを表示する <ph type="x-smartling-placeholder">
</ph> 図 5.Android 13 でコピー確認トーストを表示する場合、 メッセージが重複して表示されます。

実装方法の例を次に示します。

fun textCopyThenPost(textCopied:String) {
    val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
    // When setting the clipboard text.
    clipboardManager.setPrimaryClip(ClipData.newPlainText   ("", textCopied))
    // Only show a toast for Android 12 and lower.
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2)
        Toast.makeText(context, “Copied”, Toast.LENGTH_SHORT).show()
}

機密コンテンツをクリップボードに追加する

アプリで、ユーザーがパスワードやクレジットなどの機密性の高いコンテンツをクリップボードにコピーできるようにしている場合 ClipDataClipDescription にフラグを追加する必要があります。 までメールでご連絡ください。ClipboardManager.setPrimaryClip()このフラグを追加すると、機密データが Android 13 以降では、コピーされたコンテンツを視覚的に確認する際にコンテンツが表示されなくなります。

機密コンテンツのフラグを設定せずにコピーされたテキストのプレビュー
図 6. 機密コンテンツのフラグなしでコピーされたテキストのプレビュー。
で確認できます。
<ph type="x-smartling-placeholder">
</ph> 機密コンテンツのフラグを設定してコピーされたテキストのプレビュー <ph type="x-smartling-placeholder">
</ph> 図 7.機密コンテンツのフラグを設定してコピーされたテキストのプレビュー。

機密コンテンツのフラグを設定するには、ClipDescription にブール型のエクストラを追加します。すべてのアプリで必須 常に同じです。

// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
    }
}

// If your app is compiled with a lower SDK.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean("android.content.extra.IS_SENSITIVE", true)
    }
}

クリップボードから貼り付け

前述のように、グローバル クリップボード オブジェクトを取得して、クリップボードからデータを貼り付けます。 クリップ オブジェクトの取得、そのデータの確認、可能であればクリップ オブジェクトからのデータのコピー 独自のストレージに保存できますこのセクションでは、3 種類のクリップボードを貼り付ける方法を詳しく説明します。 分析できます

<ph type="x-smartling-placeholder">

書式なしテキストを貼り付ける

書式なしテキストを貼り付けるには、グローバル クリップボードを取得して、書式なしテキストを返すことができることを確認します。次に、 クリップ オブジェクトを作成し、getText() を使用してそのテキストを独自のストレージにコピーします。詳しくは、 次の操作を行います。

  1. 次のコマンドを使用して、グローバル ClipboardManager オブジェクトを取得します。 getSystemService(CLIPBOARD_SERVICE)。また、この変数名を格納するグローバル変数を宣言し、 貼り付けたテキスト:

    Kotlin

    var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    var pasteData: String = ""
    

    Java

    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    String pasteData = "";
    
  2. 「貼り付け」を有効または無効にする必要があるかどうかを判断するオプションを できます。クリップボードにクリップが含まれていることと、その種類のデータを処理できることを確認する 表現します。

    Kotlin

    // Gets the ID of the "paste" menu item.
    val pasteItem: MenuItem = menu.findItem(R.id.menu_paste)
    
    // If the clipboard doesn't contain data, disable the paste menu item.
    // If it does contain data, decide whether you can handle the data.
    pasteItem.isEnabled = when {
        !clipboard.hasPrimaryClip() -> {
            false
        }
        !(clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) -> {
            // Disables the paste menu item, since the clipboard has data but it
            // isn't plain text.
            false
        }
        else -> {
            // Enables the paste menu item, since the clipboard contains plain text.
            true
        }
    }
    

    Java

    // Gets the ID of the "paste" menu item.
    MenuItem pasteItem = menu.findItem(R.id.menu_paste);
    
    // If the clipboard doesn't contain data, disable the paste menu item.
    // If it does contain data, decide whether you can handle the data.
    if (!(clipboard.hasPrimaryClip())) {
    
        pasteItem.setEnabled(false);
    
    } else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) {
    
        // Disables the paste menu item, since the clipboard has data but
        // it isn't plain text.
        pasteItem.setEnabled(false);
    } else {
    
        // Enables the paste menu item, since the clipboard contains plain text.
        pasteItem.setEnabled(true);
    }
    
  3. クリップボードからデータをコピーします。コード内のこのポイントにアクセスできるのは、 "貼り付ける"有効な状態になっているため、クリップボードにプレーン テキストが あります。書式なしテキストを指すテキスト文字列や URI かどうかはまだわかりません。 次のコード スニペットでこれをテストしますが、プレーン テキストを処理するコードのみを示します。

    Kotlin

    when (menuItem.itemId) {
        ...
        R.id.menu_paste -> {    // Responds to the user selecting "paste".
            // Examines the item on the clipboard. If getText() doesn't return null,
            // the clip item contains the text. Assumes that this application can only
            // handle one item at a time.
            val item = clipboard.primaryClip.getItemAt(0)
    
            // Gets the clipboard as text.
            pasteData = item.text
    
            return if (pasteData != null) {
                // If the string contains data, then the paste operation is done.
                true
            } else {
                // The clipboard doesn't contain text. If it contains a URI,
                // attempts to get data from it.
                val pasteUri: Uri? = item.uri
    
                if (pasteUri != null) {
                    // If the URI contains something, try to get text from it.
    
                    // Calls a routine to resolve the URI and get data from it.
                    // This routine isn't presented here.
                    pasteData = resolveUri(pasteUri)
                    true
                } else {
    
                    // Something is wrong. The MIME type was plain text, but the
                    // clipboard doesn't contain text or a Uri. Report an error.
                    Log.e(TAG,"Clipboard contains an invalid data type")
                    false
                }
            }
        }
    }
    

    Java

    // Responds to the user selecting "paste".
    case R.id.menu_paste:
    
    // Examines the item on the clipboard. If getText() does not return null,
    // the clip item contains the text. Assumes that this application can only
    // handle one item at a time.
     ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
    
    // Gets the clipboard as text.
    pasteData = item.getText();
    
    // If the string contains data, then the paste operation is done.
    if (pasteData != null) {
        return true;
    
    // The clipboard doesn't contain text. If it contains a URI, attempts to get
    // data from it.
    } else {
        Uri pasteUri = item.getUri();
    
        // If the URI contains something, try to get text from it.
        if (pasteUri != null) {
    
            // Calls a routine to resolve the URI and get data from it.
            // This routine isn't presented here.
            pasteData = resolveUri(Uri);
            return true;
        } else {
    
            // Something is wrong. The MIME type is plain text, but the
            // clipboard doesn't contain text or a Uri. Report an error.
            Log.e(TAG, "Clipboard contains an invalid data type");
            return false;
        }
    }
    

コンテンツ URI からデータを貼り付ける

ClipData.Item オブジェクトにコンテンツ URI が含まれていて、 MIME タイプの 1 つを処理し、ContentResolver を作成して適切なコンテンツを呼び出します。 データを取得します。

コンテンツ URI に基づいてコンテンツ プロバイダからデータを取得する手順は次のとおりです。 確認できます。アプリケーションが使用できる MIME タイプが 接続します。

  1. MIME タイプを格納するグローバル変数を宣言します。

    Kotlin

    // Declares a MIME type constant to match against the MIME types offered
    // by the provider.
    const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
    

    Java

    // Declares a MIME type constant to match against the MIME types offered by
    // the provider.
    public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
    
  2. グローバル クリップボードを取得します。また、コンテンツ リゾルバも取得します。これにより、コンテンツ プロバイダにアクセスできるようになります。

    Kotlin

    // Gets a handle to the Clipboard Manager.
    val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    
    // Gets a content resolver instance.
    val cr = contentResolver
    

    Java

    // Gets a handle to the Clipboard Manager.
    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    
    // Gets a content resolver instance.
    ContentResolver cr = getContentResolver();
    
  3. クリップボードからプライマリ クリップを取得し、その内容を URI として取得します。

    Kotlin

    // Gets the clipboard data from the clipboard.
    val clip: ClipData? = clipboard.primaryClip
    
    clip?.run {
    
        // Gets the first item from the clipboard data.
        val item: ClipData.Item = getItemAt(0)
    
        // Tries to get the item's contents as a URI.
        val pasteUri: Uri? = item.uri
    

    Java

    // Gets the clipboard data from the clipboard.
    ClipData clip = clipboard.getPrimaryClip();
    
    if (clip != null) {
    
        // Gets the first item from the clipboard data.
        ClipData.Item item = clip.getItemAt(0);
    
        // Tries to get the item's contents as a URI.
        Uri pasteUri = item.getUri();
    
  4. 次を呼び出して、URI がコンテンツ URI であるかどうかをテストします。 getType(Uri)Uri が有効なコンテンツ プロバイダをポイントしていない場合、このメソッドは null を返します。

    Kotlin

        // If the clipboard contains a URI reference...
        pasteUri?.let {
    
            // ...is this a content URI?
            val uriMimeType: String? = cr.getType(it)
    

    Java

        // If the clipboard contains a URI reference...
        if (pasteUri != null) {
    
            // ...is this a content URI?
            String uriMimeType = cr.getType(pasteUri);
    
  5. コンテンツ プロバイダが、アプリが認識する MIME タイプをサポートしているかどうかをテストします。条件 呼び出す場合は、 ContentResolver.query() 必要があります。戻り値は Cursor

    Kotlin

            // If the return value isn't null, the Uri is a content Uri.
            uriMimeType?.takeIf {
    
                // Does the content provider offer a MIME type that the current
                // application can use?
                it == MIME_TYPE_CONTACT
            }?.apply {
    
                // Get the data from the content provider.
                cr.query(pasteUri, null, null, null, null)?.use { pasteCursor ->
    
                    // If the Cursor contains data, move to the first record.
                    if (pasteCursor.moveToFirst()) {
    
                        // Get the data from the Cursor here.
                        // The code varies according to the format of the data model.
                    }
    
                    // Kotlin `use` automatically closes the Cursor.
                }
            }
        }
    }
    

    Java

            // If the return value isn't null, the Uri is a content Uri.
            if (uriMimeType != null) {
    
                // Does the content provider offer a MIME type that the current
                // application can use?
                if (uriMimeType.equals(MIME_TYPE_CONTACT)) {
    
                    // Get the data from the content provider.
                    Cursor pasteCursor = cr.query(uri, null, null, null, null);
    
                    // If the Cursor contains data, move to the first record.
                    if (pasteCursor != null) {
                        if (pasteCursor.moveToFirst()) {
    
                        // Get the data from the Cursor here.
                        // The code varies according to the format of the data model.
                        }
                    }
    
                    // Close the Cursor.
                    pasteCursor.close();
                 }
             }
         }
    }
    

インテントを貼り付ける

インテントを貼り付けるには、まずグローバル クリップボードを取得します。ClipData.Item オブジェクトを調べる Intent が含まれているかどうかを確認します。次に、getIntent() を呼び出して、 独自のストレージに保存できます。この手順を行うスニペットは以下のとおりです。

Kotlin

// Gets a handle to the Clipboard Manager.
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

// Checks whether the clip item contains an Intent by testing whether
// getIntent() returns null.
val pasteIntent: Intent? = clipboard.primaryClip?.getItemAt(0)?.intent

if (pasteIntent != null) {

    // Handle the Intent.

} else {

    // Ignore the clipboard, or issue an error if
    // you expect an Intent to be on the clipboard.
}

Java

// Gets a handle to the Clipboard Manager.
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

// Checks whether the clip item contains an Intent, by testing whether
// getIntent() returns null.
Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent();

if (pasteIntent != null) {

    // Handle the Intent.

} else {

    // Ignore the clipboard, or issue an error if
    // you expect an Intent to be on the clipboard.
}

アプリがクリップボード データにアクセスしたときに表示されるシステム通知

Android 12(API レベル 31)以降では、通常、アプリが 通話 getPrimaryClip()。 メッセージ内のテキストは次の形式になっています。

APP pasted from your clipboard

アプリが次のいずれかを行った場合、トースト メッセージは表示されません。

  • アクセス 自分のアプリの ClipData
  • 特定のアプリから ClipData に繰り返しアクセスする。トーストは そのアプリのデータに初めてアクセスしたとき。
  • 次の呼び出しによって、クリップ オブジェクトのメタデータを取得します。 getPrimaryClipDescription()getPrimaryClip() は使用しません)。

コンテンツ プロバイダを使用して複雑なデータをコピーする

コンテンツ プロバイダは、データベース レコードやファイル ストリームなどの複雑なデータのコピーをサポートします。コピー対象 コンテンツ URI をクリップボードに配置します。貼り付けるアプリケーションは、この URI を データベース データやファイル ストリーム記述子を取得するために使用できます。

貼り付け側アプリにはデータのコンテンツ URI しかないため、 指定します。この情報を指定するには、データの識別子をエンコードします。 または、コピーするデータを返す一意の URI を指定できます。対象 選択する手法は、データの構成によって異なります。

以降のセクションでは、URI の設定方法、複雑なデータの提供方法、ファイルの提供方法について説明します。 使用できます。以下の説明は、読者がコンテンツ プロバイダの一般原則をよく理解していることを前提としています。 考えています

URI で識別子をエンコードする

URI を使用してクリップボードにデータをコピーするには、URL の識別子をエンコードすると便利です。 URI 自体のデータです。コンテンツ プロバイダは URI から識別子を取得して、 データを取得します。貼り付け側アプリは、この ID の存在を認識する必要はありません。これは、 「参照」、つまり URI と ID を コンテンツ プロバイダに渡してデータを取得する必要があります。

識別子は通常、URI の末尾に連結してコンテンツ URI にエンコードします。 たとえば、プロバイダ URI を次の文字列として定義したとします。

"content://com.example.contacts"

この URI に対して名前をエンコードする場合は、次のコード スニペットを使用します。

Kotlin

val uriString = "content://com.example.contacts/Smith"

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
val copyUri = Uri.parse(uriString)

Java

String uriString = "content://com.example.contacts" + "/" + "Smith";

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
Uri copyUri = Uri.parse(uriString);

すでにコンテンツ プロバイダを使用している場合は、新しい URI パスを追加して、 URI はコピー用ですたとえば、次のような URI パスがあるとします。

"content://com.example.contacts/people"
"content://com.example.contacts/people/detail"
"content://com.example.contacts/people/images"

URI をコピーするための別のパスを追加できます。

"content://com.example.contacts/copying"

続けて「コピー」を検出し、パターン マッチングによって URI を取得し、 コピー&ペースト専用のオプションです

すでにコンテンツ プロバイダや内部 IP アドレスを使用する場合は、通常、このエンコード手法を使用します。 内部テーブルを使用してデータを整理できますそのような場合は 各部分の一意の ID が必要です。お客様から その ID でデータを検索して返すことができます。

複数のデータがない場合、識別子をエンコードする必要はありません。 プロバイダに固有の URI を使用できます。クエリに対して、プロバイダは 表示されます。

データ構造をコピーする

複雑なデータをコピーして貼り付けるコンテンツ プロバイダを ContentProvider 説明します。クリップボードに配置した URI をエンコードして、必要なレコードを正確にポイントするようにします。 提供します。さらに、アプリケーションの既存の状態についても考慮してください。

  • すでにコンテンツ プロバイダを使用している場合は、その機能に追加できます。皆さんは その query() メソッドを変更して、 貼り付けることもできます。場合によっては、メソッドを変更して「コピー」URI パターンです。
  • アプリケーションで内部データベースを保守している場合は、そのデータベースを コンテンツ プロバイダにコピーして、そこから簡単にコピーできるようにします。
  • データベースを使用しない場合は、次のようなシンプルなコンテンツ プロバイダを実装できます。 クリップボードから貼り付けるアプリケーションにデータを提供することのみを目的としている。

コンテンツ プロバイダで、少なくとも次のメソッドをオーバーライドします。

query()
貼り付けるアプリケーションは、このメソッドを使用して、指定した URI を使用してデータを取得できることを前提としています。 指定します。コピーをサポートするには、このメソッドを使用して、特別な属性を含む URI を検出し、 「コピー」あります。アプリケーションはその後、出力する URI を クリップボードにコピーした内容を含めます。
getType()
このメソッドは、コピーするデータの MIME タイプを返す必要があります。メソッド newUri() getType() を呼び出して MIME タイプを新しい ClipData に入れます。 渡されます。

複雑なデータの MIME タイプは、 コンテンツ プロバイダ

次のようなコンテンツ プロバイダ メソッドを使用する必要はありません。 insert() または update()。 貼り付け側アプリは、サポートされている MIME タイプを取得し、プロバイダからデータをコピーするだけで済みます。 これらのメソッドがすでにある場合は、コピー オペレーションの妨げになることはありません。

次のスニペットは、複雑なデータをコピーするようにアプリを設定する方法を示しています。

  1. アプリのグローバル定数で、ベース URI 文字列と は、データのコピーに使用する URI 文字列を識別します。コピー先の MIME タイプも宣言し、 分析できます

    Kotlin

    // Declares the base URI string.
    private const val CONTACTS = "content://com.example.contacts"
    
    // Declares a path string for URIs that you use to copy data.
    private const val COPY_PATH = "/copy"
    
    // Declares a MIME type for the copied data.
    const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
    

    Java

    // Declares the base URI string.
    private static final String CONTACTS = "content://com.example.contacts";
    
    // Declares a path string for URIs that you use to copy data.
    private static final String COPY_PATH = "/copy";
    
    // Declares a MIME type for the copied data.
    public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
    
  2. ユーザーがデータをコピーするアクティビティで、クリップボードにデータをコピーするコードを設定します。 コピー リクエストに応じて、URI をクリップボードに配置します。

    Kotlin

    class MyCopyActivity : Activity() {
        ...
    when(item.itemId) {
        R.id.menu_copy -> { // The user has selected a name and is requesting a copy.
            // Appends the last name to the base URI.
            // The name is stored in "lastName".
            uriString = "$CONTACTS$COPY_PATH/$lastName"
    
            // Parses the string into a URI.
            val copyUri: Uri? = Uri.parse(uriString)
    
            // Gets a handle to the clipboard service.
            val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    
            val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
    
            // Sets the clipboard's primary clip.
            clipboard.setPrimaryClip(clip)
        }
    }
    

    Java

    public class MyCopyActivity extends Activity {
        ...
    // The user has selected a name and is requesting a copy.
    case R.id.menu_copy:
    
        // Appends the last name to the base URI.
        // The name is stored in "lastName".
        uriString = CONTACTS + COPY_PATH + "/" + lastName;
    
        // Parses the string into a URI.
        Uri copyUri = Uri.parse(uriString);
    
        // Gets a handle to the clipboard service.
        ClipboardManager clipboard = (ClipboardManager)
            getSystemService(Context.CLIPBOARD_SERVICE);
    
        ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
    
        // Sets the clipboard's primary clip.
        clipboard.setPrimaryClip(clip);
    
  3. コンテンツ プロバイダのグローバル スコープで、URI マッチャーを作成し、 クリップボード上に配置した URI に一致します。

    Kotlin

    // A Uri Match object that simplifies matching content URIs to patterns.
    private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
    
        // Adds a matcher for the content URI. It matches.
        // "content://com.example.contacts/copy/*"
        addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT)
    }
    
    // An integer to use in switching based on the incoming URI pattern.
    private const val GET_SINGLE_CONTACT = 0
    ...
    class MyCopyProvider : ContentProvider() {
        ...
    }
    

    Java

    public class MyCopyProvider extends ContentProvider {
        ...
    // A Uri Match object that simplifies matching content URIs to patterns.
    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    
    // An integer to use in switching based on the incoming URI pattern.
    private static final int GET_SINGLE_CONTACT = 0;
    ...
    // Adds a matcher for the content URI. It matches
    // "content://com.example.contacts/copy/*"
    sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
    
  4. セットアップする query() メソッドを呼び出します。このメソッドは、コーディング方法に応じてさまざまな URI パターンを処理できますが、 クリップボードのコピー操作のパターンが表示されます。

    Kotlin

    // Sets up your provider's query() method.
    override fun query(
            uri: Uri,
            projection: Array<out String>?,
            selection: String?,
            selectionArgs: Array<out String>?,
            sortOrder: String?
    ): Cursor? {
        ...
        // When based on the incoming content URI:
        when(sUriMatcher.match(uri)) {
    
            GET_SINGLE_CONTACT -> {
    
                // Queries and returns the contact for the requested name. Decodes
                // the incoming URI, queries the data model based on the last name,
                // and returns the result as a Cursor.
            }
        }
        ...
    }
    

    Java

    // Sets up your provider's query() method.
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
        String sortOrder) {
        ...
        // Switch based on the incoming content URI.
        switch (sUriMatcher.match(uri)) {
    
        case GET_SINGLE_CONTACT:
    
            // Queries and returns the contact for the requested name. Decodes the
            // incoming URI, queries the data model based on the last name, and
            // returns the result as a Cursor.
        ...
    }
    
  5. コピーしたファイルに対して適切な MIME タイプを返すように getType() メソッドを設定します。 data:

    Kotlin

    // Sets up your provider's getType() method.
    override fun getType(uri: Uri): String? {
        ...
        return when(sUriMatcher.match(uri)) {
            GET_SINGLE_CONTACT -> MIME_TYPE_CONTACT
            ...
        }
    }
    

    Java

    // Sets up your provider's getType() method.
    public String getType(Uri uri) {
        ...
        switch (sUriMatcher.match(uri)) {
        case GET_SINGLE_CONTACT:
            return (MIME_TYPE_CONTACT);
        ...
        }
    }
    

コンテンツ URI からデータを貼り付けるセクションでは、コンテンツ URI を取得する方法を コンテンツ URI を取得し、データの取得と貼り付けに使用します。

データ ストリームをコピーする

大量のテキストデータやバイナリデータをストリームとしてコピー&ペーストすることができます。データにはフォームを含めることができる 次に例を示します。

  • 実際のデバイスに保存されているファイル
  • ソケットからのストリーム
  • プロバイダの基盤となるデータベース システムに大量のデータが保存されている

データ ストリームのコンテンツ プロバイダは、ファイル記述子オブジェクトを使用してデータへのアクセスを提供します。 AssetFileDescriptor, Cursor オブジェクトを使用します。貼り付け側アプリケーションは、これを使用してデータ ストリームを読み取ります。 使用します。

プロバイダを使用してデータ ストリームをコピーするようにアプリケーションを設定するには、以下の手順を行います。

  1. クリップボード上に配置するデータ ストリームのコンテンツ URI をセットアップします。次のような方法があります。
    • データ ストリームの識別子を URI にエンコードする( URI に基づいて識別子をエンコードし、 テーブルに識別子と対応するストリーム名を格納します。
    • URI でストリーム名を直接エンコードします。
    • プロバイダから現在のストリームを常に返す一意の URI を使用します。もし このオプションを使用する場合は、別のストリームを参照するようにプロバイダを更新してください。 URI を使用してストリームをクリップボードにコピーすると、
  2. 提供する予定のデータ ストリームのタイプごとに MIME タイプを指定します。アプリケーションを貼り付けています クリップボードにデータを貼り付けられるかどうかを判断するには、この情報が必要です。
  3. ファイル記述子を返す ContentProvider メソッドのいずれかを実装します。 クリックします。コンテンツ URI で識別子をエンコードする場合は、このメソッドを使用して、 クリックします。
  4. データ ストリームをクリップボードにコピーするには、コンテンツ URI を作成して クリックします。

データ ストリームを貼り付ける場合、アプリはクリップボードからクリップを取得し、URI を取得して、 ストリームを開く ContentResolver ファイル記述子メソッドを呼び出すだけです。「 ContentResolver メソッドは、対応する ContentProvider メソッドを呼び出します。 コンテンツ URI を渡します。そのファイル記述子はプロバイダから ContentResolver メソッドを使用します。その後、貼り付け側アプリが 取得します。

コンテンツ プロバイダにとって最も重要なファイル記述子メソッドを次のリストに示します。各 これに対応する ContentResolver メソッドがあり、 "記述子"メソッド名に追加されます。たとえば、ContentResolver の類似 openAssetFile() openAssetFileDescriptor()

openTypedAssetFile()

このメソッドはアセット ファイル記述子を返します。ただし、指定された MIME タイプが ルートを動的に交換できます。呼び出し元(貼り付けを行うアプリケーション)は、 MIME タイプパターンを指定しますURI をストレージにコピーするアプリのコンテンツ プロバイダ AssetFileDescriptor ファイル ハンドルを提供できる場合、クリップボードはファイル ハンドルを返します。 できない場合は例外をスローします。

このメソッドは、ファイルのサブセクションを処理します。これを使用して、 コンテンツ プロバイダがクリップボードにコピーしました。

openAssetFile()
このメソッドは、openTypedAssetFile() のより一般的な形式です。フィルタリングされない 使用できる MIME タイプをサポートしていますが、ファイルのサブセクションを読み取ることはできます。
openFile()
これは openAssetFile() のより一般的な形式です。次のサブセクションを読み取ることはできません。 できます。

必要に応じて openPipeHelper() メソッドをファイル記述子メソッドと併用します。これにより、貼り付け側アプリケーションがストリーム データを 呼び出します。このメソッドを使用するには、 ContentProvider.PipeDataWriter 行うことができます。

効果的なコピー&ペースト機能を設計する

アプリケーションの効果的なコピー&ペースト機能を設計するには、次の点に注意してください。

  • クリップボード上には常に 1 つのクリップしか存在できません。任意のファイルによる新しいコピー オペレーションを で上書きされる前のクリップが上書きされます。ユーザーはおそらく クリップボードからコピーして、アプリから ユーザーが以前に自分のアプリケーションでコピーしたクリップが含まれている。
  • クリップごとに複数の ClipData.Item オブジェクトを使用することの本来の目的は次のとおりです。 さまざまな形式ではなく、複数の選択範囲をコピーして貼り付けることができるようになりました。 1 つの選択項目を参照することもできます。通常は ClipData.Item がすべて必要です 同じ形式にすることができます。つまり、すべての要素が単純なテキスト、コンテンツ、 URI、または Intent のいずれか。混在はしないでください。
  • データを提供するときに、さまざまな MIME 表現を指定できます。MIME タイプを追加する ClipDescription に追加してから、MIME タイプを 提供します。
  • クリップボードからデータを取得した後、アプリは、利用可能な MIME タイプをチェックし、使用できる MIME タイプがあった場合はどの MIME タイプを使用するのかを決定します。たとえ ユーザーが貼り付けをリクエストした場合、アプリは必要ありません。 貼り付けます。MIME タイプに互換性がある場合は、貼り付けを行います。データを強制変換したり、 coerceToText() を使用して、クリップボード内のテキストにテキストを追加します。アプリケーションが 使用可能な MIME タイプが複数ある場合は、使用する MIME タイプをユーザーが選択できるようにします。