Criar um autenticador de stubs

O framework do adaptador de sincronização presume que o adaptador transfira dados entre o armazenamento do dispositivo associado a uma conta e um armazenamento do servidor que exige acesso com 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 contas e autenticação do Android e fornece uma interface padrão para gerenciar credenciais de usuário, por exemplo, informações de login.

Mesmo que seu app não use contas, você precisa fornecer um componente de autenticação. Se você não usar login em contas ou no servidor, as informações gerenciadas pelo autenticador serão ignoradas para que você possa fornecer um componente de autenticação que contenha implementações de método stub. Você também precisará 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 stub necessárias para atender aos requisitos do framework do adaptador de sincronização. Se precisar fornecer um autenticador real que gerencie contas de usuários, 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 depois crie stubs para os métodos necessários, seja retornando null ou lançando 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 de vinculação do Android que permite ao framework chamar o autenticador e transmitir dados entre ele e o framework.

Como o framework inicia este Service na primeira vez que precisa acessar o autenticador, você também pode usar o serviço para instanciar o autenticador chamando o construtor de autenticadores no método Service.onCreate() do serviço.

O snippet a seguir 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(this)
        }

        /*
         * 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(this);
        }
        /*
         * 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 contas, 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 exibidos pelo sistema, quando você quer 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 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, junto com uma conta de usuário, é enviado para o servidor como parte das credenciais de login.

Mesmo que seu servidor não exija login, você ainda precisará fornecer um tipo de conta. Para o valor, use um nome de domínio que você controla. Embora o framework o utilize 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, forneça esse recurso de ícone. Ele aparece na seção Contas do app Config. 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 Config. 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, forneça essa string. Ela aparece na seção Contas do app Config. 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 que vincula o autenticador ao framework do adaptador de sincronização. Para identificar esse serviço para o sistema declare-o no manifesto do seu app, adicionando o seguinte elemento <service> como 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 do intent android.accounts.AccountAuthenticator, enviada pelo sistema para executar o autenticador. Quando o filtro é acionado, o sistema inicia AuthenticatorService, o Service vinculado que você forneceu para unir o autenticador.

O elemento <meta-data> declara os metadados para o 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 usar 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.