Android用户使用他们的设备以及他们喜欢的应用程序。让你的应用用户体验友好的一种方式是使你的应用私人化。Android设备识别你的用户:他们使用了何种服务,数据存储在何处。通过用户的许可,你可以用那些信息使你的应用更加丰富,更多个性化体验。

这节课,你将学会多种用户身份交互技术,能够让你:

•使用账户名记住用户,从而个性化你的app。

•认证用户,确认他们的身份。

•通过服务(如google APIs),获得权限去访问用户的在线数据。

 

课程表:

记住你的用户

认证Oauth2服务

创建自定义账号类型

 

记住你的用户:

每个人都喜欢你能记住他们的名字。让你的app更友好,你能做的最简单,最有效的事情之一是记住你的用户,尤其是当用户升级到一个新设备或者同时使用平板以及手机。但是你怎么知道你的用户是谁,你怎样在新设备上识别他们?

对很多app来说,答案是使用AccountManager APIs。通过用户授权,你能够使用账户管理获取用户存储在设备中的账户名。

与用户账户整合,允许你做各种事情,比如:

•自动填充用户email地址表单

•获取用户绑定的ID,而不是设备ID。

 

确定AccountManager是否适合您

应用程序通常试图记住用户会使用以下三种技术中的一种:

A.     要求用户输入用户名

B.     获取唯一的设备ID去记住设备

C.     从AccountManager检索内置账户

选项(a)是有问题的。首先,进入app之前要求用户进行输入,会使你的app缺乏吸引力。其次,不能保证用户名的唯一性。

选项(b)对用户不够简洁。但是获取权限却是严格的。更重要的是,它只允许你记住一个设备上的用户。很难想象那些升级到一个新的设备,然后才发现你的app不再记住他们的用户,回事多么沮丧。

选项(C)是首先技术。账户管理允许你获取存储在用户设备中的账户信息。在本节课也会学到用账户管理让你记住你的用户,不管用户有多少设备,实现这一点仅需要在你的UI中增加一对额外的tap。

决定使用哪种类型的账户:

Android设备能够存储来自不同提供者(Provider)的多种账户。当你从com/reference/android/accounts/AccountManager.html">AccountManager查询账户名时,你可以通过账户类型进行过滤。账户类型是一个字符串,它唯一标示存储在账户中的实体。例如:google账户使用"com.google"形式,而twitter使用"com.twitter.android.auth.login"。

请求GET_ACCOUNT权限

为了得到设备上的账户列表,你的app需要GET_ACCOUNTS权限。在manifest文件添加

<uses-permission>标签请求这个权限:


<manifest ... >
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    ...
</manifest>


查询AccountManager得到账户列表

一旦你决定选定的账户类型,你就需要查询那种类型的账户。通过调用AccountManaqger.get()得到AccountManager的实例,然后用该实例去调用getAcccountByType()


AccountManager am = AccountManager.get(this); // "this" references the current Context

Account[] accounts = am.getAccountsByType("com.google");



这会返回一个

Account

数组对象。如果在这个数组中的 Account

对象多以一个,你应该显示一个对话框让用户选择其中的一个。

使用Account对象私有化你的App

Account对象包含一个账户名,对于google账户会是一个email地址。你可以在不同的场景中使用该信息(账户名),比如:

•作为表单填充时的建议,如此用户不必手动输入账户信息。

•作为你的在线数据库(用户存储用户的App使用和个性化信息)的键值。

确认一个账户名是否够用

账户名是一种很好的方式去记住用户,但是Account对象不会保护你的数据,也不能让你访问用户的账户名以外的任何东西。如果你的app需要允许用户在线访问私有数据,你需要更健壮的东西,即认证。下节课会阐述怎样认证在线服务。这节课,完成一个自定义认证之后,你可以使用你自己的账户类型

 

认证Oauth2服务:


自定义账户类型

目前我们已经讨论过使用账户或google所定义的用户访问google Api。如果你有自己的在线服务,然而却没有google账户和用户,该怎么办呢?直截了当的方法是在用户的设备上安装新的账户类型。这节课会讲述怎样创建自定义账户类型,并像内置账户一样工作。

实现你的自定义账户编码

你需要做的第一件事是从用户获取凭据。这也许就像有一个对话框去询问用户名和密码一样简单。甚至也许是一个更奇特的程序就像一次性密码或生物扫描(biometric scan)。不论哪种方式,你的责任是要去实现代码:

1.      收集用户凭据

2.      与服务器认证凭据

3.      在设备上存储凭据

 

通常上面三种需求可以被一个Activity处理。我们将调用这个验证(Authenticator)Activity。

由于需要与账户管理系统交互,Authenticator 会有普通Activity所没有的需求。为了使事情简化,Android FrameWork提供了一个基类AccountAuthenticatorActivity,你可以对其进行扩展从而创建自定义验证程序。

怎样解决一个验证Activity中的前两个需求:凭据的收集和认证,这全取决于你。(如果只有一种实现方式,那就没什么必要自定义账户类型)第三个需求有一个规范,也相当简单,实现方法:

final Account account = newAccount(mUsername, your_account_type);
mAccountManager.addAccountExplicitly(account,mPassword, null);


对于安全的智能化

AccountManager不是一个加密服务或密钥链,理解这点很重要。它存储账户凭据,就像你在纯文本看到的那样。在多数设备上,这并没受到特别关注,因为它存储在数据库中,只能被root访问。但是在一个已经被root的设备上,证书就会被那些使用adb访问设备的人读取。考虑到这一点,不能在调用addAccountExplicitly() 时传递用户的真实密码。应该存储加密了的有使用限制的安全令牌,防止黑客攻击。如果你的用户凭据保护了一些有用的东西,那么你应该考虑做同样的事情。

记住:当涉及安全码,遵循“Mythbusters”原则:不要自己私自尝试。实现任何自定义账户代码之前,应该咨询安全人士。

既然安全申明在讨论范围之外,是时候回到工作当中来了。你已经实现了自定义账户的主体,剩下的就是使用它。

扩展AbstractAccountAuthenticator

为了使AccountManager运用你的自定义账户代码,你要有一个类实现AccountManager预置的接口。这个类就是验证类。

创建一个验证类最简单的方法是继承AbstractAccountAuthenticator并实现它的抽象方法。如果你通过了先前的课程,你会发现AbstractAccountAuthenticator的抽象方法看起来很相似:它们是先前课程中用来获取账户信息和认证令牌的方法的对立面。

实现一个验证类需要许多分散的代码片段,首先,AbstractAccountAuthenticator有几个你必须重写的方法。其次,在manifest中为"android.accounts.AccountAuthenticator"添加一个inten tfilter(会在下一节讲)。最后,必须提供两个XML资源文件,用于定义自定义账户类型的名字,以及系统在该账户类型下显示的图标。

AbstractAccountAuthenticator文档中,你能找到实现一个完整的验证类的一步步指导。在SampleSyncAdapter中有一个实现示例。

如果你读过SampleSyncAdapter代码,你会注意到几个方法在bundle里返回了intent。这与用来启动自定义验证Activity的intent是同一个intent。如果你的验证Activity需要任何特殊的初始化参数,你可以使用Intent.putExtra() Intent.putExtra()把它们附加到intent上。

创建一个验证服务

既然已经有了一个验证类,就需要一个地方去存放它,账户验证需要适配多个应用并且在后台运行,因此要在Service中运行。我们称之为验证服务。

验证服务很简单。它要做的所有事情就是在onCreate()中创建验证类的实例并在onBind()里调用getIBinder()SampleSyncAdapter就有一个验证服务的示例。

不要忘了把<service>标签添加到manifest文件中,并且对AccountAuthenticator的intent添加intent filter,然后申明账户验证:

<service...><intent-filter><actionandroid:name="android.accounts.AccountAuthenticator"/></intent-filter><meta-data android:name="android.accounts.AccountAuthenticator"android:resource="@xml/authenticator"/></service>


分发服务

成功了!系统现在可以识别你的账户类型,所有的大企业名字的右边账户类型定义是“google”或者“Corporate”。你可以在账户与同步设置页面添加新账户,然后那些需要自定义类型账户的应用能够进行枚举和验证,就像它们在用其他账户类型一样。

当然,所有的这些都假定你的账户服务已经被安装到设备上。如果只有一个应用将访问该服务,那也不会有什么问题——仅仅是把服务绑定在应用上。但是如果你想让你的账户服务被更多的app访问,事情就会变得有点棘手。你肯定不想把服务绑定到所有的app上,这样会有多个副本,导致占据用户设备的空间。

一种解决方案是把该服务替换成一个小的,特殊目的的APK。当app希望使用自定义账户类型时,它就会检查设备,看自定义账户服务是否可用。要是不可用,就会把用户重定向到Google Play去下载该服务。起初这看起来很麻烦,但是相较于在那些使用自定义账户的app上重新键入用户凭据,这似乎很简单。