| page.title=Creating a Custom Account Type |
| parent.title=Remembering and Authenticating Users |
| parent.link=index.html |
| |
| trainingnavtop=true |
| previous.title=Authenticating to OAuth2 Services |
| previous.link=authenticate.html |
| |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| <h2>This lesson teaches you to</h2> |
| <ol> |
| <li><a href="#AccountCode">Implement Your Custom Account Code</a></li> |
| <li><a href="#Security">Be Smart About Security!</a></li> |
| <li><a href="#ExtendThatThing">Extend AbstractAccountAuthenticator</a></li> |
| <li><a href="#TaskFour">Create an Authenticator Service</a></li> |
| <li><a href="#DistributeService">Distribute Your Service</a></li> |
| </ol> |
| |
| <h2>You should also read</h2> |
| <ul> |
| <li><a |
| href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> |
| SampleSyncAdapter app</a></li> |
| </ul> |
| </div> |
| </div> |
| |
| <p>So far we've talked about accessing Google APIs, which use accounts and users |
| defined by Google. If you have your own online service, though, it won't have |
| Google accounts or users, so what do you do? It turns out |
| to be relatively straightforward to install new account types on a user's |
| device. This lesson explains how to create a custom account type that works the |
| same way as the built-in accounts do. </p> |
| |
| |
| <h2 id="AccountCode">Implement Your Custom Account Code</h2> |
| |
| <p>The first thing you'll need is a way to get credentials from the user. This |
| may be as simple as a dialog box that asks for a name and a password. Or it may |
| be a more exotic procedure like a one-time password or a biometric scan. Either |
| way, it's your responsibility to implement the code that:</p> |
| <ol> |
| <li>Collects credentials from the user</li> |
| <li>Authenticates the credentials with the server</li> |
| <li>Stores the credentials on the device</li> |
| </ol> |
| |
| |
| <p>Typically all three of these requirements can be handled by one activity. We'll call this the |
| authenticator activity.</p> |
| |
| <p>Because they need to interact with the {@link android.accounts.AccountManager} system, |
| authenticator activities have certain requirements that normal activities don't. To make it easy to |
| get things right, the Android framework supplies a base class, {@link |
| android.accounts.AccountAuthenticatorActivity}, which you can extend to create your own custom |
| authenticator.</p> |
| |
| <p>How you address the first two requirements of an authenticator activity, |
| credential collection and authentication, is completely up to you. (If there |
| were only one way to do it, there'd be no need for "custom" account types, after |
| all.) The third requirement has a canonical, and rather simple, |
| implementation:</p> |
| |
| <pre> |
| final Account account = new Account(mUsername, <em>your_account_type</em>); |
| mAccountManager.addAccountExplicitly(account, mPassword, null); |
| </pre> |
| |
| |
| <h2 id="Security">Be Smart About Security!</h2> |
| |
| <p>It's important to understand that {@link android.accounts.AccountManager} is not an encryption |
| service |
| or a keychain. It stores account credentials just as you pass them, in <strong>plain |
| text</strong>. On most devices, this isn't |
| a particular concern, because it stores them in |
| a database that is only accessible to root. But on a rooted device, the |
| credentials would be readable by anyone with {@code adb} access to the device.</p> |
| |
| <p>With this in mind, you shouldn't pass the user's actual |
| password to {@link android.accounts.AccountManager#addAccountExplicitly |
| AccountManager.addAccountExplicitly()}. Instead, you should store a |
| cryptographically secure token that would be of limited use to an attacker. If your |
| user credentials are protecting something valuable, you should carefully |
| consider doing something similar.</p> |
| |
| <p class="caution"><strong>Remember:</strong> When it comes to security code, follow the |
| "Mythbusters" rule: don't try this at home! Consult a security professional before implementing any |
| custom account code.</p> |
| |
| <p>Now that the security disclaimers are out of the way, it's time to get back to work. |
| You've already implemented the meat of your custom account code; what's left is |
| plumbing.</p> |
| |
| |
| <h2 id="ExtendThatThing">Extend AbstractAccountAuthenticator</h2> |
| |
| <p>In order for the {@link android.accounts.AccountManager} to work with your custom account |
| code, you |
| need a class that implements the interfaces that {@link android.accounts.AccountManager} expects. |
| This class is the <em>authenticator class</em>.</p> |
| |
| <p>The easiest way to create an authenticator class is to extend |
| {@link android.accounts.AbstractAccountAuthenticator} and implement its abstract methods. If you've |
| worked through the previous lessons, the abstract methods of |
| {@link android.accounts.AbstractAccountAuthenticator} should look familiar: they're the opposite |
| side of |
| the methods you called in the previous lesson to get account information and |
| authorization tokens.</p> |
| |
| <p>Implementing an authenticator class properly requires a number of separate |
| pieces of code. First, {@link android.accounts.AbstractAccountAuthenticator} has seven abstract |
| methods that you must override. Second, you need to add an |
| <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filter</a> for |
| <code>"android.accounts.AccountAuthenticator"</code> to your application |
| manifest (shown in the next section). Finally, you must supply two XML resources that define, among |
| other |
| things, the name of your custom account type and the icon that the system will |
| display next to accounts of this type.</p> |
| |
| <p> You can find a step-by-step guide to implementing a successful authenticator class and the XML |
| files in the {@link android.accounts.AbstractAccountAuthenticator} documentation. There's also a |
| sample implementation in the <a |
| href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> |
| SampleSyncAdapter sample app</a>.</p> |
| |
| <p>As you read through the SampleSyncAdapter code, you'll notice that several of |
| the methods return an intent in a bundle. This is the same intent that will be |
| used to launch your custom authenticator activity. If your authenticator |
| activity needs any special initialization parameters, you can attach them to the |
| intent using {@link android.content.Intent#putExtra Intent.putExtra()}.</p> |
| |
| |
| <h2 id="TaskFour">Create an Authenticator Service</h2> |
| |
| <p>Now that you have an authenticator class, you need a place for it to live. |
| Account authenticators need to be available to multiple applications and work in |
| the background, so naturally they're required to run inside a {@link android.app.Service}. We'll |
| call this the authenticator service.</p> |
| |
| <p>Your authenticator service can be very simple. All it needs to do is create |
| an instance of your authenticator class in {@link android.app.Service#onCreate onCreate()} and call |
| {@link android.accounts.AbstractAccountAuthenticator#getIBinder getIBinder()} in {@link |
| android.app.Service#onBind onBind()}. The <a |
| href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> |
| SampleSyncAdapter</a> contains a good example of an authenticator service.</p> |
| |
| <p>Don't forget to add a {@code <service>} tag to your manifest file |
| and add an intent filter for the AccountAuthenticator intent and declare the account |
| authenticator:</p> |
| |
| <pre> |
| <service ...> |
| <intent-filter> |
| <action android:name="android.accounts.AccountAuthenticator" /> |
| </intent-filter> |
| <meta-data android:name="android.accounts.AccountAuthenticator" |
| android:resource="@xml/authenticator" /> |
| </service> |
| </pre> |
| |
| |
| <h2 id="DistributeService">Distribute Your Service</h2> |
| |
| <p>You're done! The system now recognizes your account type, right alongside all |
| the big name account types like "Google" and "Corporate." You can use the |
| <strong>Accounts & Sync</strong> Settings page to add an account, and apps that ask for |
| accounts of your custom type will be able to enumerate and authenticate just as |
| they would with any other account type.</p> |
| |
| <p>Of course, all of this assumes that your account service is actually |
| installed on the device. If only one app will ever access the service, then |
| this isn't a big deal—just bundle the service in the app. |
| But if you want your account service to be used by more than one app, things get |
| trickier. You don't want to bundle the service with all of your apps and have |
| multiple copies of it taking up space on your user's device.</p> |
| |
| <p>One solution is to place the service in one small, special-purpose APK. When |
| an app wishes to use your custom account type, it can check the device to see if |
| your custom account service is available. If not, it can direct the user to |
| Google Play to download the service. This may seem like a great deal of |
| trouble at first, but compared with the alternative of re-entering credentials |
| for every app that uses your custom account, it's refreshingly easy.</p> |