So its been nearly a year that I created this blog, and I have unsuccessfully written a blog post yet. I guess the first step is always the hardest. Finally I can celebrate a triumph of getting over mental barriers that I have imposed over myself by asking me if my articles would be any good and whether it would be critiqued in the quality of the content given my poor experience in the industry. But, as we all know, you can’t satisfy everyone, and I have started accepting critiques as the only that people would point out to me how to get better. So please all feedback, welcome!
So to commence, I will give a brief reasoning as to why I will write about Android Authenticator. Simply, documentation is bad and I need a reference for myself. If I might be writing notes for myself I might as well share them with the rest of the world, maybe someone out there will help my notes completeness over the topic given any gaps and help me improve too.
Ok, enough of introductions,
lets get our code dirty lets commence.
What this articles assumes of the reader.
- Knowledge of authentication methods such as OAuth or any method that uses tokens in each request.
- Knowledge of Android Service.
- Knowledge of other basic Android concepts such as application permissions, AndroidManifest, etc …
Why use Android Authenticator?
Authenticator and SyncAdapters complement each other, but it is wise to use Authenticator to manage your application accounts even if you are not using SyncAdapters. More on SyncAdapters will follow in subsequent articles.
The reason for using Authenticator and the underlying AccountManager API is that a uniform method and experience for the user to manage its accounts for apps installed in its device (UX is an important subject by itself and out of scope of this article), and for the developer a reason not to reinvent the wheel and/or write boilerplate code and only write logic that makes your app different and unique compared to others (need I mention that authentication is pretty standard?).
So what features does the Account Manager API pack?
- Centralised registry of the users online Accounts.
- Convenience to the user to specify its user and password combination once per account. This can then be used across multiple apps, rather needing to specify username and password per app. Its always good to think ahead if its your first app for a given account type. A good example is the multiple google apps that can be contained within a device and with a only need to authenticate the user once. The Account Manager API also supports very well accounts that do not store passwords but only tokens, storing passwords per account is optional.
- Can have multiple accounts within a device of the same type, i.e. again see Google apps example.
- Can store multiple types of auth token against a single. In my case while creating an app the only token returned by the server granted full access to the account resources, but in case of using scope based tokens, you could store multiple tokens against an account.
- Can add accounts without launching your app and then if using sync adapters, can sync data again all without launching your app!
- Handles positive and negative case scenarios of the authentication process.
I assume that by reading to this point that I have convinced you, or you were already convinced in implementing and using Android Authenticator. So to the good stuff.
What we need to do:
- We need to create an Android Service.
- Due to the fact that the operation of syncing (I know, SyncAdapters and Authenticators are made for each other!), adding accounts, updating accounts information is specific to the server implementation of authentication and what our app supports, the Authenticator should be able to be invoked by the Android system outside the normal process of running the application.
- We need to create a class that extends the AbstractAccountAuthenticator abstract class. Our previous service must return an class instance that extends this class on the onBind method, this will export the methods of our class to be called from the system.
- Create an XML file describing how the account should look like in the Accounts Manager within Settings (Settings > Accounts Manager)
- Adding some relevant permission. At the minimum you would need to add the permission android.permission.AUTHENTICATE_ACCOUNTS, but depending on how you access the accounts and from where some more permission might be needed.
While I really wanted to get down to writing example code, I will leave it to another article with proper examples, for now as the first part of this “series” of articles I will break down the mechanism of how Android interacts with the Android Service and the implementation of the AbstractAccountAuthenticator.
Account lookup resolution
So in this part of the article I will run through some case scenarios, maybe later I’ll add a flow diagram. Please use the docs from Android along with this article (AbstractAccountAuthenticator).
First time logging in
Through the Account Manager in Settings the user is able to click on the ” + Add accounts” row. This will invoke the abstract method addAccount implemented by you. From here you could launch a Login Activity which would capture the user credentials, authenticate with your server and receive a token. If successfully logged in the activity should create a new Account instance and then use AccountManager.addAccountExplicitly() to add the new Account to the system. Depending on your authentication method, you can save the password against an account as the second argument of addAccountExplicitly() or leave it as null if no password based authentication method is used. To save tokens, you can use the AccountManager.setAuthToken(). You can save multiple tokens against the same account, thats why you should specify the token type in the second argument. For example if all of your apps use third parties to authenticate the user, as minimum the scope of a token might be just the email address of the user, but some optional features within the app might require some additional information such as date of birth, so another token can be issued with those additional scope and both tokens can be maintained.
It is important to note that refreshing a token or issuing another need to be maintained by your app.
Accessing account data from your app
You can use the AccountManager.getAccountsByType() to retrieve all the accounts associated to your app or apps specifying the account type. This will return all the associated accounts, it is up-to your app to either select one or all, like the Gmail app does, when viewing a single account only the emails of that account will be retrieved and displayed, otherwise if you select within the app to show all emails regardless of the account, it will then retrieve all the relevant emails from all the accounts associated with the Gmail app.
P.S. will continue editing this article and add more content for completeness.