Obsługa ciągłości na różnych urządzeniach na Googlebooku

Użytkownicy często zaczynają wykonywać zadania na telefonie z Androidem – na przykład przeglądać dokument, sortować wiadomości lub przeglądać różne produkty – a potem chcą przejść na Chromebooka z większym wyświetlaczem, fizyczną klawiaturą i przestrzenią roboczą z wieloma oknami.

Funkcja Kontynuuj w Androidzie 17 (API na poziomie 37) i nowszym umożliwia wyświetlanie na pasku zadań Googlebook ikony aplikacji (tzw. sugestii) dla aktywności, którą użytkownik wykonywał na pobliskim telefonie. Użytkownicy mogą kontynuować aktywność na Googlebooku jednym kliknięciem.

Wdrożenie przekazywania między urządzeniami umożliwia aplikacji przenoszenie kontekstu aktywności, dzięki czemu użytkownik może wznowić pracę w adaptacyjnej aplikacji na Androida lub w przeglądarce na komputerze dokładnie w miejscu, w którym skończył na telefonie.

Wybieranie przepływu przekazywania

Zanim włączysz przekazywanie na innym urządzeniu, zdecyduj, jak każda aktywność w aplikacji na telefonie ma się otwierać, gdy użytkownik wybierze sugestię „Kontynuuj na” na Googlebooku:

Proces przekazania Kierowanie na Googlebooka Urządzenia Key API
Przekazywanie połączenia między aplikacjami Natywna aplikacja na Androida uruchomiona w oknie na komputerze Aplikacje zoptymalizowane pod kątem dużych ekranów i trybu okien na pulpicie w Google Play HandoffActivityData.Builder
Przekazywanie z aplikacji do aplikacji z zastępczą stroną internetową Natywna aplikacja na Androida, jeśli jest zainstalowana; w przeciwnym razie adres URL w domyślnej przeglądarce na komputerze Aplikacje zoptymalizowane pod kątem natywnego okna na komputerze, ale wymagające niezawodnego działania zastępczego w przeglądarce, gdy nie są zainstalowane na Chromebooku. setFallbackUri
Przekazywanie do przeglądarki Adres URL w domyślnej przeglądarce na komputerze (lub przechwycony przez aplikację natywną, jeśli jest skonfigurowana pod kątem linków aplikacji na Androida) Przepływy pracy, w których aplikacja internetowa jest głównym środowiskiem na komputerze HandoffActivityData.createWebHandoff

Włączanie przekazywania aktywności

Funkcja Kontynuuj jest domyślnie wyłączona i konfigurowana dla każdej aktywności. Wykonaj te czynności podczas każdej aktywności związanej z wysyłaniem na telefonie:

  1. Wywołaj funkcję setHandoffEnabled i przekaż true, gdy aktywność wczyta stan wymagany do przekazania. Po włączeniu tej funkcji system może wysyłać żądania danych o przekazywaniu, gdy aktywność jest na pierwszym planie lub przechodzi w tło.
  2. Zastąp onHandoffActivityDataRequested, aby zwrócić obiekt niebędący wartością null.HandoffActivityData W dowolnym momencie możesz wysłać zapytanie isHandoffEnabled, aby sprawdzić, czy przekazanie jest aktywne w przypadku działania.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.os.Bundle
import android.os.PersistableBundle

class DocumentEditorActivity : Activity() {

    private var documentId: String = "doc_42"
    private var scrollOffsetPx: Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Enable handoff once the activity is ready to transfer state.
        setHandoffEnabled(true, null)
    }

    override fun onHandoffActivityDataRequested(
        handoffRequestInfo: HandoffActivityDataRequestInfo
    ): HandoffActivityData {
        val extras = PersistableBundle().apply {
            putString(EXTRA_DOCUMENT_ID, documentId)
            putInt(EXTRA_SCROLL_OFFSET, scrollOffsetPx)
        }

        return HandoffActivityData.Builder(getComponentName())
            .setExtras(extras)
            .build()
    }

    companion object {
        const val EXTRA_DOCUMENT_ID = "extra_document_id"
        const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
    }
}

Stan działania pakietu w przypadku przekazania

System wywołuje funkcję onHandoffActivityDataRequested w 2 sytuacjach:

  • Przekazywanie na pierwszym planie: aktywność jest na pierwszym planie na telefonie, a użytkownik inicjuje przekazywanie z paska zadań Googlebooka.
  • Przechwytywanie stanu w tle: aktywność przechodzi w tle na telefonie, a system buforuje ładunek przekazywania na wypadek, gdyby użytkownik później wybrał sugestię na Googlebooku.

Sprawdzanie, czy prośba o przekazanie jest aktywna

Sprawdź HandoffActivityDataRequestInfo za pomocą isActiveRequest, aby odróżnić aktywne przekazanie zainicjowane przez użytkownika od zapisu w tle:

  • Jeśli funkcja isActiveRequest zwróci wartość true, oznacza to, że użytkownik aktywnie poprosił o kontynuowanie na innym urządzeniu, a aktywność jest widoczna.
  • Jeśli isActiveRequest zwraca false, system buforuje stan, gdy aktywność się zatrzymuje.

Jeśli na telefonie wyświetlasz wskaźnik wizualny potwierdzający, że zadanie jest przenoszone na Googlebooka, zaplanuj asynchroniczną aktualizację interfejsu, aby funkcja onHandoffActivityDataRequested zwracała wartość bez opóźnień.

Dołączanie dodatków do stanu i zastępczego adresu URL

Ładunek HandoffActivityData zawiera te informacje:

  • Komponent docelowy (wymagany w przypadku przekazywania sterowania między aplikacjami): przekazywanie parametru this.getComponentName() (ComponentName aktywności) lub jawne przekazywanie parametru ComponentName(this, TargetActivity::class.java) do HandoffActivityData.Builder, aby określić, która aktywność ma się uruchamiać w Googlebook.
  • Dodatkowe informacje (opcjonalnie): przekaż PersistableBundle do setExtras() zawierającego identyfikatory i współrzędne interfejsu (np. identyfikatory otwartych dokumentów, klucze aktywnych kart lub pozycje przewijania). Pakiet musi być mniejszy niż 50 KB.
  • Zapasowy identyfikator URI (opcjonalnie): przekaż Uri do setFallbackUri, aby Googlebook mógł otworzyć zadanie w przeglądarce domyślnej, jeśli aplikacja na Androida nie jest zainstalowana.
odbiorczym urządzeniu Googlebook.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
import android.os.PersistableBundle

class ArticleReaderActivity : Activity() {

    private var articleId: String = "android-desktop-windowing"
    private var readingProgressPercent: Int = 45

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setHandoffEnabled(
            true,
            HandoffActivityParams.Builder()
                .setAllowHandoffWithoutPackageInstalled(true)
                .build()
        )
    }

    override fun onHandoffActivityDataRequested(
        handoffRequestInfo: HandoffActivityDataRequestInfo
    ): HandoffActivityData {
        if (handoffRequestInfo.isActiveRequest()) {
            window.decorView.post {
                onHandoffStartedToSecondaryDevice()
            }
        }

        val extras = PersistableBundle().apply {
            putString(EXTRA_ARTICLE_ID, articleId)
            putInt(EXTRA_READING_PROGRESS, readingProgressPercent)
        }

        val fallbackWebUri = Uri.Builder()
            .scheme("https")
            .authority("example.com")
            .appendPath("articles")
            .appendPath(articleId)
            .appendQueryParameter("progress", readingProgressPercent.toString())
            .build()

        return HandoffActivityData.Builder(getComponentName())
            .setExtras(extras)
            .setFallbackUri(fallbackWebUri)
            .build()
    }

    private fun onHandoffStartedToSecondaryDevice() {
        // Save local drafts and update phone UI without blocking handoff.
    }

    companion object {
        const val EXTRA_ARTICLE_ID = "extra_article_id"
        const val EXTRA_READING_PROGRESS = "extra_reading_progress"
    }
}

Konfigurowanie przekazywania bezpośrednio do internetu

Jeśli głównym sposobem korzystania z Googlebooka jest aplikacja internetowa, przekaż wartość HandoffActivityParams z wartością setAllowHandoffWithoutPackageInstalled(true) do setHandoffEnabled i zamiast HandoffActivityData.Builder wywołaj HandoffActivityData.createWebHandoff:

import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle

class WebDashboardActivity : Activity() {

    private var projectId: String = "proj_901"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setHandoffEnabled(
            true,
            HandoffActivityParams.Builder()
                .setAllowHandoffWithoutPackageInstalled(true)
                .build()
        )
    }

    override fun onHandoffActivityDataRequested(
        handoffRequestInfo: HandoffActivityDataRequestInfo
    ): HandoffActivityData {
        val webUri = Uri.Builder()
            .scheme("https")
            .authority("app.example.com")
            .appendPath("projects")
            .appendPath(projectId)
            .build()

        return HandoffActivityData.createWebHandoff(webUri)
    }
}

Odbieranie i przywracanie stanu na Googlebooku

Gdy użytkownik wybierze sugestię „Kontynuuj na” na pasku zadań Googlebook, system uruchomi docelową aplikację ComponentName w oknie na komputerze i dołączy do uruchomienia Intent dodatkowe elementy PersistableBundle.

Na Googlebooku obsługuj przychodzące przekazywanie z uwzględnieniem trybu okien na pulpicie i układów wielopanelowych:

  1. Wyodrębnij dodatkowe informacje o przekazaniu: w przypadku obu metod onCreate i onNewIntent aktywności odbierającej pobierz dodatkowe informacje z przychodzącego elementu Intent. Obsługa onNewIntent zapewnia, że jeśli aktywność korzysta z singleTop trybu uruchamiania lub kieruje do istniejącego okna na komputerze, okno zostanie zaktualizowane do przekazanego elementu.
  2. Dostosuj stan do układów wielopanelowych: stan, który zajmował widok szczegółów na pełnym ekranie telefonu, często odpowiada wybranemu elementowi w układzie szczegółowej listy lub panelu pomocniczego na Googlebooku. Wypełnij zarówno listę główną, jak i panel szczegółów, aby okno na komputerze miało pełny kontekst.
  3. Zachowaj przywrócony stan podczas zmiany rozmiaru okna: zapisz przekazany stan w ViewModel (SavedStateHandle) lub rememberSaveable w Jetpack Compose, aby zmiana rozmiaru okna na Googlebooku nie resetowała przywróconej sesji.
import android.app.Activity
import android.content.Intent
import android.os.Bundle

class DocumentEditorReceiverActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Restore from the handoff intent only on initial launch so subsequent
        // desktop window configuration changes use saved instance state.
        if (savedInstanceState == null) {
            handleHandoffIntent(intent)
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleHandoffIntent(intent)
    }

    private fun handleHandoffIntent(incomingIntent: Intent?) {
        val documentId = incomingIntent?.getStringExtra(EXTRA_DOCUMENT_ID)
            ?: return
        val scrollOffsetPx = incomingIntent.getIntExtra(EXTRA_SCROLL_OFFSET, 0)

        openDocumentInDesktopWorkspace(
            documentId = documentId,
            initialScrollOffsetPx = scrollOffsetPx
        )
    }

    private fun openDocumentInDesktopWorkspace(
        documentId: String,
        initialScrollOffsetPx: Int
    ) {
        // Load the document into the list-detail layout and restore scroll position.
    }

    companion object {
        const val EXTRA_DOCUMENT_ID = "extra_document_id"
        const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
    }
}

Testowanie przekazywania między telefonem a Googlebookiem

Aby sprawdzić implementację od początku do końca:

  1. Przygotuj oba urządzenia
    • Zaloguj się na to samo konto Google na telefonie z Androidem (w wersji 17 lub nowszej) i na Googlebooku (lub urządzeniu testowym działającym w trybie okien na pulpicie).
    • Włącz Bluetootha i połącz oba urządzenia z tą samą siecią Wi-Fi.
    • Na obu urządzeniach otwórz Ustawienia > Połączone urządzenia > Ustawienia połączeń > Ustawienia dla wielu urządzeń > Kontynuowanie aktywności, postępuj zgodnie z instrukcjami konfiguracji i włącz Zadania. Pełne wymagania wstępne dotyczące środowiska znajdziesz w sekcji Konfigurowanie i testowanie.
  2. Instalowanie aplikacji
    • W przypadku przekazywania aplikacji zainstaluj kompilację zarówno na telefonie, jak i na Googlebooku.
    • W przypadku przekierowania do przeglądarki lub bezpośredniego przekierowania do przeglądarki zainstaluj kompilację na telefonie i pozostaw aplikację odinstalowaną na Chromebooku, aby sprawdzić, czy przeglądarka otwiera oczekiwany adres URL.
  3. Przekazywanie rozmowy
    • Otwórz aplikację na telefonie i przejdź do aktywności, która umożliwia przekazywanie (wywołanie setHandoffEnabled(true, null) w przypadku przekazywania między aplikacjami lub przekazanie HandoffActivityParams z setAllowHandoffWithoutPackageInstalled(true) podczas testowania z odinstalowaną aplikacją na Googlebooku).
    • Na Googlebooku sprawdź prawą stronę paska zadań. Powinna tam być ikona aplikacji z odznaką „Kontynuuj na”. Kliknij ją.
  4. Weryfikowanie przywracania komputera
    • Sprawdź, czy aplikacja otwiera się w oknie na komputerze (lub w karcie przeglądarki) w tym samym miejscu i z tą samą pozycją przewijania co na telefonie.
    • Zmień rozmiar okna aplikacji na urządzeniu Googlebook i sprawdź, czy przywrócona treść i wybór są zachowywane podczas przechodzenia między różnymi klasami rozmiaru okna.

Dodatkowe materiały