Как создать заглушку аутентификатора

Фреймворк адаптера синхронизации предполагает, что адаптер синхронизации передает данные между хранилищем устройства, связанным с аккаунтом, и хранилищем сервера, для доступа к которому требуется войти в аккаунт. Поэтому в рамках фреймворка требуется, чтобы вы предоставили компонент, называемый программой для аутентификации, как часть адаптера синхронизации. Этот компонент подключается к фреймворку аккаунтов и аутентификации Android и предоставляет стандартный интерфейс для обработки учетных данных пользователя, например информации для входа.

Даже если в вашем приложении не используются аккаунты, вам все равно нужно предоставить компонент аутентификатора. Если вы не используете аккаунты или вход на сервер, информация, обрабатываемая аутентификатором, игнорируется, поэтому вы можете предоставить компонент аутентификатора, содержащий реализации методов-заглушек. Вам также нужно предоставить связанный объект Service, который позволит фреймворку адаптера синхронизации вызывать методы аутентификатора.

В этом уроке рассказывается, как определить все части заглушки аутентификатора, необходимые для соответствия требованиям фреймворка адаптера синхронизации. Если вам нужно предоставить реальный аутентификатор, который обрабатывает аккаунты пользователей, ознакомьтесь со справочной документацией по AbstractAccountAuthenticator.

Как добавить компонент заглушки аутентификатора

Чтобы добавить в приложение компонент заглушки аутентификатора, создайте класс, который расширяет AbstractAccountAuthenticator, а затем заглушите необходимые методы, вернув null или вызвав исключение.

Во фрагменте кода ниже приведен пример класса заглушки аутентификатора:

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();
    }
}

Как привязать аутентификатор к фреймворку

Чтобы фреймворк адаптера синхронизации мог получить доступ к аутентификатору, необходимо создать для него связанный сервис. Этот сервис предоставляет объект связывания Android, который позволяет фреймворку вызывать ваш аутентификатор и передавать данные между аутентификатором и фреймворком.

Во фрагменте кода ниже показано, как определить границу Service:

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();
    }
}

Как добавить файл метаданных аутентификатора

Чтобы подключить компонент аутентификатора к адаптеру синхронизации и фреймворкам аккаунта, вам нужно предоставить этим фреймворкам метаданные, описывающие компонент. Эти метаданные определяют тип аккаунта, созданного для адаптера синхронизации, и элементы интерфейса, которые система показывает, если вы хотите, чтобы тип аккаунта был виден пользователю. Задекларируйте эти метаданные в XML-файле, хранящемся в каталоге /res/xml/ в проекте приложения. Вы можете дать файлу любое название, но обычно его называют authenticator.xml.

Этот XML-файл содержит один элемент <account-authenticator> со следующими атрибутами:

android:accountType
Для каждого адаптера синхронизации в фреймворке адаптеров синхронизации должен быть указан тип аккаунта в виде доменного имени. Платформа использует тип аккаунта как часть внутреннего идентификатора адаптера синхронизации. Для серверов, требующих входа в систему, тип аккаунта вместе с учетной записью пользователя отправляется на сервер как часть учетных данных для входа.

Если для вашего сервера не требуется вход, все равно нужно указать тип аккаунта. В качестве значения используйте доменное имя, которым вы управляете. Хотя фреймворк использует его для управления адаптером синхронизации, значение не отправляется на ваш сервер.

android:icon
Указатель на ресурс Drawable, содержащий значок. Если вы сделаете адаптер синхронизации видимым, указав атрибут android:userVisible="true" в res/xml/syncadapter.xml, то должны будете предоставить этот ресурс значка. Он находится в разделе Аккаунты приложения "Настройки".
android:smallIcon
Указатель на ресурс Drawable, содержащий уменьшенную версию значка. Этот ресурс может использоваться вместо android:icon в разделе Аккаунты приложения "Настройки" в зависимости от размера экрана.
android:label
Локализуемая строка, которая идентифицирует тип аккаунта для пользователей. Если вы сделали адаптер синхронизации видимым, указав атрибут android:userVisible="true" в res/xml/syncadapter.xml, то вам нужно предоставить эту строку. Он показывается в разделе Аккаунты приложения "Настройки" рядом со значком, который вы задали для аутентификатора.

Ниже приведен фрагмент XML-файла для созданного ранее аутентификатора:

<?xml version="1.0" encodin>g<="utf-8"?
account-authenticator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:accountType="@example.com"
        android:icon="draw@able/ic_launcher"
        android:smallI@con="drawabl>e/ic_launcher"
        android:label="string/app_name"/

Как объявить аутентификатор в манифесте

На предыдущем шаге вы создали объект Service, который связывает аутентификатор с фреймворком адаптера синхронизации. Чтобы система могла распознать этот сервис, объявите его в манифесте приложения, добавив следующий элемент <service> в качестве дочернего элемента <application>:

    <service
            android:name="com.example.android.syncadapter.AuthenticatorSer>vice"<;
        int>ent-filter
  <          action android:name="android.accounts.Account>Authentic<ator"/
  >      /in<tent-filter
        meta-data
            android:name="android.accounts.AccountAuthenticator"
            android:r>esour<ce=">;@xml/authenticator" /
    /service

Элемент <intent-filter> задает фильтр, который активируется действием интента android.accounts.AccountAuthenticator, отправляемым системой для запуска программы для аутентификации. Когда фильтр активируется, система начинает AuthenticatorService, используя предоставленный вами связанный Service для обертывания аутентификатора.

Элемент <meta-data> объявляет метаданные аутентификатора. Атрибут android:name связывает метаданные с фреймворком аутентификации. Элемент android:resource указывает название файла метаданных аутентификатора, созданного ранее.

Помимо аутентификатора, адаптеру синхронизации также требуется поставщик контента. Если в вашем приложении ещё не используется поставщик контента, перейдите к следующему уроку, чтобы узнать, как создать заглушку поставщика контента. В противном случае перейдите к уроку Создание адаптера синхронизации.