使用适用于Android API的Login with Amazon SDK(v2.0.2及更低版本)

使用适用于Android API的Login with Amazon SDK(v2.0.2及更低版本)

请注意,以下说明仅适用于更低版本的Login with Amazon Android SDK(2.0.2及更低版本)。

较低版本的SDK虽然已不可下载,但本文将保留与之相关的说明,以便为正在使用这些SDK的开发者提供帮助。

安装Android开发者工具

适用于Android的Login with Amazon SDK将帮助您为Android、Fire TV和Fire平板电脑应用添加Login with Amazon。我们建议您结合Android Studio使用适用于Android的Login with Amazon SDK,不过,您也可以使用Eclipse与ADT插件。有关如何安装Android Studio和获取Android SDK安装程序的步骤,请前往developer.android.com页面参阅获取Android SDK

Android SDK安装完成后,在Android安装应用中找到SDK Manager(SDK管理器)。为开发Login with Amazon,必须使用SDK Manager安装SDK Platform for Android 2.2或更高版(API v9)。有关如何使用SDK Manager的信息,请前往developer.android.com页面参阅添加SDK程序包

SDK安装完成后,安装Android虚拟设备(AVD)以运行应用。请前往developer.android.com页面参阅管理虚拟设备了解虚拟设备安装说明。

处理登录按钮并获取个人资料数据

本部分介绍了如何调用authorizegetProfile API来登录用户及检索其个人资料数据。这包括在应用的onCreate方法中为您的Login with Amazon按钮创建onClick侦听器。

将Login with Amazon API导入到源文件。

  1. 将Login with Amazon API导入到源文件。

    要导入Login with Amazon API,需要为源文件添加以下import语句:

    import com.amazon.identity.auth.device.AuthError;
    import com.amazon.identity.auth.device.authorization.api.AmazonAuthorizationManager;
    import com.amazon.identity.auth.device.authorization.api.AuthorizationListener;
    import com.amazon.identity.auth.device.authorization.api.AuthzConstants;
    
  2. 初始化AmazonAuthorizationManager。您需要声明AmazonAuthorizationManager变量并为此类创建新实例。创建新实例只对应用当前的环境有要求,且只需要一个空的应用。初始化AmazonAuthorizationManager的最佳位置为Activity中的onCreate方法。例如:

    private AmazonAuthorizationManager mAuthManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAuthManager = new AmazonAuthorizationManager(this, Bundle.EMPTY);
    }
    
  3. 创建AuthorizeListenerAuthorizeListener将实现AuthorizationListener接口,处理authorize调用的结果。一共包含三种方法:onSuccessonErroronCancel。每个方法都将接收到一个BundleAuthError对象。

    private class AuthorizeListener implements AuthorizationListener{
    
        /*授权已成功完成。*/
        @Override
        public void onSuccess(Bundle response) {
        }
        /*尝试授权应用时发生错误。*/
        @Override
        public void onError(AuthError ae) {
        }
        /*授权未完成便已取消。*/
        @Override
        public void onCancel(Bundle cause) {
        }
    }
    
  4. 调用AmazonAuthorizationManager.authorize

    在Login with Amazon按钮的onClick处理程序中,调用authorize来提示用户登录并授权应用。

    此方法通过以下其中一种方式授权客户:

    1. 切换到系统浏览器,以便客户登录并授权所需信息。

    2. 切换到安全环境下的网页视图,以便客户登录并授权所需信息。

    目前,Android设备的亚马逊购物应用可实现#2的安全环境。运行Fire OS的亚马逊设备(例如Kindle Fire、Fire手机和Fire TV)始终使用此选项,即使设备中没有亚马逊购物应用,也不例外。因此,如果客户已登录到亚马逊购物应用,此API将跳过登录页面,为用户提供单点登录体验。

    如果您的应用已获得授权,则将会得到一个或多个数据集的授权,即范围。第一个参数是一个范围数组,包含了向Login with Amazon请求的用户数据。用户首次登录您的应用时,将看到您请求的数据列表并会询问是否批准。Login with Amazon目前支持三个范围:profile包含用户的名称、电子邮件地址和亚马逊账户ID,profile:user_id仅包含亚马逊账户ID,postal_code包含用户的邮政编码。

    调用authorize的最佳方式为异步调用,因此您不必阻止UI线程或创建自己的工作线程。要异步调用authorize,需要将支持AuthorizationListener接口的对象作为最后一个参数进行传递:

    private AmazonAuthorizationManager mAuthManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAuthManager = new AmazonAuthorizationManager(this, Bundle.EMPTY);
        // 查找带有login_with_amazon ID的按钮
        // 安装单击处理程序
        mLoginButton = (Button) findViewById(R.id.login_with_amazon);
        mLoginButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mAuthManager.authorize(
                    new String []{"profile","postal_code"},
                    Bundle.EMPTY, new AuthorizeListener());
            }
        });
    }
    
  5. 创建 ProfileListenerProfileListener 是实现APIListener接口的类的名称,并处理getProfile调用的结果。APIListener包含两种方法,即onSuccessonError(由于无法取消getProfile调用,该方法不支持onCance)。onSuccess将收到包含个人资料数据的Bundle对象,onError将收到包含错误信息的AuthError对象。

    private class ProfileListener implements APIListener{
    
        /*getProfile成功完成。*/
        @Override
        public void onSuccess(Bundle response) {
        }
        /*尝试获取个人资料时发生错误。*/
        @Override
        public void onError(AuthError ae) {
        }
    }
    
  6. 为您的AuthorizeListener实现onSuccess。在onSuccess中,调用AmazonAuthorizationManager.getProfile来检索客户个人资料客户个人资料getProfileauthorize类似,使用异步侦听器接口。对于getProfile,该接口为APIListener,而不是AuthorizationListener

    /*授权已成功完成。*/
    @Override
    public void onSuccess(Bundle response) {
        mAuthManager.getProfile(new ProfileListener());
    }
    
  7. 为您的ProfileListener实现onSuccessonSuccess具有两项主任务,即检索Bundle响应中的个人资料数据,以及向UI传递数据。updateProfileData是一项假想功能,您的应用可用以实现显示个人资料的详细信息。setLoggedInState也是一项假想功能,用于显示用户已登录且拥有一种注销方式。要从Bundle中检索个人资料数据,需要使用AuthzConstants类中存储的名称。onSuccess批的BUNDLE_KEY.PROFILE批中包含个人资料数据。在个人资料批中,范围数据索引位于PROFILE_KEY.NAMEPROFILE_KEY.EMAILPROFILE_KEY.USER_IDPROFILE_KEY.POSTAL_CODE。如果请求范围为postal_code,则只显示PROFILE_KEY.POSTAL_CODE

    @Override
    public void onSuccess(Bundle response) {
        // 从Bundle中检索所需数据
        Bundle profileBundle = response.getBundle(
            AuthzConstants.BUNDLE_KEY.PROFILE.val);
        String name = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.NAME.val);
        String email = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.EMAIL.val);
        String account = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.USER_ID.val);
        String zipcode = profileBundle.getString(
            AuthzConstants.PROFILE_KEY.POSTAL_CODE.val);
    
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateProfileData(name, email, account, zipcode);
            }
        });
    }
    
  8. 为您的ProfileListener实现onErroronError中的AuthError对象包含错误的详细信息。

    /* 尝试获取个人资料时发生错误。*/
    @Override
    public void onError(AuthError ae) {
        /*重试并提示用户发生错误*/
    }
    
  9. 为您的AuthorizeListener实现onError

    /*尝试授权应用时发生错误。*/
    @Override
    public void onError(AuthError ae) {
       /*提示用户发生错误*/
    }
    
  10. 为您的AuthorizeListener实现onCancel。由于授权流程会在网页浏览器(或网页视图)中向用户显示登录界面(可能也会显示同意界面同意界面),用户可以取消登录或导航离开该网页。如果用户明确取消登录流程,则调用onCancel。如果已调用onCancel,则需要重置您的UI。

    /*授权未完成便已取消。*/
    @Override
    public void onCancel(Bundle cause) {
       /*将UI重新设置为随时登录状态*/
    }
    

检查首次登录的用户

如果用户登录并关闭您的应用,并在之后重新启动,应用仍然有权检索数据。用户不会自动注销。如果您的应用仍处于授权状态,可在启动时将用户显示为已登录。本部分介绍了如何使用getToken确定应用是否仍处于授权状态。

  1. 创建TokenListenerTokenListener实现APIListener接口并处理getToken调用的结果。APIListener包含两种方法,即onSuccessonError(由于无法取消getToken调用,该方法不支持onCance)。onSuccess将收到包含令牌数据的Bundle对象,onError将收到包含错误信息的AuthError对象。

    private class TokenListener implements APIListener{
    
        /*getToken成功完成。*/
        @Override
        public void onSuccess(Bundle response) {
        }
        /*尝试获取令牌时发生错误。*/
        @Override
        public void onError(AuthError ae) {
        }
    }
    
  2. Activity下的onStart方法中,调用getToken以查看应用是否仍处于授权状态。

    getToken将检索AmazonAuthorizationManager用于访问客户个人资料的原始访问令牌访问令牌。如果令牌值不为null,则应用仍在处于授权状态,可成功调用getProfile

    getToken的请求范围需要与authorize的调用范围相同。

    getToken支持与getProfile相同的异步调用,因此无需阻止UI线程或创建您自己的工作线程。要异步调用getToken异步,需要将支持APIListener接口的对象作为最后一个参数进行传递。

    @Override
    protected void onStart(){
        super.onStart();
        mAuthManager.getToken(new String []{"profile","postal_code"}, new TokenListener());
    }
    
  3. 为您的TokenListener实现onSuccessonSuccess有两项任务:从Bundle中检索令牌;如果令牌有效,则调用getProfile。要从Bundle中检索令牌数据,需要使用AuthzConstants类中存储的名称。onSuccess批的BUNDLE_KEY.TOKEN值中包含令牌数据。如果该值不为空,此示例将使用上文声明的同一侦听器(见第7步与第8步)调用getProfile

    /* getToken成功完成。*/
    @Override
    public void onSuccess(Bundle response) {
        final String authzToken =
            response.getString(AuthzConstants.BUNDLE_KEY.TOKEN.val);
        if (!TextUtils.isEmpty(authzToken))
        {
            // 检索个人资料数据
            mAuthManager.getProfile(new ProfileListener());
        }
    }
    

清除授权状态并注销用户

clearAuthorizationState方法将清除AmazonAuthorizationManager本地数据存储中的用户授权数据。应用若要检索个人资料数据,必须令用户重新登录。使用此方法可注销用户,也可以对应用中的登录问题进行故障排除。

  1. 实现注销机制。您应在用户成功登录后提供注销机制,以便用户清除个人资料数据和以前的授权范围。这项机制可以是超链接,也可以是菜单项。本示例将为按钮创建onClick方法。
  2. 在注销处理程序中调用clearAuthorizationStateclearAuthorizationState将在本地存储中删除用户的授权数据(访问令牌和个人资料)。clearAuthorizationState只需要 APIListener返回成功或失败,除此之外,无需任何参数。
  3. 声明匿名的APIListener。匿名类是实现APIListener时声明新类的有力方法。 
  4. APIListener中实现onSuccessclearAuthorizationState成功后,应更新UI来移除用户参考,并提供用户可用来再次登录的登录机制。
  5. APIListener内实现onError。如果clearAuthorizationState返回错误,可让用户尝试再次注销。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /*省略之前的onCreate声明*/

    // 查找带有注销ID的按钮并安装单击处理程序
    mLogoutButton = (Button) findViewById(R.id.logout);
    mLogoutButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mAuthManager.clearAuthorizationState(new APIListener() {
                @Override
                public void onSuccess(Bundle results) {
                    // 设置退出状态UI
                }
                @Override
                public void onError(AuthError authError) {
                    // 记录错误
                }
            });
        }
    });
}

同步调用AmazonAuthorizationManager方法

有些 AmazonAuthorizationManager方法会返回Future对象。这可以用同步调用方法来代替侦听器的参数传递。Future不应用于UI线程。如果某个UI线程的阻止时间超过五秒,则将收到ANR(应用程序未响应)提示。在上述处理登录按钮和获取个人资料数据的示例中,用于AuthorizeListeneronSuccess方法与AmazonAuthorizationManager创建的工作线程一同进行调用。这意味着可以安全地使用该线程来同步调用getProfile。要作出同步调用,需要将getProfile的返回值分配给Future对象,并在此对象上调用get方法,直至方法完成。

Future.get返回的Bundle对象中会在SUCCESSERRORCANCEL中包含一项FUTURE_TYPE值。如果此方法已成功,则此值将包含个人资料数据的PROFILE_KEY值。例如:

/*授权已成功完成。*/
@Override
public void onSuccess(Bundle response) {
    Future<Bundle> future = mAuthManager.getProfile(null);
    Bundle result = future.get();
    // 查找调用是否成功,并检索个人资料
    Object future_type = result.get(AuthzConstants.BUNDLE_KEY.FUTURE.val);
    if (future_type == AuthzConstants.FUTURE_TYPE.SUCCESS)
    {
        String name = result.getString(
                AuthzConstants.PROFILE_KEY.NAME.val);
        String email = result.getString(
                AuthzConstants.PROFILE_KEY.EMAIL.val);
        String account = result.getString(
                AuthzConstants.PROFILE_KEY.USER_ID.val);
        String zipcode = result.getString(
                AuthzConstants.PROFILE_KEY.POSTAL_CODE.val);

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                updateProfileData(name, email, account, zipcode);
            }
        });
    }
    else if (future_type == AuthzConstants.FUTURE_TYPE.ERROR)
    {
        // 获取错误对象
        AuthError authError = AuthError.extractError(result);

        /*使用authError诊断错误*/
    }
    else if (future_type == AuthzConstants.FUTURE_TYPE.CANCEL)
    {
        /*用户在授权期间选择取消*/
    }
}