Criar um tipo de conta personalizado

Até agora, falamos sobre o acesso às APIs do Google, que usam contas e usuários definidos pelo Google. No entanto, se você tiver seu próprio serviço on-line, ele não terá usuários ou Contas do Google. Então, o que você precisa fazer? Na verdade, é relativamente simples instalar novos tipos de conta no dispositivo de um usuário. Esta lição explica como criar um tipo de conta personalizada que funciona da mesma maneira que as contas integradas.

Implementar seu código de conta personalizado

Primeiramente, você precisará de uma forma de receber credenciais do usuário. Isso pode ser tão simples quanto uma caixa de diálogo que solicita um nome e uma senha. Ou pode ser um procedimento mais diferente, como uma senha única ou uma verificação biométrica. De qualquer maneira, é sua responsabilidade implementar o código que:

  1. coleta as credenciais do usuário.
  2. autentica as credenciais com o servidor;
  3. armazena as credenciais no dispositivo,

Normalmente, uma única atividade pode lidar com esses três requisitos. Chamaremos isso de atividade do autenticador.

Como as atividades do autenticador precisam interagir com o sistema do AccountManager, as atividades do autenticador têm alguns requisitos que as atividades normais não têm. Para que seja mais fácil acertar tudo, o framework do Android fornece uma classe de base, AccountAuthenticatorActivity, que pode ser estendida para criar seu próprio autenticador personalizado.

Você decide como lidar com os dois primeiros requisitos de uma atividade do autenticador, coleta de credenciais e autenticação. Se houvesse apenas uma maneira de fazer isso, não haveria necessidade de tipos de conta "personalizados". O terceiro requisito tem uma implementação canônica e bastante simples:

Kotlin

Account(username, your_account_type).also { account ->
    accountManager.addAccountExplicitly(account, password, null)
}

Java

final Account account = new Account(username, your_account_type);
accountManager.addAccountExplicitly(account, password, null);

Segurança inteligente

É importante entender que AccountManager não é um serviço de criptografia nem um conjunto de chaves. Ele armazena as credenciais da conta na forma como você as transmite, em texto simples. Na maioria dos dispositivos, essa não é uma preocupação específica, porque as informações são armazenadas em um banco de dados que só pode ser acessado pela raiz. No entanto, em um dispositivo com acesso root, as credenciais podem ser lidas por qualquer pessoa com acesso adb ao dispositivo.

Com isso em mente, não transmita a senha atual do usuário para AccountManager.addAccountExplicitly(). Em vez disso, é necessário armazenar um token criptograficamente seguro que teria uso limitado para um invasor. Se suas credenciais de usuário estiverem protegendo algo valioso, considere fazer algo semelhante.

Lembrete:quando se trata do código de segurança, siga a regra do "Caça-mitos": não tente fazer isso em casa. Consulte um profissional de segurança antes de implementar um código de conta personalizado.

Agora que já tratamos das exoneração de responsabilidade sobre segurança, é hora de voltar ao trabalho. Você já implementou a parte principal do código da sua conta personalizada. O que resta é simples.

Estender o AbstractAccountAuthenticator

Para que AccountManager funcione com seu código de conta personalizado, você precisa de uma classe que implemente as interfaces esperadas pelo AccountManager. Essa classe é a de autenticador.

A maneira mais fácil de criar uma classe de autenticador é estender AbstractAccountAuthenticator e implementar os métodos abstratos dele. Se você já concluiu as lições anteriores, os métodos abstratos de AbstractAccountAuthenticator parecerão familiares: eles são o lado oposto dos métodos que você chamou na lição anterior para receber informações da conta e tokens de autorização.

A implementação correta de uma classe de autenticador requer várias partes separadas de código. Primeiro, o AbstractAccountAuthenticator tem sete métodos abstratos que precisam ser modificados. Em segundo lugar, você precisa adicionar um filtro de intent para "android.accounts.AccountAuthenticator" ao manifesto do aplicativo (mostrado na próxima seção). Por fim, você precisa fornecer dois recursos XML que definem, entre outras coisas, o nome do seu tipo de conta personalizada e o ícone que o sistema exibirá ao lado de contas desse tipo.

Você pode encontrar um guia passo a passo para implementar uma classe de autenticador e os arquivos XML na documentação AbstractAccountAuthenticator.

Se a atividade do autenticador precisar de quaisquer parâmetros especiais de inicialização, você poderá anexá-los à intent usando Intent.putExtra().

Criar um serviço de autenticador

Agora que você tem uma classe de autenticador, precisa de um lugar para ela funcionar. Autenticadores de conta precisam estar disponíveis para vários aplicativos e funcionar em segundo plano. Portanto, é necessário que sejam executados dentro de um Service. Chamaremos isso de serviço de autenticador.

Seu serviço de autenticador pode ser muito simples. Tudo o que ele precisa fazer é criar uma instância da sua classe de autenticador em onCreate() e chamar getIBinder() em onBind().

Adicione uma tag <service> ao arquivo de manifesto, adicione um filtro de intent para a intent AccountAuthenticator e declare o autenticador de conta:

<service ...>
   <intent-filter>
      <action android:name="android.accounts.AccountAuthenticator" />
   </intent-filter>
   <meta-data android:name="android.accounts.AccountAuthenticator"
             android:resource="@xml/authenticator" />
</service>

Distribuir o serviço

Pronto! O sistema agora reconhece seu tipo de conta, ao lado de todos os tipos de conta conhecidos, como "Google" e "Corporate". Você pode usar a página Configurações de contas e sincronização para adicionar uma conta. Os apps que solicitam contas do seu tipo personalizado poderão enumerar e autenticar como fariam com qualquer outro tipo de conta.

Obviamente, tudo isso pressupõe que o serviço da sua conta está realmente instalado no dispositivo. Se apenas um app acessar o serviço, isso não é um grande problema, basta agrupar o serviço no app. Mas, se você quiser que o serviço da sua conta seja usado por mais de um app, as coisas ficam mais complicadas. Não é recomendável agrupar o serviço com todos os apps e ter várias cópias dele ocupando espaço no dispositivo do usuário.

Uma solução seria colocar o serviço em um APK pequeno para fins especiais. Quando um app quiser usar um tipo de conta personalizada, ele poderá verificar se o serviço dessa conta está disponível no dispositivo. Caso contrário, ele pode direcionar o usuário ao Google Play para fazer o download do serviço. Isso pode parecer um grande problema no início, mas é bem fácil em comparação com a alternativa de inserir novamente as credenciais para todos os apps que usam sua conta personalizada.