Os usuários costumam começar tarefas no smartphone Android, como revisar um documento, triar mensagens ou navegar por uma variedade de itens, e depois querem passar para um Googlebook com tela maior, teclado físico e espaço de trabalho com várias janelas.
O recurso Continuar em no Android 17 (nível 37 da API) e versões mais recentes permite que a barra de tarefas do Googlebook mostre um ícone de app (chamado de sugestão) para a atividade que um usuário estava executando no smartphone por perto. Com um único clique, os usuários podem continuar a atividade no Googlebook.
A implementação da transferência entre dispositivos permite que seu app transfira o contexto da atividade para que o usuário retome o fluxo de trabalho, seja no app Android adaptável ou no navegador para computador, exatamente de onde parou no smartphone.
Escolher um fluxo de transferência
Antes de ativar a transferência entre dispositivos, decida como cada atividade no app Telefone deve ser aberta quando um usuário selecionar a sugestão "Continuar no" no Googlebook:
| Fluxo de transferência | Segmentar no Googlebook | Ideal para | API Key |
|---|---|---|---|
| Transferência de app para app | App Android nativo sendo executado em uma janela de computador | Apps otimizados para telas grandes e modo janela para computador no Google Play | HandoffActivityData.Builder |
| Transferência de app para app com fallback da Web | App Android nativo, se instalado. Caso contrário, uma URL no navegador padrão para computador | Apps otimizados para uma experiência nativa de janela de computador, mas que exigem um navegador confiável quando o app não está instalado no Googlebook. | setFallbackUri |
| Transferência direta para a Web | URL no navegador padrão para computador ou interceptado pelo app nativo, se configurado para links de apps Android | Fluxos de trabalho em que seu aplicativo da Web é a principal experiência de computador | HandoffActivityData.createWebHandoff |
Ativar a transferência de uma atividade
O recurso "Continuar em" fica desativado por padrão e é configurado por atividade. Siga estas etapas em cada atividade de envio no smartphone:
- Chame
setHandoffEnablede transmitatrueassim que a atividade carregar o estado necessário para a transferência. Depois de ativado, o sistema pode solicitar dados de transferência enquanto a atividade está em primeiro plano ou sendo movida para segundo plano. - Substitua
onHandoffActivityDataRequestedpara retornar um objetoHandoffActivityDatanão nulo. Você pode consultarisHandoffEnableda qualquer momento para verificar se a transferência está ativa para a atividade.
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"
}
}
Estado da atividade do pacote para transferência
O sistema chama onHandoffActivityDataRequested em dois cenários:
- Transferência em primeiro plano:a atividade está em primeiro plano no smartphone, e o usuário inicia uma transferência na barra de tarefas do Googlebook.
- Captura do estado em segundo plano:a atividade passa para segundo plano no smartphone, e o sistema armazena em cache a carga de transferência caso o usuário selecione a sugestão no Googlebook mais tarde.
Verificar se a solicitação de transferência está ativa
Inspecione HandoffActivityDataRequestInfo usando isActiveRequest para
distinguir entre uma transferência ativa iniciada pelo usuário e um salvamento em segundo plano:
- Se
isActiveRequestretornartrue, o usuário terá solicitado ativamente continuar em outro dispositivo enquanto a atividade estiver visível. - Se
isActiveRequestretornarfalse, o sistema vai armazenar em cache o estado quando a atividade for interrompida.
Se você mostrar um indicador visual no smartphone confirmando que a tarefa está
sendo movida para o Googlebook, programe a atualização da interface de forma assíncrona para que
onHandoffActivityDataRequested retorne sem atraso.
Anexar extras de estado e um substituto da Web
Um payload HandoffActivityData contém as seguintes informações:
- Componente de destino (obrigatório para transferência de app para app): transmita
this.getComponentName()(oComponentNameda atividade) ou umComponentName(this, TargetActivity::class.java)explícito paraHandoffActivityData.Builderpara designar qual atividade será iniciada no Googlebook. - Extras (opcional): transmita um
PersistableBundleparasetExtras()contendo identificadores e coordenadas da interface (por exemplo, IDs de documentos abertos, chaves de guias ativas ou posições de rolagem). O pacote precisa ter menos de 50 KB. - URI de substituição (opcional): transmita um
Urida Web parasetFallbackUripara que o Googlebook possa abrir a tarefa no navegador padrão se o app Android não estiver instalado.
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"
}
}
Configurar a transferência direta para a Web
Se a sua experiência principal de computador no Googlebook for um aplicativo da Web, transmita
HandoffActivityParams com setAllowHandoffWithoutPackageInstalled(true) para
setHandoffEnabled e chame HandoffActivityData.createWebHandoff em vez
de usar HandoffActivityData.Builder:
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)
}
}
Receber e restaurar o estado no Googlebook
Quando o usuário seleciona a sugestão "Continuar em" na barra de tarefas do Googlebook, o
sistema inicia o ComponentName de destino em uma janela de computador e anexa os
extras PersistableBundle ao Intent de inicialização.
No Googlebook, processe a transferência de controle com o Modo Janela para Computador e layouts de vários painéis:
- Extrair extras de transferência:nos métodos
onCreateeonNewIntentda atividade de recebimento, recupere os extras daIntentrecebida. O processamento deonNewIntentgarante que, se a atividade usar o modo de inicializaçãosingleTopou rotear para uma janela de computador já aberta, a janela será atualizada para o item transferido. - Adaptar o estado a layouts de vários painéis:um estado que ocupava uma visualização de detalhes em tela cheia em um smartphone geralmente é mapeado para um item selecionado em um layout de detalhes e listas ou de painel de suporte no Googlebook. Preencha a seleção da lista principal e o painel de detalhes para que a janela da área de trabalho tenha contexto completo.
- Preservar o estado restaurado ao redimensionar a janela:armazene o estado transferido em um
ViewModel(SavedStateHandle) ourememberSaveableno Jetpack Compose para que o redimensionamento livre da janela no Googlebook não redefina a sessão restaurada.
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"
}
}
Testar a transferência entre um smartphone e um Googlebook
Para verificar a implementação de ponta a ponta:
- Prepare os dois dispositivos
- Faça login na mesma Conta do Google no smartphone Android (com Android 17 ou mais recente) e no Googlebook (ou em um dispositivo de teste no modo janela para computador).
- Ative o Bluetooth e conecte os dois dispositivos à mesma rede Wi-Fi.
- Nos dois dispositivos, abra Configurações > Dispositivos conectados > Preferências de conexão > Serviços multidispositivo > Continuar atividade, siga as instruções de configuração e ative Tarefas. Para conferir todos os pré-requisitos do ambiente, consulte Configuração e teste.
- Instalar o app
- Para o transferência de app para app, instale o build no smartphone e no Googlebook.
- Para fallback da Web ou transferência direta para a Web, instale o build no smartphone e deixe o app desinstalado no Googlebook para verificar se o navegador abre o URL esperado.
- Acionar a transferência
- No smartphone, abra o app e navegue até a atividade que permite
a transferência (chamando
setHandoffEnabled(true, null)para transferência de app para app, ou transmitindoHandoffActivityParamscomsetAllowHandoffWithoutPackageInstalled(true)ao testar com o app desinstalado no Googlebook). - No Googlebook, confira o lado direito da barra de tarefas para encontrar o ícone do app com o selo "Continuar em" e selecione-o.
- No smartphone, abra o app e navegue até a atividade que permite
a transferência (chamando
- Verificar a restauração do computador
- Confirme se o app abre em uma janela de computador (ou guia do navegador) no item exato e na posição de rolagem do smartphone.
- Redimensione a janela do app no Google Livros e verifique se o conteúdo e a seleção restaurados persistem nas transições de classe de tamanho de janela.
Outros recursos
- Criar apps adaptáveis para o Googlebook
- Sobre o recurso Continuar no
- Ativar e personalizar a transferência entre dispositivos
- Salvar estados da interface