Criar um autenticador de stubs

O framework do adaptador de sincronização presume que o adaptador de sincronização transfere dados entre o armazenamento do dispositivo associado a uma conta e o armazenamento do servidor que requer acesso de login. Por esse motivo, o framework espera que você forneça um componente chamado autenticador como parte do adaptador de sincronização. Esse componente se conecta ao framework de autenticação e contas do Android e oferece uma interface padrão para processar credenciais do usuário, como informações de login.

Mesmo que seu app não use contas, você precisa fornecer um componente de autenticação. Se você não usa login em contas ou no servidor, as informações processadas pelo autenticador serão ignoradas para que você possa fornecer um componente de autenticador que contenha implementações de métodos stub. Você também precisa fornecer um Service vinculado que permita que o framework do adaptador de sincronização chame os métodos do autenticador.

Esta lição mostra como definir todas as partes de um autenticador de stubs necessárias para atender aos requisitos do framework do adaptador de sincronização. Se precisar fornecer um autenticador real que gerencie contas de usuário, leia a documentação de referência para AbstractAccountAuthenticator.

Adicionar um componente autenticador de stubs

Para adicionar um componente autenticador de stubs no app, crie uma classe que estenda AbstractAccountAuthenticator e, em seguida, crie stubs para os métodos necessários, retornando null ou gerando uma exceção.

O snippet a seguir mostra um exemplo de uma classe de autenticador de stubs.

Kotlin

/*
 * Implement AbstractAccountAuthenticator and stub out all
 * of its methods
 */
class Authenticator(context: Context) // Simple constructor
    : AbstractAccountAuthenticator(context) {

    // Editing properties is not supported
    override fun editProperties(r: AccountAuthenticatorResponse, s: String): Bundle {
        throw UnsupportedOperationException()
    }

    // Don't add additional accounts
    @Throws(NetworkErrorException::class)
    override fun addAccount(
            r: AccountAuthenticatorResponse,
            s: String,
            s2: String,
            strings: Array<String>,
            bundle: Bundle
    ): Bundle?  = null

    // Ignore attempts to confirm credentials
    @Throws(NetworkErrorException::class)
    override fun confirmCredentials(
            r: AccountAuthenticatorResponse,
            account: Account,
            bundle: Bundle
    ): Bundle?  = null

    // Getting an authentication token is not supported
    @Throws(NetworkErrorException::class)
    override fun getAuthToken(
            r: AccountAuthenticatorResponse,
            account: Account,
            s: String,
            bundle: Bundle
    ): Bundle {
        throw UnsupportedOperationException()
    }

    // Getting a label for the auth token is not supported
    override fun getAuthTokenLabel(s: String): String {
        throw UnsupportedOperationException()
    }

    // Updating user credentials is not supported
    @Throws(NetworkErrorException::class)
    override fun updateCredentials(
            r: AccountAuthenticatorResponse,
            account: Account,
            s: String,
            bundle: Bundle
    ): Bundle {
        throw UnsupportedOperationException()
    }

    // Checking features for the account is not supported
    @Throws(NetworkErrorException::class)
    override fun hasFeatures(
            r: AccountAuthenticatorResponse,
            account: Account,
            strings: Array<String>
    ): Bundle {
        throw UnsupportedOperationException()
    }
}

Java

/*
 * Implement AbstractAccountAuthenticator and stub out all
 * of its methods
 */
public class Authenticator extends AbstractAccountAuthenticator {
    // Simple constructor
    public Authenticator(Context context) {
        super(context);
    }
    // Editing properties is not supported
    @Override
    public Bundle editProperties(
            AccountAuthenticatorResponse r, String s) {
        throw new UnsupportedOperationException();
    }
    // Don't add additional accounts
    @Override
    public Bundle addAccount(
            AccountAuthenticatorResponse r,
            String s,
            String s2,
            String[] strings,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }
    // Ignore attempts to confirm credentials
    @Override
    public Bundle confirmCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }
    // Getting an authentication token is not supported
    @Override
    public Bundle getAuthToken(
            AccountAuthenticatorResponse r,
            Account account,
            String s,
            Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
    // Getting a label for the auth token is not supported
    @Override
    public String getAuthTokenLabel(String s) {
        throw new UnsupportedOperationException();
    }
    // Updating user credentials is not supported
    @Override
    public Bundle updateCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            String s, Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
    // Checking features for the account is not supported
    @Override
    public Bundle hasFeatures(
        AccountAuthenticatorResponse r,
        Account account, String[] strings) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
}

Vincular o autenticador ao framework

Para que o framework do adaptador de sincronização acesse seu autenticador, crie um serviço vinculado a ele. Esse serviço fornece um objeto binder do Android que permite que o framework chame seu autenticador e transmita dados entre ele e o framework.

O snippet abaixo mostra como definir o Service vinculado.

Kotlin

/**
* A bound Service that instantiates the authenticator
* when started.
*/
class AuthenticatorService : Service() {

    // Instance field that stores the authenticator object
    private lateinit var mAuthenticator: Authenticator

    override fun onCreate() {
        // Create a new authenticator object
        mAuthenticator = Authenticator(getApplicationContext())
    }

    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    override fun onBind(intent: Intent?): IBinder = mAuthenticator.iBinder
}

Java

/**
 * A bound Service that instantiates the authenticator
 * when started.
 */
public class AuthenticatorService extends Service {
    ...
    // Instance field that stores the authenticator object
    private Authenticator mAuthenticator;
    @Override
    public void onCreate() {
        // Create a new authenticator object
        mAuthenticator = new Authenticator(getApplicationContext());
    }
    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mAuthenticator.getIBinder();
    }
}

Adicionar o arquivo de metadados do autenticador

Para conectar o componente autenticador ao adaptador de sincronização e a frameworks de conta, você precisa fornecer a esses frameworks metadados que descrevam o componente. Esses metadados declaram o tipo de conta que você criou para o adaptador de sincronização e declara elementos da interface do usuário que o sistema exibe se você quiser tornar o tipo de conta visível para o usuário. Declare esses metadados em um arquivo XML armazenado no diretório /res/xml/ no projeto do app. Você pode dar qualquer nome ao arquivo, embora ele seja normalmente chamado de authenticator.xml.

Esse arquivo XML contém um único elemento <account-authenticator>, que tem os seguintes atributos:

android:accountType
O framework do adaptador de sincronização exige que cada adaptador de sincronização tenha um tipo de conta, na forma de um nome de domínio. O framework usa o tipo de conta como parte da identificação interna do adaptador de sincronização. Para servidores que exigem login, o tipo de conta e uma conta de usuário são enviados ao servidor como parte das credenciais de login.

Mesmo que seu servidor não exija login, você ainda precisará fornecer um tipo de conta. Como valor, use um nome de domínio que você controla. Embora o framework o use para gerenciar o adaptador de sincronização, o valor não é enviado ao servidor.

android:icon
Ponteiro para um recurso Drawable que contém um ícone. Se você tornar o adaptador de sincronização visível especificando o atributo android:userVisible="true" em res/xml/syncadapter.xml, precisará fornecer esse recurso de ícone. Ela aparece na seção Contas do app Configurações do sistema.
android:smallIcon
Ponteiro para um recurso Drawable que contém uma versão pequena do ícone. Este recurso pode ser usado em vez de android:icon na seção Contas do app Configurações do sistema, dependendo do tamanho da tela.
android:label
String localizável que identifica o tipo de conta para os usuários. Se você tornar o adaptador de sincronização visível especificando o atributo android:userVisible="true" em res/xml/syncadapter.xml, precisará fornecer essa string. Ela aparece na seção Contas do app Configurações do sistema, ao lado do ícone definido para o autenticador.

O snippet a seguir mostra o arquivo XML para o autenticador criado anteriormente.

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:accountType="example.com"
        android:icon="@drawable/ic_launcher"
        android:smallIcon="@drawable/ic_launcher"
        android:label="@string/app_name"/>

Declarar o autenticador no manifesto

Em uma etapa anterior, você criou um Service vinculado que vincula o autenticador ao framework do adaptador de sincronização. Para identificar esse serviço para o sistema, declare-o no manifesto do app adicionando o seguinte elemento <service> como um elemento filho de <application>:

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

O elemento <intent-filter> configura um filtro que é acionado pela ação da intent android.accounts.AccountAuthenticator, enviada pelo sistema para executar o autenticador. Quando o filtro é acionado, o sistema inicia AuthenticatorService, a Service vinculada que você forneceu para unir o autenticador.

O elemento <meta-data> declara os metadados do autenticador. O atributo android:name vincula os metadados ao framework de autenticação. O elemento android:resource especifica o nome do arquivo de metadados do autenticador criado anteriormente.

Além de um autenticador, um adaptador de sincronização também exige um provedor de conteúdo. Se o app ainda não usa um provedor de conteúdo, vá para a próxima lição para saber como criar um provedor de conteúdo de stubs ou para a lição Como criar um adaptador de sincronização.