스터브 인증자 만들기

동기화 어댑터 프레임워크에서는 동기화 어댑터가 계정에 연결된 기기 저장소와 로그인 액세스가 필요한 서버 저장소 간에 데이터를 전송한다고 가정합니다. 따라서 프레임워크에서는 개발자가 동기화 어댑터의 일부로 '인증자'라는 구성요소를 제공할 것으로 기대합니다. 이 구성요소는 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()
        }
    }
    

자바

    /*
     * 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를 시작하므로 이 서비스를 사용하여 서비스의 Service.onCreate() 메서드에서 인증자 생성자를 호출함으로써 인증자를 인스턴스화할 수도 있습니다.

다음 스니펫에서는 바인드된 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(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
    }
    

자바

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

인증자 메타데이터 파일 추가

인증자 구성요소를 동기화 어댑터 및 계정 프레임워크에 연결하려면 구성요소를 설명하는 메타데이터를 이 프레임워크에 제공해야 합니다. 이 메타데이터에서는 동기화 어댑터를 위해 만든 계정 유형을 선언하고 계정 유형을 사용자에게 표시하고 싶을 때는 시스템에서 표시하는 사용자 인터페이스 요소를 선언합니다. 이 메타데이터를 앱 프로젝트의 /res/xml/ 디렉터리에 저장된 XML 파일에서 선언하세요. 파일 이름은 일반적으로 authenticator.xml이지만 원하는 이름을 지정할 수 있습니다.

이 XML 파일에는 다음 속성을 지닌 단일 요소 <account-authenticator>가 포함되어 있습니다.

android:accountType
동기화 어댑터 프레임워크는 각 동기화 어댑터에 도메인 이름 형식의 계정 유형이 있어야 합니다. 프레임워크에서는 동기화 어댑터 내부 식별의 일부로 계정 유형을 사용합니다. 로그인이 필요한 서버라면 사용자 계정과 함께 계정 유형이 로그인 사용자 인증 정보의 일부로 서버에 전송됩니다.

서버에 로그인이 필요하지 않더라도 계정 유형을 제공해야 합니다. 자신이 직접 제어하는 도메인 이름을 이 값에 사용하세요. 프레임워크에서는 이 값을 사용하여 동기화 어댑터를 관리하지만 값이 서버로 전송되지는 않습니다.

android:icon
아이콘이 포함된 드로어블 리소스를 가리키는 포인터입니다. res/xml/syncadapter.xml에서 android:userVisible="true" 속성을 지정하여 동기화 어댑터를 표시하려면 이 아이콘 리소스를 제공해야 합니다. 이 아이콘 리소스는 시스템 설정 앱의 계정 섹션에 표시됩니다.
android:smallIcon
작은 버전의 아이콘이 포함된 드로어블 리소스를 가리키는 포인터입니다. 이 리소스는 화면 크기에 따라 시스템 설정 앱의 계정 섹션에 있는 android:icon 대신에 사용할 수 있습니다.
android:label
사용자에게 계정 유형을 식별해주는 현지화 가능한 문자열입니다. res/xml/syncadapter.xml에서 android:userVisible="true" 속성을 지정하여 동기화 어댑터를 표시하려면 이 문자열을 제공해야 합니다. 이 문자열은 시스템 설정 앱의 계정 섹션에서 인증자에 관해 정의한 아이콘 옆에 표시됩니다.

다음 스니펫에서는 앞서 만든 인증자의 XML 파일을 보여줍니다.

    <?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"/>
    

매니페스트에서 인증자 선언

이전 단계에서는 인증자를 동기화 어댑터 프레임워크에 연결하는 바인드된 Service를 생성했습니다. 시스템에서 이 서비스를 식별하도록 하려면 다음 <service> 요소를 <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>
    

<intent-filter> 요소에서는 시스템이 인증자를 실행하기 위해 전송한 android.accounts.AccountAuthenticator 인텐트 작업에서 트리거하는 필터를 설정합니다. 필터가 트리거되면 시스템에서는 인증자를 래핑하기 위해 제공한 바인드된 ServiceAuthenticatorService를 시작합니다.

<meta-data> 요소에서는 인증자의 메타데이터를 선언합니다. android:name 속성은 메타데이터를 인증 프레임워크에 연결합니다. android:resource 요소에서는 앞서 만든 인증자 메타데이터 파일의 이름을 지정합니다.

동기화 어댑터에는 인증자 외에 콘텐츠 제공업체도 필요합니다. 앱에서 아직 콘텐츠 제공업체를 사용하지 않는다면 다음 과정으로 이동하여 스터브 콘텐츠 제공업체를 만드는 방법을 알아보세요. 이미 사용하고 있다면 동기화 어댑터 만들기 과정으로 이동하세요.