Wysyłanie danych do innych aplikacji

Android udostępnia użytkownikom 2 sposoby udostępniania danych między aplikacjami:

  • Arkusz udostępniania w Androidzie jest przeznaczony głównie do wysyłania treści poza aplikację lub bezpośrednio do innego użytkownika. Na przykład do udostępniania adresu URL znajomemu.
  • Rozpoznawanie intencji Androida najlepiej sprawdza się w przypadku przekazywania danych do następnego etapu dobrze zdefiniowanego zadania. Na przykład do otwierania pliku PDF z aplikacji i umożliwiania użytkownikom wybrania preferowanej przeglądarki.

Dlaczego warto korzystać z arkusza udostępniania w Androidzie

Rysunek 1. Arkusz udostępniania w Androidzie.

Używaj arkusza udostępniania w Androidzie, aby zapewnić użytkownikom spójność w różnych aplikacjach. Nie wyświetlaj własnej listy miejsc docelowych udostępniania ani nie twórz własnych wariantów arkusza udostępniania.

Arkusz udostępniania w Androidzie umożliwia użytkownikom udostępnianie informacji odpowiedniej osobie za pomocą sugestii aplikacji – wszystko to jednym kliknięciem. Arkusz udostępniania może sugerować miejsca docelowe niedostępne dla rozwiązań niestandardowych i używa spójnego rankingu. Dzieje się tak, ponieważ arkusz udostępniania może uwzględniać informacje o aktywności aplikacji i użytkownika, które są dostępne tylko dla systemu.

Arkusz udostępniania w Androidzie ma też wiele przydatnych funkcji dla deweloperów. Możesz na przykład:

Korzystanie z arkusza udostępniania w Androidzie

W przypadku wszystkich typów udostępniania utwórz intencję i ustaw jej działanie na Intent.ACTION_SEND. Aby wyświetlić arkusz udostępniania w Androidzie, wywołaj Intent.createChooser(), przekazując mu obiekt Intent. Zwraca wersję Twojej intencji, która zawsze wyświetla arkusz udostępniania w Androidzie.

Wysyłanie treści tekstowych

Najprostszym i najczęstszym sposobem użycia arkusza udostępniania w Androidzie jest wysyłanie treści tekstowych z jednej aktywności do drugiej. Na przykład większość przeglądarek może udostępniać adres URL aktualnie wyświetlanej strony jako tekst innej aplikacji. Jest to przydatne do udostępniania artykułu lub witryny znajomym przez e-mail lub w mediach społecznościowych. W Jetpack Compose pobierz bieżący kontekst za pomocą LocalContext.current i wywołaj context.startActivity(). Oto przykład, jak to zrobić:

fun shareText(context: Context) {
    val sendIntent: Intent = Intent().apply {
        action = ACTION_SEND
        putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
        type = "text/plain"
    }

    val shareIntent = Intent.createChooser(sendIntent, null)
    context.startActivity(shareIntent)
}

Opcjonalnie możesz dodać dodatkowe informacje, takie jak adresaci e-maili (EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC) lub temat e-maila (EXTRA_SUBJECT).

Uwaga: niektóre aplikacje do poczty e-mail, np. Gmail, oczekują, że dodatkowe informacje, takie jak EXTRA_EMAIL i EXTRA_CC, będą miały postać String[]. Aby dodać je do intencji, użyj putExtra(String, String[]).

Wysyłanie treści binarnych

Udostępniaj dane binarne za pomocą działania ACTION_SEND. Ustaw odpowiedni typ MIME i umieść identyfikator URI danych w dodatkowym polu EXTRA_STREAM, jak pokazano w tym przykładzie. Jest to powszechnie używane do udostępniania obrazu, ale można go używać do udostępniania dowolnego typu treści binarnych.

fun shareBinaryContent(context: Context) {
    val shareIntent: Intent = Intent().apply {
        action = ACTION_SEND
        // Example: content://com.google.android.apps.photos.contentprovider/...
        val imageUri: Uri =
            Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1")
        putExtra(Intent.EXTRA_STREAM, imageUri)
        type = "image/jpeg"
    }
    context.startActivity(Intent.createChooser(shareIntent, null))
}

Aplikacja odbierająca musi mieć uprawnienia dostępu do danych, na które wskazuje Uri. Zalecamy 2 sposoby na to:

  • Przechowuj dane we własnym ContentProvider, upewniając się, że inne aplikacje mają odpowiednie uprawnienia dostępu do Twojego dostawcy. Preferowanym mechanizmem zapewniania dostępu jest używanie uprawnień do identyfikatora URI, które są tymczasowe i przyznają dostęp tylko aplikacji odbierającej. Aby utworzyć taki ContentProvider, użyj klasy pomocniczej FileProvider.
  • Użyj systemowego MediaStore. MediaStore jest przeznaczony głównie do typów MIME wideo, audio i obrazów. Jednak począwszy od Androida 3.0 (poziom API 11) może też przechowywać typy inne niż multimedia. Więcej informacji znajdziesz w artykule MediaStore.Files. Pliki można wstawiać do MediaStore za pomocą scanFile(), po czym do podanego wywołania zwrotnego onScanCompleted() przekazywany jest identyfikator Uri w stylu content://, który można udostępniać. Pamiętaj, że po dodaniu do systemowego MediaStore treści są dostępne dla każdej aplikacji na urządzeniu.

Używanie odpowiedniego typu MIME

Podaj najbardziej szczegółowy typ MIME dostępny dla wysyłanych danych. Na przykład podczas udostępniania zwykłego tekstu użyj text/plain. Oto kilka typowych typów MIME podczas wysyłania danych w Androidzie:

Odbiorcy rejestrują się w Nadawcy wysyłają
text/*
  • text/plain
  • text/rtf
  • text/html
  • text/json
image/*
  • image/jpg
  • image/png
  • image/gif
video/*
  • video/mp4
  • video/3gp
Obsługiwane rozszerzenia plików application/pdf

Aby określić typ MIME dynamicznie w czasie działania zamiast kodować go na stałe, użyj tych metod:

Jeśli nie możesz określić konkretnego typu MIME, użyj application/octet-stream w przypadku ogólnych danych binarnych lub */* w ostateczności.

Więcej informacji o typach MIME znajdziesz w oficjalnym rejestrze typów MIME IANA.

W zależności od podanego typu MIME arkusz udostępniania w Androidzie może wyświetlać podgląd treści. Niektóre funkcje w wersji testowej są dostępne tylko w przypadku określonych typów.

Udostępnianie wielu treści

Aby udostępnić wiele treści, użyj działania ACTION_SEND_MULTIPLE wraz z listą identyfikatorów URI wskazujących na treści. Typ MIME różni się w zależności od kombinacji udostępnianych treści. Jeśli na przykład udostępniasz 3 obrazy JPEG, użyj typu "image/jpg". W przypadku mieszanki typów obrazów użyj "image/*", aby dopasować aktywność, która obsługuje dowolny typ obrazu. Chociaż można udostępniać mieszankę typów, unikaj tego, ponieważ odbiorca nie wie, co ma zostać wysłane. Jeśli musisz wysłać wiele typów, użyj "*/*". To aplikacja odbierająca musi przeanalizować i przetworzyć Twoje dane. Oto przykład:

fun shareMultiple(context: Context) {
    val imageUris: ArrayList<Uri> = arrayListOf(
        Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/1"),
        Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/2")
    )

    val shareIntent = Intent().apply {
        action = Intent.ACTION_SEND_MULTIPLE
        putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris)
        type = "image/*"
    }
    context.startActivity(Intent.createChooser(shareIntent, null))
}

Upewnij się, że podane obiekty Uri wskazują dane, do których aplikacja odbierająca ma dostęp.

Dodawanie szczegółowych treści do podglądów tekstu

Począwszy od Androida 10 (poziom API 29) arkusz udostępniania w Androidzie wyświetla podgląd udostępnianego tekstu. W niektórych przypadkach udostępniany tekst może być trudny do zrozumienia. Rozważ udostępnienie skomplikowanego adresu URL, takiego jak https://www.google.com/search?ei=2rRVXcLkJajM0PEPoLy7oA4. Bogatszy podgląd może zapewnić użytkowników, że udostępniane treści są odpowiednie.

Jeśli wyświetlasz podgląd tekstu, możesz ustawić tytuł, miniaturę lub oba te elementy. Przed wywołaniem Intent.createChooser() dodaj opis do Intent.EXTRA_TITLE i dodaj odpowiednią miniaturę za pomocą ClipData.

Uwaga: identyfikator URI treści obrazu jest podawany przez FileProvider, zwykle z skonfigurowanej <cache-path>. Więcej informacji znajdziesz w artykule Udostępnianie plików. Upewnij się, że arkusz udostępniania ma odpowiednie uprawnienia do odczytu dowolnego obrazu, którego chcesz użyć jako miniatury. Więcej informacji znajdziesz w artykule Intent.FLAG_GRANT_READ_URI_PERMISSION.

Oto przykład:

fun richContentToTextPreviewShares(context: Context) {
    val share = Intent.createChooser(
        Intent().apply {
            action = ACTION_SEND
            putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/")

            // (Optional) Here you're setting the title of the content
            putExtra(Intent.EXTRA_TITLE, "Introducing content previews")

            // (Optional) Here you're passing a content URI to an image to be displayed
            data =
                Uri.parse("content://com.google.android.apps.photos.contentprovider/0/1/mediakey/A123456789")
            flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        },
        null
    )
    context.startActivity(share)
}

Podgląd wygląda mniej więcej tak:

Rysunek 2. Podgląd treści tekstowych w arkuszu udostępniania w Androidzie.

Dodawanie działań niestandardowych do arkusza udostępniania

Rysunek 3. Działania niestandardowe w arkuszu udostępniania w Androidzie.

W Androidzie 14 (poziom interfejsu API 34) i nowszym aplikacje mogą dodawać działania niestandardowe do arkusza udostępniania w Androidzie. Działania niestandardowe są wyświetlane jako małe ikony działań u góry arkusza udostępniania w Androidzie, a aplikacje mogą określić dowolną Intent jako działanie wywoływane po kliknięciu ikony.

Aby dodać działania niestandardowe w arkuszu udostępniania w Androidzie, najpierw utwórz a ChooserAction za pomocą ChooserAction.Builder. Możesz określić PendingIntent jako działanie wywoływane po kliknięciu ikony. Utwórz tablicę zawierającą wszystkie działania niestandardowe i określ ją jako EXTRA_CHOOSER_CUSTOM_ACTIONS intencji udostępniania Intent.

fun sharesheetCustomActions(context: Context, previewText: String) {
    val sendIntent = Intent(ACTION_SEND)
        .setType("text/plain")
        .putExtra(Intent.EXTRA_TEXT, previewText)
    val shareIntent = Intent.createChooser(sendIntent, null)
    val customActions = arrayOf(
        ChooserAction.Builder(
            Icon.createWithResource(context, R.drawable.ic_logo),
            "Custom",
            PendingIntent.getBroadcast(
                context,
                1,
                Intent(Intent.ACTION_VIEW),
                PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
            )
        ).build()
    )
    shareIntent.putExtra(Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS, customActions)
    context.startActivity(shareIntent)
}

Dodawanie kierowania niestandardowego

Arkusz udostępniania w Androidzie umożliwia określenie maksymalnie 2 niestandardowych intencji Activity, które są wymienione przed sugestiami aplikacji za pomocą Intent.EXTRA_INITIAL_INTENTS. W przypadku miejsc docelowych udostępniania bezpośredniego (takich jak rozmowy lub kontakty) publikuj skróty dynamiczne za pomocą ShortcutManagerCompat zamiast (patrz Udostępnianie miejsc docelowych udostępniania bezpośredniego):

Rysunek 4. Miejsca docelowe niestandardowe w arkuszu udostępniania Androida.

Dodaj Intent.EXTRA_INITIAL_INTENTS do intencji udostępniania po wywołaniu Intent.createChooser():

val sendIntent = Intent(ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, previewText)
}

val customIntent = Intent().apply {
    component = ComponentName(context.packageName, "${context.packageName}.CustomActivity")
}

val shareIntent = Intent.createChooser(sendIntent, null).apply {
    putExtra(
        Intent.EXTRA_INITIAL_INTENTS,
        arrayOf(customIntent)
    )
}
context.startActivity(shareIntent)

Używaj tej funkcji ostrożnie. Każda dodana intencja niestandardowa Intent zmniejsza liczbę sugestii systemu. Ogólnie unikaj dodawania kierowania niestandardowego. Typowym przykładem dodawania Intent.EXTRA_INITIAL_INTENTS jest udostępnianie dodatkowych działań, które użytkownicy mogą wykonywać na udostępnianych treściach. Na przykład użytkownik udostępnia obrazy, a Intent.EXTRA_INITIAL_INTENTS umożliwia mu wysłanie linku.

Wykluczanie określonych miejsc docelowych według komponentu

Możesz wykluczyć określone miejsca docelowe, podając Intent.EXTRA_EXCLUDE_COMPONENTS. Rób to tylko w przypadku usuwania miejsc docelowych, nad którymi masz kontrolę. Typowym przypadkiem użycia jest ukrywanie miejsc docelowych udostępniania aplikacji, gdy użytkownicy udostępniają treści z aplikacji, ponieważ prawdopodobnie chcą udostępnić je poza aplikacją.

Po wywołaniu Intent.createChooser() dodaj Intent.EXTRA_EXCLUDE_COMPONENTS do intencji:

fun excludeSpecificTargets(context: Context) {
    val share = Intent.createChooser(Intent(ACTION_SEND), null).apply {
        // Only use for components you have control over
        val excludedComponentNames =
            arrayOf(ComponentName("com.example.android", "ExampleClass"))
        putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, excludedComponentNames)
    }
    context.startActivity(share)
}

Uzyskiwanie informacji o udostępnianiu

Może być przydatne, aby wiedzieć, kiedy użytkownicy udostępniają treści i jakie miejsce docelowe wybierają. Arkusz udostępniania w Androidzie umożliwia uzyskanie tych informacji przez podanie ComponentName miejsc docelowych wybranych przez użytkowników za pomocą IntentSender.

Najpierw utwórz PendingIntent dla BroadcastReceiver i podaj jego IntentSender w Intent.createChooser():

fun infoAboutSharing(context: Context, requestCode: Int) {
    var share = Intent(ACTION_SEND)
    // ...
    val pi = PendingIntent.getBroadcast(
        context, requestCode,
        Intent(context, ShareBroadcastReceiver::class.java),
        PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
    )
    share = Intent.createChooser(share, null, pi.intentSender)
    context.startActivity(share)
}

Odbierz wywołanie zwrotne w MyBroadcastReceiver i sprawdź Intent.EXTRA_CHOOSER_RESULT:

override fun onReceive(context: Context?, intent: Intent) {
    val TAG = ShareBroadcastReceiver::class.simpleName
    val chooserResult: ChooserResult? = IntentCompat.getParcelableExtra(
        intent,
        Intent.EXTRA_CHOOSER_RESULT,
        ChooserResult::class.java,
    )
    chooserResult?.let {
        Log.i(TAG,
            "Share callback: isShortcut: ${it.isShortcut}, type: ${typeToString(it.type)}, componentName: ${it.selectedComponent}",
        )
    } ?: Log.i(TAG, "chooserResult is null")
}

Więcej informacji znajdziesz w przykładzie udostępniania na platformie.

Korzystanie z rozpoznawania intencji Androida

Rysunek 5. Rozpoznawanie intencji ACTION_SEND.

Rozpoznawanie intencji Androida najlepiej sprawdza się w przypadku wysyłania danych do innej aplikacji w ramach dobrze zdefiniowanego przepływu zadań.

Aby użyć rozpoznawania intencji Androida, utwórz intencję i dodaj dodatkowe informacje tak jak w przypadku wywoływania arkusza udostępniania w Androidzie. Jednak nie wywołuj Intent.createChooser().

Jeśli jest zainstalowanych kilka aplikacji z filtrami pasującymi do ACTION_SEND i typu MIME, system wyświetli okno z pytaniem o wybór , które umożliwia użytkownikowi wybranie miejsca docelowego udostępniania. Jeśli pasuje tylko jedna aplikacja, zostanie ona uruchomiona.

Oto przykład użycia rozpoznawania intencji Androida do wysyłania tekstu:

fun intentResolver(context: Context) {
    val sendIntent: Intent = Intent().apply {
        action = ACTION_SEND
        putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
        type = "text/plain"
    }
    context.startActivity(sendIntent)
}

Więcej informacji

Więcej informacji o wysyłaniu danych znajdziesz w artykule Intencje i filtry intencji.