1. Visão geral
O ARCore é uma plataforma para criar apps de realidade aumentada (RA) em dispositivos móveis. Com a API Cloud Anchors, você pode criar apps de RA que compartilham um frame de referência comum, permitindo que vários usuários coloquem conteúdo virtual no mesmo local real.
Este codelab orientará você pela API Cloud Anchors. Você usará um app existente do ARCore, o modificará para usar o Cloud Anchors e criará uma experiência de RA compartilhada.
Âncoras do ARCore e âncoras permanentes do Cloud
Um conceito fundamental no ARCore é o de uma Âncora, que descreve uma posição fixa no mundo real. O ARCore ajusta automaticamente o valor da posição de uma âncora enquanto o rastreamento de movimento dela melhora com o tempo.
As âncoras do Cloud são hospedadas na nuvem. Elas podem ser resolvidas por vários usuários para estabelecer um frame de referência comum entre os usuários e os dispositivos.
Como hospedar uma âncora
Quando uma âncora é hospedada, acontece o seguinte:
- A posição da âncora com relação ao mundo é enviada para a nuvem, e um ID do Cloud Anchor é recebido.
O ID do Cloud Anchor é uma string que precisa ser enviada para qualquer pessoa que queira resolver essa âncora.. - Um conjunto de dados que contém dados visuais da âncora é enviado aos servidores do Google.
Esse conjunto contém dados visuais vistos pelo dispositivo recentemente. Mover o dispositivo um pouco para capturar a área ao redor da âncora de diferentes pontos de vista antes da hospedagem resultará em uma melhor localização.
Como transferir IDs do Cloud Anchor
Neste codelab, você vai transferir IDs do Cloud Anchor usando o Firebase. Você pode compartilhar os IDs do Cloud Anchor usando outros meios.
Como resolver uma âncora
Você pode usar a API Cloud Anchor para resolver uma âncora usando o ID do Cloud Anchor. Isso cria uma nova âncora no mesmo local físico da âncora hospedada original. Durante a resolução, o dispositivo precisa ter o mesmo ambiente físico que a âncora hospedada original.
Âncoras do Cloud permanentes
Antes da versão 1.20, o Cloud Anchors só podia ser resolvido por 24 horas depois de ser hospedado. Com a API Persistent Cloud Anchors, você pode criar uma âncora da nuvem que pode ser resolvida de 1 a 365 dias após a criação.
O que você criará
Neste codelab, você criará com base em um app do ARCore existente. Ao final do codelab, seu app será capaz de:
- hospedar Cloud Anchors permanentes e receber IDs do Cloud Anchor;
- salvar os IDs do Cloud Anchor no dispositivo para facilitar a recuperação usando o Android
SharedPreferences
; - usar os IDs salvos do Cloud Anchor para resolver âncoras hospedadas anteriormente, o que facilita a simulação de uma experiência com vários usuários em um único dispositivo para este codelab.
- Compartilhe os IDs do Cloud Anchor com outro dispositivo com o mesmo app para que vários usuários vejam a estátua do Android na mesma posição.
Uma estátua do Android é renderizada na posição do Cloud Anchor:
O que você aprenderá
- Como hospedar âncoras usando o SDK do ARCore e conseguir um ID do Cloud Anchor.
- Como usar IDs do Cloud Anchor para resolver âncoras.
- Como armazenar e compartilhar IDs do Cloud Anchor entre diferentes sessões de RA no mesmo dispositivo ou em dispositivos diferentes.
Pré-requisitos
- Um dispositivo compatível com o ARCore, conectado por um cabo USB à sua máquina de desenvolvimento.
- Google Play Services para RA 1.22 ou mais recente.
- Uma máquina de desenvolvimento com o Android Studio (v3.0 ou mais recente).
2. Configurar seu ambiente de desenvolvimento
Como configurar a máquina de desenvolvimento
Conecte o dispositivo ARCore ao computador usando o cabo USB. Verifique se o dispositivo permite a depuração USB.
Abra um terminal e execute adb devices
, como mostrado abaixo:
adb devices List of devices attached <DEVICE_SERIAL_NUMBER> device
A <DEVICE_SERIAL_NUMBER>
será uma string exclusiva do dispositivo. Antes de continuar, verifique se apenas um dispositivo é exibido.
Como fazer o download e instalar o código
Você pode clonar o repositório:
git clone https://github.com/googlecodelabs/arcore-cloud-anchors.git
Ou fazer o download de um arquivo ZIP e extraí-lo:
Inicie o Android Studio. Clique em Open an existing Android Studio project. Em seguida, navegue até o diretório em que você extraiu o arquivo ZIP depois de ter feito o download acima e clique duas vezes no diretório arcore-cloud-anchors
.
Esse é um projeto individual do Gradle com vários módulos. Se ele não ainda não for exibido no painel "Project" no canto superior esquerdo do Android Studio, clique em Projects no menu suspenso. O resultado será semelhante a este:
Você trabalhará principalmente no módulo work
. Outros módulos incluem um módulo helpers
, que contém um conjunto de classes de wrappers úteis que você usará. Também fornecemos soluções completas para cada parte do codelab. Com exceção do módulo helpers
, cada módulo é um app que pode ser compilado.
Se uma caixa de diálogo sugerir que você faça upgrade do Plug-in do Android para Gradle, clique em Don't remind me again for this project:
Clique em Executar > Executar... > "trabalho". Na caixa de diálogo Select Deployment Target que será exibida, o dispositivo estará listado em Connected Devices. Selecione o dispositivo e clique em OK. O Android Studio criará o app inicial e o executará no dispositivo.
Quando você executar o app pela primeira vez, ele solicitará a permissão CAMERA
. Toque em PERMITIR para continuar.
Como usar o app
- Mova o dispositivo para ajudar o app a encontrar uma superfície plana. Uma superfície plana será pontilhada quando encontrada.
- Toque em algum lugar plano para colocar uma âncora. Um ícone do Android será exibido onde a âncora for colocada. Este app permite colocar apenas uma âncora de cada vez.
- Mova o dispositivo pelo ambiente. A figura precisa dar a impressão de permanecer no mesmo lugar, embora o dispositivo esteja se movendo.
- Pressione o botão "CLEAN" para remover a âncora. Dessa forma, você poderá colocar outra âncora.
No momento, este app só usa o rastreamento de movimento fornecido pelo ARCore para monitorar uma âncora em uma única execução do app. Se você sair, encerrar e reiniciar o app, a âncora colocada anteriormente e todas as informações relacionadas a ela, incluindo a posição, serão perdidas.
Nas próximas seções, você vai usar este app para ver como as âncoras podem ser compartilhadas em sessões de RA.
3. Hospedar uma âncora
Nesta seção, você modificará o projeto work
para hospedar uma âncora. Antes de escrever o código, será necessário implementar algumas modificações na configuração do app.
Declarar permissões INTERNET
Como o Cloud Anchors precisa de comunicação com o serviço da API ARCore Cloud Anchor, seu app precisa ter permissão para acessar a Internet.
No seu arquivo AndroidManifest.xml
, adicione a seguinte linha logo abaixo da declaração de permissão android.permission.CAMERA
:
<!-- Find this line... -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- Add the line right below -->
<uses-permission android:name="android.permission.INTERNET"/>
Ativar a API ARCore Cloud Anchor
- Acesse a página de serviços da API ARCore Cloud Anchor.
- Na lista de projetos, selecione um projeto ou crie um novo.
- Clique em Ativar.
Configurar o OAuth
Para usar os âncoras de nuvem permanentes, você precisará usar o OAuth para fazer a autenticação com o serviço do ARCore Cloud Anchor.
- Acesse o Console do Google Cloud Platform.
- Selecione um projeto na lista.
- Se a página de APIs e serviços ainda não estiver aberta, abra o menu lateral à esquerda do console e selecione APIs e serviços.
- À esquerda, clique em Credentials.
- Clique em Criar credenciais e selecione ID do cliente OAuth.
- Preencha os seguintes valores:
- Tipo de aplicativo: Android
- Nome do pacote:
com.google.ar.core.codelab.cloudanchor
- Recupere sua impressão digital do certificado de assinatura de depuração:
- No projeto do Android Studio, abra o painel de ferramentas do Gradle.
- Em cloud-anchors > work > Tarefas > android, execute a tarefa signingReport.
- Copie a impressão digital SHA-1 para o campo de impressão digital do certificado SHA-1 no Google Cloud.
Configurar o ARCore
Em seguida, você modificará o app para criar uma âncora hospedada no toque de um usuário, em vez de uma âncora normal. Para fazer isso, você precisa configurar a sessão do ARCore para ativar o Cloud Anchors.
No arquivo CloudAnchorFragment.java
, adicione o seguinte código:
// Find this line...
session = new Session(requireActivity());
// Add these lines right below:
// Configure the session.
Config config = new Config(session);
config.setCloudAnchorMode(CloudAnchorMode.ENABLED);
session.configure(config);
Antes de continuar, crie e execute o app. Lembre-sede criar apenas o módulo work
. O app será criado e executado da mesma forma que antes.
Criar uma âncora hospedada
Está na hora de criar uma âncora hospedada que será enviada ao serviço do ARCore Cloud Anchor.
Adicione os novos campos a seguir à classe CloudAnchorFragment
:
// Find this line...
private final SnackbarHelper messageSnackbarHelper = new SnackbarHelper();
// Add this line right below.
private final CloudAnchorManager cloudAnchorManager = new CloudAnchorManager();
As classes CloudAnchorManager
e SnackbarHelper
já foram fornecidas a você. Essas são algumas classes de wrapper úteis que encapsulam código boilerplate para que o código programado seja muito mais limpo e menos detalhado.
No método onDrawFrame()
, adicione a linha mencionada abaixo:
// Find this line...
Frame frame = session.update();
// Add this line right below:
cloudAnchorManager.onUpdate();
Modifique o método onClearButtonPressed
desta maneira:
private synchronized void onClearButtonPressed() {
// Clear the anchor from the scene.
// The next line is the new addition.
cloudAnchorManager.clearListeners();
currentAnchor = null;
}
Em seguida, adicione o seguinte método à classe CloudAnchorFragment
:
private synchronized void onHostedAnchorAvailable(Anchor anchor) {
CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == CloudAnchorState.SUCCESS) {
messageSnackbarHelper.showMessage(
getActivity(), "Cloud Anchor Hosted. ID: " + anchor.getCloudAnchorId());
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
}
}
Localize o método handleTap
na classe CloudAnchorFragment
e adicione estas linhas:
//Find this line...
currentAnchor = hit.createAnchor();
// Add these lines right below:
messageSnackbarHelper.showMessage(getActivity(), "Now hosting anchor...");
cloudAnchorManager.hostCloudAnchor(session, currentAnchor, /* ttl= */ 300, this::onHostedAnchorAvailable);
Execute o app no Android Studio novamente: Você verá a mensagem "Now hosting anchor..." ao colocar uma âncora. Você verá outra mensagem quando a hospedagem for concluída. Se a mensagem "Error hosting anchor: ERROR_NOT_AUTHORIZED
" for exibida, verifique se o cliente OAuth está configurado corretamente.
Qualquer pessoa que conheça o ID da âncora e esteja presente no mesmo espaço físico que a âncora pode usar o código para criar uma âncora na mesma posição (posição e orientação) relativa ao ambiente ao redor dela.
No entanto, o ID da âncora é longo e não é fácil para outro usuário inserir manualmente. Nas seções a seguir, você armazenará IDs do Cloud Anchor de maneira fácil de recuperar para permitir que as âncoras sejam resolvidas no mesmo dispositivo ou em outro.
4. Armazenar IDs e resolver âncoras
Nesta parte, você atribuirá códigos curtos aos IDs longos do Cloud Anchor para facilitar a entrada manual de outro usuário. Você usará a API Shared Preferences para armazenar os IDs do Cloud Anchor como valores em uma tabela de chave-valor. Essa tabela persistirá mesmo se o app for encerrado e reiniciado.
Uma classe auxiliar chamada StorageManager
já foi fornecida para você. Trata-se de um wrapper em torno da API SharedPreferences
que tem métodos para gerar novos códigos curtos exclusivos e ler/gravar IDs do Cloud Anchor.
Usar o StorageManager
Modifique CloudAnchorFragment
para usar StorageManager
para armazenar IDs do Cloud Anchor com códigos curtos e facilitar a recuperação.
Crie o novo campo a seguir em CloudAnchorFragment
:
// Find this line...
private TapHelper tapHelper;
// And add the storageManager.
private final StorageManager storageManager = new StorageManager();
Em seguida, modifique o método onHostedAnchorAvailable
:
private synchronized void onHostedAnchorAvailable(Anchor anchor) {
CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == CloudAnchorState.SUCCESS) {
int shortCode = storageManager.nextShortCode(getActivity());
storageManager.storeUsingShortCode(getActivity(), shortCode, anchor.getCloudAnchorId());
messageSnackbarHelper.showMessage(
getActivity(), "Cloud Anchor Hosted. Short code: " + shortCode);
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
}
}
Agora, crie e execute o app no Android Studio. Ao criar e hospedar uma âncora, você verá códigos curtos em vez de IDs longos do Cloud Anchor.
Imediatamente após colocar uma âncora | Depois de esperar um pouco |
No momento, os códigos curtos gerados por StorageManager
são sempre atribuídos em ordem crescente.
Em seguida, você adicionará alguns elementos da IU que permitirão inserir códigos curtos e recriar as âncoras.
Adicionar o botão "Resolver"
Você adicionará outro botão ao lado do botão CLEAN. Esse será o botão RESOLVE. Clicar no botão RESOLVE abrirá uma caixa de diálogo que solicita ao usuário um código curto. O código curto é usado para recuperar o ID do Cloud Anchor do StorageManager
e resolver a âncora.
Para adicionar o botão, modifique o arquivo res/layout/cloud_anchor_fragment.xml
. No Android Studio, clique duas vezes no arquivo e, em seguida, na guia "Texto" na parte inferior para exibir o XML bruto. Faça as seguintes modificações:
<!-- Find this element. -->
<Button
android:text="CLEAR"
android:id="@+id/clear_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- Add this element right below. -->
<Button
android:text="RESOLVE"
android:id="@+id/resolve_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Agora, adicione um novo campo ao CloudAnchorFragment
:
private Button resolveButton;
Adicione um novo método:
private synchronized void onResolveButtonPressed() {
ResolveDialogFragment dialog = new ResolveDialogFragment();
dialog.show(getFragmentMagetActivity().getSupportFragmentManagernager(), "Resolve");
}
Inicialize resolveButton
no método onCreateView
da seguinte maneira:
// Find these lines...
Button clearButton = rootView.findViewById(R.id.clear_button);
clearButton.setOnClickListener(v -> onClearButtonPressed());
// Add these lines right below.
resolveButton = rootView.findViewById(R.id.resolve_button);
resolveButton.setOnClickListener(v -> onResolveButtonPressed());
Encontre e modifique o método handleTap
:
private void handleTap(Frame frame, Camera camera) {
// ...
// Find this line.
currentAnchor = hit.createAnchor();
// Add this line right below.
getActivity().runOnUiThread(() -> resolveButton.setEnabled(false));
}
Adicione uma linha no método onClearButtonPressed
:
private synchronized void onClearButtonPressed() {
// Clear the anchor from the scene.
cloudAnchorManager.clearListeners();
// The next line is the new addition.
resolveButton.setEnabled(true);
currentAnchor = null;
}
Crie e execute o app no Android Studio. Você verá o botão RESOLVE ao lado do botão CLEAN. Ao clicar no botão RESOLVE, uma caixa de diálogo será exibida como mostrado abaixo.
O botão RESOLVE agora está visível. | Ao clicar no botão, essa caixa de diálogo é exibida |
Tocar no plano e hospedar uma âncora deve desativar o botão RESOLVE, mas tocar no botão CLEAN deve ativá-lo novamente. Isso ocorre por padrão, de modo que apenas uma âncora aparece por vez.
A caixa de diálogo "Resolve Anchor" não faz nada, mas você pode mudar isso agora.
Resolver âncoras
Adicione os seguintes métodos à classe CloudAnchorFragment
:
private synchronized void onShortCodeEntered(int shortCode) {
String cloudAnchorId = storageManager.getCloudAnchorId(getActivity(), shortCode);
if (cloudAnchorId == null || cloudAnchorId.isEmpty()) {
messageSnackbarHelper.showMessage(
getActivity(),
"A Cloud Anchor ID for the short code " + shortCode + " was not found.");
return;
}
resolveButton.setEnabled(false);
cloudAnchorManager.resolveCloudAnchor(
session,
cloudAnchorId,
anchor -> onResolvedAnchorAvailable(anchor, shortCode));
}
private synchronized void onResolvedAnchorAvailable(Anchor anchor, int shortCode) {
CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == CloudAnchorState.SUCCESS) {
messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Resolved. Short code: " + shortCode);
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(
getActivity(),
"Error while resolving anchor with short code " + shortCode + ". Error: "
+ cloudState.toString());
resolveButton.setEnabled(true);
}
}
Em seguida, modifique o método onResolveButtonPressed
:
private synchronized void onResolveButtonPressed() {
ResolveDialogFragment dialog = ResolveDialogFragment.createWithOkListener(
this::onShortCodeEntered);
dialog.show(getActivity().getSupportFragmentManager(), "Resolve");
}
Crie e execute o app no Android Studio e siga estas etapas:
- Crie uma âncora em um plano e aguarde a hospedagem da âncora.
Lembre-se do código curto. - Pressione o botão CLEAN para excluir a âncora.
- Pressione o botão RESOLVE. Digite o código curto da etapa 1.
- Você verá uma âncora na mesma posição em relação ao ambiente em que foi colocada originalmente.
- Saia e encerre o aplicativo. Feito isso, abra-o novamente.
- Repita as etapas 3 e 4. Você verá uma nova âncora, novamente na mesma posição.
Como inserir um código curto | A âncora foi resolvida |
5. Compartilhar entre dispositivos
Você viu como armazenar o ID do Cloud Anchor de uma âncora no armazenamento local do seu dispositivo e recuperá-lo mais tarde para recriar a mesma âncora. Mas todo o potencial do Cloud Anchors é desbloqueado apenas quando você pode compartilhar os IDs do Cloud Anchor entre diferentes dispositivos.
Você escolhe como o app compartilhará os IDs do Cloud Anchor. Tudo pode ser usado para transferir a string de um dispositivo para outro. Neste codelab, você usará o Firebase Realtime Database para transferir IDs do Cloud Anchor entre instâncias do app.
Configurar o Firebase
Você precisa configurar um Firebase Realtime Database com sua Conta do Google para usar com este app. Isso é fácil com o Firebase Assistente no Android Studio.
No Android Studio, clique em Ferramentas > Firebase. No painel do Assistente exibido, clique em Realtime Database e em Save and retrieve data:
Clique no botão Connect to Firebase para conectar seu projeto do Android Studio a um projeto novo ou existente do Firebase.
Aparecerá uma solicitação para selecionar um módulo. Selecione o módulo work
:
A caixa de diálogo "Iniciando conexão" é exibida. Isso pode demorar um pouco.
Faça login com sua Conta do Google e siga o fluxo de trabalho da Web para criar um projeto do Firebase para seu app até retornar ao Android Studio.
Depois, no painel do Assistente, clique em add the Realtime Database to your app:
Na caixa de diálogo exibida, selecione work no menu suspenso Módulo de destino e clique em Aceitar alterações.
Esta ação resultará no seguinte:
- Adicione um arquivo
google-services.json
ao diretóriowork
- Adicione algumas linhas ao arquivo
build.gradle
no mesmo diretório. - Crie e execute o app. Talvez você veja um erro de solução no número da versão do banco de dados do Firebase.
No arquivo build.gradle
do módulo work
, localize e remova a seguinte linha (o xxxx
é um marcador para o número da versão mais recente).
dependencies {
...
implementation 'com.google.firebase:firebase-database:xxxx'
Em seguida, revise (mas não siga) as instruções vinculadas na página Configurar suas regras para acesso público e configure seu Firebase Realtime Database para ser gravável por todos. Isso ajuda a simplificar os testes neste codelab:
No Console do Firebase, selecione o projeto a que você conectou o projeto do Android Studio e selecione CRIAR > Realtime Database.
Clique em Create Database para configurar o Realtime Database:
Escolha qualquer local do banco de dados.
Na próxima etapa, selecione as regras de segurança do modo de teste e clique em Ativar:
Seu app agora está configurado para usar o banco de dados do Firebase.
Como usar o FirebaseManager
Você substituirá o StorageManager
pelo FirebaseManager
.
No Android Studio, localize a classe CloudAnchorFragment
no diretório work
. Substitua o StorageManager
por um FirebaseManager
:
// Find this line.
private final StorageManager storageManager = new StorageManager();
// And replace it with this line.
private FirebaseManager firebaseManager;
Inicialize firebaseManager
no método onAttach
:
public void onAttach(@NonNull Context context) {
super.onAttach(context);
tapHelper = new TapHelper(context);
trackingStateHelper = new TrackingStateHelper(requireActivity());
// The next line is the new addition.
firebaseManager = new FirebaseManager(context);
}
Modifique o método onShortCodeEntered
desta maneira:
private synchronized void onShortCodeEntered(int shortCode) {
firebaseManager.getCloudAnchorId(shortCode, cloudAnchorId -> {
if (cloudAnchorId == null || cloudAnchorId.isEmpty()) {
messageSnackbarHelper.showMessage(
getActivity(),
"A Cloud Anchor ID for the short code " + shortCode + " was not found.");
return;
}
resolveButton.setEnabled(false);
cloudAnchorManager.resolveCloudAnchor(
session,
cloudAnchorId,
anchor -> onResolvedAnchorAvailable(anchor, shortCode));
});
}
Em seguida, modifique o método onHostedAnchorAvailable
da seguinte maneira:
private synchronized void onHostedAnchorAvailable(Anchor anchor) {
CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == CloudAnchorState.SUCCESS) {
String cloudAnchorId = anchor.getCloudAnchorId();
firebaseManager.nextShortCode(shortCode -> {
if (shortCode != null) {
firebaseManager.storeUsingShortCode(shortCode, cloudAnchorId);
messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Hosted. Short code: " + shortCode);
} else {
// Firebase could not provide a short code.
messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Hosted, but could not "
+ "get a short code from Firebase.");
}
});
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
}
}
Crie e execute seu app. Você verá o mesmo fluxo de IU da seção anterior. A diferença é que agora o banco de dados on-line do Firebase está sendo usado para armazenar IDs do Cloud Anchor e códigos curtos em vez de armazenamento local no dispositivo.
Teste de vários usuários
Para testar a experiência multiusuário, use dois smartphones diferentes:
- Instale o app em dois dispositivos.
- Use um dispositivo para hospedar uma âncora e gerar um código curto.
- Use o outro dispositivo para resolver a âncora usando esse código curto.
Você poderá hospedar âncoras de um dispositivo, acessar um código curto e usá-lo no outro dispositivo para ver a âncora no mesmo lugar.
6. Resumo
Parabéns! Você chegou ao fim deste codelab.
O que vimos
- Como hospedar âncoras usando o SDK do ARCore e conseguir um ID do Cloud Anchor.
- Como usar IDs do Cloud Anchor para resolver âncoras.
- Como armazenar e compartilhar IDs do Cloud Anchor entre diferentes sessões de RA no mesmo dispositivo ou em dispositivos diferentes.