1page.title=Creating a Custom Account Type 2parent.title=Remembering and Authenticating Users 3parent.link=index.html 4 5trainingnavtop=true 6previous.title=Authenticating to OAuth2 Services 7previous.link=authenticate.html 8 9@jd:body 10 11<div id="tb-wrapper"> 12 <div id="tb"> 13<h2>This lesson teaches you to</h2> 14<ol> 15 <li><a href="#AccountCode">Implement Your Custom Account Code</a></li> 16 <li><a href="#Security">Be Smart About Security!</a></li> 17 <li><a href="#ExtendThatThing">Extend AbstractAccountAuthenticator</a></li> 18 <li><a href="#TaskFour">Create an Authenticator Service</a></li> 19 <li><a href="#DistributeService">Distribute Your Service</a></li> 20</ol> 21 22<h2>You should also read</h2> 23<ul> 24 <li><a 25href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> 26SampleSyncAdapter app</a></li> 27</ul> 28 </div> 29</div> 30 31<p>So far we've talked about accessing Google APIs, which use accounts and users 32defined by Google. If you have your own online service, though, it won't have 33Google accounts or users, so what do you do? It turns out 34to be relatively straightforward to install new account types on a user's 35device. This lesson explains how to create a custom account type that works the 36same way as the built-in accounts do. </p> 37 38 39<h2 id="AccountCode">Implement Your Custom Account Code</h2> 40 41<p>The first thing you'll need is a way to get credentials from the user. This 42may be as simple as a dialog box that asks for a name and a password. Or it may 43be a more exotic procedure like a one-time password or a biometric scan. Either 44way, it's your responsibility to implement the code that:</p> 45<ol> 46 <li>Collects credentials from the user</li> 47 <li>Authenticates the credentials with the server</li> 48 <li>Stores the credentials on the device</li> 49</ol> 50 51 52<p>Typically all three of these requirements can be handled by one activity. We'll call this the 53authenticator activity.</p> 54 55<p>Because they need to interact with the {@link android.accounts.AccountManager} system, 56authenticator activities have certain requirements that normal activities don't. To make it easy to 57get things right, the Android framework supplies a base class, {@link 58android.accounts.AccountAuthenticatorActivity}, which you can extend to create your own custom 59authenticator.</p> 60 61<p>How you address the first two requirements of an authenticator activity, 62credential collection and authentication, is completely up to you. (If there 63were only one way to do it, there'd be no need for "custom" account types, after 64all.) The third requirement has a canonical, and rather simple, 65implementation:</p> 66 67<pre> 68final Account account = new Account(mUsername, <em>your_account_type</em>); 69mAccountManager.addAccountExplicitly(account, mPassword, null); 70</pre> 71 72 73<h2 id="Security">Be Smart About Security!</h2> 74 75<p>It's important to understand that {@link android.accounts.AccountManager} is not an encryption 76service 77or a keychain. It stores account credentials just as you pass them, in <strong>plain 78text</strong>. On most devices, this isn't 79a particular concern, because it stores them in 80a database that is only accessible to root. But on a rooted device, the 81credentials would be readable by anyone with {@code adb} access to the device.</p> 82 83<p>With this in mind, you shouldn't pass the user's actual 84password to {@link android.accounts.AccountManager#addAccountExplicitly 85AccountManager.addAccountExplicitly()}. Instead, you should store a 86cryptographically secure token that would be of limited use to an attacker. If your 87user credentials are protecting something valuable, you should carefully 88consider doing something similar.</p> 89 90<p class="caution"><strong>Remember:</strong> When it comes to security code, follow the 91"Mythbusters" rule: don't try this at home! Consult a security professional before implementing any 92custom account code.</p> 93 94<p>Now that the security disclaimers are out of the way, it's time to get back to work. 95You've already implemented the meat of your custom account code; what's left is 96plumbing.</p> 97 98 99<h2 id="ExtendThatThing">Extend AbstractAccountAuthenticator</h2> 100 101<p>In order for the {@link android.accounts.AccountManager} to work with your custom account 102code, you 103need a class that implements the interfaces that {@link android.accounts.AccountManager} expects. 104This class is the <em>authenticator class</em>.</p> 105 106<p>The easiest way to create an authenticator class is to extend 107{@link android.accounts.AbstractAccountAuthenticator} and implement its abstract methods. If you've 108worked through the previous lessons, the abstract methods of 109{@link android.accounts.AbstractAccountAuthenticator} should look familiar: they're the opposite 110side of 111the methods you called in the previous lesson to get account information and 112authorization tokens.</p> 113 114<p>Implementing an authenticator class properly requires a number of separate 115pieces of code. First, {@link android.accounts.AbstractAccountAuthenticator} has seven abstract 116methods that you must override. Second, you need to add an 117<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filter</a> for 118<code>"android.accounts.AccountAuthenticator"</code> to your application 119manifest (shown in the next section). Finally, you must supply two XML resources that define, among 120other 121things, the name of your custom account type and the icon that the system will 122display next to accounts of this type.</p> 123 124<p> You can find a step-by-step guide to implementing a successful authenticator class and the XML 125files in the {@link android.accounts.AbstractAccountAuthenticator} documentation. There's also a 126sample implementation in the <a 127href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> 128SampleSyncAdapter sample app</a>.</p> 129 130<p>As you read through the SampleSyncAdapter code, you'll notice that several of 131the methods return an intent in a bundle. This is the same intent that will be 132used to launch your custom authenticator activity. If your authenticator 133activity needs any special initialization parameters, you can attach them to the 134intent using {@link android.content.Intent#putExtra Intent.putExtra()}.</p> 135 136 137<h2 id="TaskFour">Create an Authenticator Service</h2> 138 139<p>Now that you have an authenticator class, you need a place for it to live. 140Account authenticators need to be available to multiple applications and work in 141the background, so naturally they're required to run inside a {@link android.app.Service}. We'll 142call this the authenticator service.</p> 143 144<p>Your authenticator service can be very simple. All it needs to do is create 145an instance of your authenticator class in {@link android.app.Service#onCreate onCreate()} and call 146{@link android.accounts.AbstractAccountAuthenticator#getIBinder getIBinder()} in {@link 147android.app.Service#onBind onBind()}. The <a 148href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html"> 149SampleSyncAdapter</a> contains a good example of an authenticator service.</p> 150 151<p>Don't forget to add a {@code <service>} tag to your manifest file 152and add an intent filter for the AccountAuthenticator intent and declare the account 153authenticator:</p> 154 155<pre> 156<service ...> 157 <intent-filter> 158 <action android:name="android.accounts.AccountAuthenticator" /> 159 </intent-filter> 160 <meta-data android:name="android.accounts.AccountAuthenticator" 161 android:resource="@xml/authenticator" /> 162</service> 163</pre> 164 165 166<h2 id="DistributeService">Distribute Your Service</h2> 167 168<p>You're done! The system now recognizes your account type, right alongside all 169the big name account types like "Google" and "Corporate." You can use the 170<strong>Accounts & Sync</strong> Settings page to add an account, and apps that ask for 171accounts of your custom type will be able to enumerate and authenticate just as 172they would with any other account type.</p> 173 174<p>Of course, all of this assumes that your account service is actually 175installed on the device. If only one app will ever access the service, then 176this isn't a big deal—just bundle the service in the app. 177But if you want your account service to be used by more than one app, things get 178trickier. You don't want to bundle the service with all of your apps and have 179multiple copies of it taking up space on your user's device.</p> 180 181<p>One solution is to place the service in one small, special-purpose APK. When 182an app wishes to use your custom account type, it can check the device to see if 183your custom account service is available. If not, it can direct the user to 184Google Play to download the service. This may seem like a great deal of 185trouble at first, but compared with the alternative of re-entering credentials 186for every app that uses your custom account, it's refreshingly easy.</p> 187