as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
设备
构建
测试
应用发布
相关资源
文档

集成和测试GetUserAgeData API

集成和测试GetUserAgeData API

本页包含示例代码,展示了如何从您的应用访问GetUserAgeData API以及如何使用响应。示例代码提供了一个测试实现,可用于在2026年1月1日之前即时模拟实际API的行为。要开发和测试GetUserAgeData API集成,请使用AmazonUserDataClient类中提供的非生产环境值,并结合使用可提供模拟数据的TestContentProvider类。

概览

要在您的应用中集成GetUserAgeData API,请按照以下高层步骤操作:

  1. 如果使用模拟数据进行测试,请在测试所用应用的Android清单中注册TestContentProvider类。
  2. 创建一个简单的Java对象来存放用户年龄数据。
  3. 创建一个帮助程序类,对提取自该Java对象的用户年龄数据进行建模。
  4. 实现AmazonUserDataClient类,以查询用户年龄数据。
  5. 从您的应用中调用AmazonUserDataClient类,您将在其中添加响应处理逻辑。

对于测试

在用于测试的AmazonUserDataClient类版本中:

  • AUTHORITY字符串设置为amzn_test_appstore
  • PATH字符串设置为/getUserAgeData?testOption=k(其中k为介于1到10之间的数字)

这些值为非生产环境值,无法访问亚马逊系统。

本页提供的TestContentProvider类的实现会根据GetUserAgeData API的实际响应结构返回模拟响应组合。要测试该功能,请在testOption 查询参数中传递一个介于1到10之间的值。TestContentProvider类会返回对应于testOption参数值的响应。如需查看提供的可用模拟响应的列表,请参阅测试数据响应

对于生产环境

对于生产环境,请忽略TestContentProvider类及其清单注册,并将您的应用指向生产版本GetUserAgeData API。

要使用生产版本GetUserAgeData API,请在AmazonUserDataClient类中执行以下操作:

  • AUTHORITY字符串设置为amzn_appstore
  • PATH字符串设置为/getUserAgeData

2026年1月1日起,GetUserAgeData API将开始返回实时响应。但是,如果在2026年1月1日之前调用,您将获得以下值之一:nullExceptionFEATURE_NOT_SUPPORTED

AmazonUserDataClient

以下为示例代码,展示了如何从您的应用调用模拟GetUserAgeData API。

已复制到剪贴板。

import android.content.Context;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.Optional;

public class AmazonUserDataClient {
    
    // 下面指定的这个端点单纯用于测试目的。
    // 用“amzn_appstore”替换生产版本/已上线API。
    public static final String AUTHORITY = "amzn_test_appstore";

    // 下面指定的这个PATH单纯用于测试目的。
    // 请使用一个介于1到10之间的值来修改查询参数testOption(例如从testOption=1到testOption=10),
    // 以获取TestContentProvider从getResponse1() 到getResponse10() 的相应输出。
    
    // 用“/getUserAgeData”替换生产版本/已上线API。
    private static final String PATH = "/getUserAgeData?testOption=1";

    private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + PATH);

    private Context context;

    public AmazonUserDataClient(Context context) {
        this.context = context;
    }

    public UserData getMyData(Context context) throws TimeoutException, InterruptedException, ExecutionException {
        CancellationSignal signal = new CancellationSignal();
        CompletableFuture<UserData> future = CompletableFuture.supplyAsync(() ->
            queryUserDataInternal(context, signal)
        );
        try {
            return future.get(5, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            signal.cancel();
            throw e;
        }
    }
    
    private UserData queryUserDataInternal(Context context, CancellationSignal signal) {
        try (Cursor cursor = context.getContentResolver().query(CONTENT_URI, null, null, null, null, signal)) {
            int ageLowerColumnIndex = cursor.getColumnIndex(UserAgeDataResponse.COLUMN_AGE_LOWER);
            int ageUpperColumnIndex = cursor.getColumnIndex(UserAgeDataResponse.COLUMN_AGE_UPPER);
            return Optional.ofNullable(cursor)
                .filter(Cursor::moveToFirst)
                .map(c -> new UserData(
                    c.getString(c.getColumnIndex(UserAgeDataResponse.COLUMN_RESPONSE_STATUS)),
                    c.getString(c.getColumnIndex(UserAgeDataResponse.COLUMN_USER_STATUS)),
                    !c.isNull(ageLowerColumnIndex) ? c.getInt(ageLowerColumnIndex) : null,
                    !c.isNull(ageUpperColumnIndex) ? c.getInt(ageUpperColumnIndex) : null,
                    c.getString(c.getColumnIndex(UserAgeDataResponse.COLUMN_USER_ID)),
                    c.getString(c.getColumnIndex(UserAgeDataResponse.COLUMN_MOST_RECENT_APPROVAL_DATE))
                ))
                .orElseThrow(() -> new RuntimeException("没有可用的用户数据"));
        } catch (Exception e) {
            throw new RuntimeException("查询失败", e);
        }
    }
}

要处理用户数据响应,请使用以下“简单Java对象”(POJO) 模型。有关更多详细信息,请参阅GetUserAgeData API

已复制到剪贴板。

public class UserData {
    private final String responseStatus;
    private final String userStatus;
    private final Integer ageLower;
    private final Integer ageUpper;
    private final String userId;
    private final String mostRecentApprovalDate;

    public UserData(String responseStatus, String userStatus, Integer ageLower, 
                   Integer ageUpper, String userId, String mostRecentApprovalDate) {
        this.responseStatus = responseStatus;
        this.userStatus = userStatus;
        this.ageLower = ageLower;
        this.ageUpper = ageUpper;
        this.userId = userId;
        this.mostRecentApprovalDate = mostRecentApprovalDate;
    }

    public String getResponseStatus() { return responseStatus; }
    public String getUserStatus() { return userStatus; }
    public Integer getAgeLower() { return ageLower; }
    public Integer getAgeUpper() { return ageUpper; }
    public String getUserId() { return userId; }
    public String getMostRecentApprovalDate() { return mostRecentApprovalDate; }
}

UserAgeDataResponse

AmazonUserDataClient类中,可以使用以下帮助程序类对所提取的用户年龄数据进行建模。AmazonUserDataClient部分的示例代码使用了该帮助程序类。

已复制到剪贴板。

public final class UserAgeDataResponse {
    private UserAgeDataResponse() {}
    public static final String COLUMN_RESPONSE_STATUS = "responseStatus";
    public static final String COLUMN_USER_STATUS = "userStatus";
    public static final String COLUMN_USER_ID = "userId";
    public static final String COLUMN_MOST_RECENT_APPROVAL_DATE = "mostRecentApprovalDate";
    public static final String COLUMN_AGE_LOWER = "ageLower";
    public static final String COLUMN_AGE_UPPER = "ageUpper";
}

TestContentProvider

以下实现是完全独立的,不会与亚马逊应用商店交互。该类仅用于早期开发、单元测试或测试目的。它的预期用途既不是全栈集成测试,也不是用于生产环境。

通过实现TestContentProvider类,您可以模拟实际GetUserAgeData API的行为。在新应用、测试应用中,或是在实际应用中作为测试逻辑时,请使用TestContentProvider类来获取模拟响应。

有关GetUserAgeData API响应的详细信息,请参阅GetUserAgeData API

已复制到剪贴板。

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;

/**
 * 负责提供年龄信号的内容提供方。
 * 返回responseStatus、userStatus、ageLower、ageUpper、userId、mostRecentApprovalDate
 */
public class TestContentProvider extends ContentProvider {


    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        sUriMatcher.addURI(AmazonUserDataClient.AUTHORITY, "getUserAgeData", 1);
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        throw new UnsupportedOperationException("不支持insert");
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("不支持delete");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("不支持update");
    }

    @Override
    public final Cursor query(Uri uri, String[] projection, Bundle queryArgs, CancellationSignal cancellationSignal) {
        return query(uri, null, null, null, null, cancellationSignal);
    }

    @Override
    public final Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
        return query(uri, projection, selection, selectionArgs, sortOrder, null);
    }

    @Override
    public final Cursor query(final Uri uri, final String[] projection, final String selection,
                              final String[] selectionArgs, final String sortOrder, CancellationSignal cancellationSignal) {
        int match = sUriMatcher.match(uri);
        if (match != 1) {
            throw new IllegalArgumentException("未知URI:" + uri);
        }

        String param1 = uri.getQueryParameter("testOption");
        if (param1 == null) {
            throw new IllegalArgumentException("需要testOption参数");
        }

        int option;
        try {
            option = Integer.parseInt(param1);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("testOption必须为有效的整数");
        }

        if (option < 1 || option > 10) {
            throw new IllegalArgumentException("testOption必须介于1到10之间");
        }
        MatrixCursor cursor = createCursor();
        cursor.addRow(getResponse(option));
        return cursor;
    }

    private Object[] getResponse(int option) {
        switch (option) {
            case 2: return getResponse2();
            case 3: return getResponse3();
            case 4: return getResponse4();
            case 5: return getResponse5();
            case 6: return getResponse6();
            case 7: return getResponse7();
            case 8: return getResponse8();
            case 9: return getResponse9();
            case 10: return getResponse10();
        }
        return getResponse1();
    }

    private MatrixCursor createCursor() {
        return new MatrixCursor(new String[]{
                UserAgeDataResponse.COLUMN_RESPONSE_STATUS,
                UserAgeDataResponse.COLUMN_USER_STATUS,
                UserAgeDataResponse.COLUMN_AGE_LOWER,
                UserAgeDataResponse.COLUMN_AGE_UPPER,
                UserAgeDataResponse.COLUMN_USER_ID,
                UserAgeDataResponse.COLUMN_MOST_RECENT_APPROVAL_DATE
        });
    }

    /***
     * 示例响应:适用于年满18周岁且年龄已得到确认的用户
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse1() {
        return new Object[]{ "SUCCESS", "VERIFIED", 18, null, null, null };
    }


    /***
     * 示例响应:在无法确定年龄确认/同意的情况下,适用于任何用户。
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse2() {
        return new Object[]{ "SUCCESS", "UNKNOWN", null, null, null, null };
    }


    /***
     * 响应:适用于年龄介于0到12周岁之间的用户。
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse3() {
        return new Object[]{ "SUCCESS", "SUPERVISED", 0, 12, "randomTestUserId1jC3QQeivdAytchaIVkWOjDiDlvz8xglhUcLwkbUHNQZKKw", "2023-07-01T00:00:00.008+02:00" };
    }


    /***
     * 响应:适用于年龄介于13到15周岁之间的用户。
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse4() {
        return new Object[]{ "SUCCESS", "SUPERVISED", 13, 15, "randomTestUserId1jC3QQeivdAytchaIVkWOjDiDlvz8pUxhUcLwkbUHNQZKKw", "2023-07-01T00:00:00.008Z" };
    }


    /***
     * 响应:适用于年龄介于16到17周岁之间的用户。
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse5() {
        return new Object[]{ "SUCCESS", "SUPERVISED", 16, 17, "randomTestUserId1jC3QQeivdhBcchaIVkWOjDiDlvz8pUxhUcLwkbUHNQZKKw", "2023-07-01T00:00:00.008Z" };
    }


    /***
     * 响应:适用于年龄确认法律不适用的所有一般情形。
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse6() {
        return new Object[]{ "SUCCESS", "", null, null, null, null };
    }


    /***
     * API返回APP_NOT_OWNED状态时的响应
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse7() {
        return new Object[]{ "APP_NOT_OWNED", "", null, null, null, null };
    }


    /***
     * API返回INTERNAL_TRANSIENT_ERROR状态时的响应
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse8() {
        return new Object[]{ "INTERNAL_TRANSIENT_ERROR", "", null, null, null, null };
    }


    /***
     * API返回INTERNAL_ERROR状态时的响应
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse9() {
        return new Object[]{ "INTERNAL_ERROR", "", null, null, null, null };
    }


    /***
     * API返回FEATURE_NOT_SUPPORTED状态时的响应
     * 有关更多详细信息,请参阅API文档。
     */
    private static Object[] getResponse10() {
        return new Object[]{ "FEATURE_NOT_SUPPORTED", "", null, null, null, null };
    }
}

测试数据响应

下表列出了上一节写到的从TestContentProvider API返回的10个模拟响应。testOption是仅用于查询模拟用户数据的查询参数,可提供以下预定义响应。

testOption值 用例 响应数据
1 响应:适用于年满18周岁且年龄已得到确认的用户。
{
  "responseStatus": "SUCCESS",
  "userStatus": "VERIFIED",
  "ageLower": 18,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
2 响应:在无法确定年龄确认/同意的情况下,适用于任何用户。
{
  "responseStatus": "SUCCESS",
  "userStatus": "UNKNOWN",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
3 响应:适用于年龄介于0到12周岁(包括0周岁和12周岁)之间的用户。
{
  "responseStatus": "SUCCESS",
  "userStatus": "SUPERVISED",
  "ageLower": 0,
  "ageUpper": 12,
  "userId": "randomTestUserId1jC3QQeivdAytchaIVkWOjDiDlvz8xglhUcLwkbUHNQZKKw",
  "mostRecentApprovalDate": "2023-07-01T00:00:00.008+02:00"
}
4 响应:适用于年龄介于13到15周岁(包括13周岁和15周岁)之间的用户。
{
  "responseStatus": "SUCCESS",
  "userStatus": "SUPERVISED",
  "ageLower": 13,
  "ageUpper": 15,
  "userId": "randomTestUserId1jC3QQeivdAytchaIVkWOjDiDlvz8pUxhUcLwkbUHNQZKKw",
  "mostRecentApprovalDate": "2023-07-01T00:00:00.008Z"
}
5 响应:适用于年龄介于16到17周岁(包括16周岁和17周岁)之间的用户。
{
  "responseStatus": "SUCCESS",
  "userStatus": "SUPERVISED",
  "ageLower": 16,
  "ageUpper": 17,
  "userId": "randomTestUserId1jC3QQeivdhBcchaIVkWOjDiDlvz8pUxhUcLwkbUHNQZKKw",
  "mostRecentApprovalDate": "2023-07-01T00:00:00.008Z"
}
6 响应:适用于年龄确认法律不适用的所有情形。
{
  "responseStatus": "SUCCESS",
  "userStatus": "",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
7 响应:API返回APP_NOT_OWNED状态时。
{
  "responseStatus": "APP_NOT_OWNED",
  "userStatus": "",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
8 响应:API返回INTERNAL_TRANSIENT_ERROR状态时。
{
  "responseStatus": "INTERNAL_TRANSIENT_ERROR",
  "userStatus": "",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
9 响应:API返回INTERNAL_ERROR状态时。
{
  "responseStatus": "INTERNAL_ERROR",
  "userStatus": "",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}
10 响应:API返回FEATURE_NOT_SUPPORTED状态时。
{
  "responseStatus": "FEATURE_NOT_SUPPORTED",
  "userStatus": "",
  "ageLower": null,
  "ageUpper": null,
  "userId": null,
  "mostRecentApprovalDate": null
}

在您的Android清单中注册TestContentProvider类

要使用TestContentProvider类,必须在AndroidManifest.xml文件中注册该类。只有为您提供TestContentProvider API逻辑的应用(例如测试应用)才需要完成这一注册步骤。更改provider元素中的android:name属性,以匹配TestContentProvider类的完全限定类名。

<application
            android:name="{.MainApplication或您的应用}"
            android:label="测试应用">

        <!-- 测试内容提供方 -->
        <provider
                android:name="com.test_app.TestContentProvider"
                android:authorities="amzn_test_appstore"
                android:exported="true" />

</application>

在您的应用中访问亚马逊提供的用户数据

以下代码展示了如何获取通过AmazonUserDataClient类提供的用户数据。在您的应用中使用这段代码,您将在其中添加用户年龄确认状态和用户年龄范围的处理逻辑。

// // 从应用的调用位置开始。
UserData userData = new AmazonUserDataClient().getUserData(context);
// if("SUCCESS".equals(userData.getResponseStatus())) {
//     // 基于userStatus和年龄范围值的恰当逻辑。
//     // 有关更多详细信息,请参考API文档。
// }
// // 恰当地处理其他状态。

其他语言表示

这段代码仅仅是示例代码。如需了解完整的语法,请参考该语言或框架的官方文档。

React Native

// 直接使用React Native ContentResolver桥文件
const userData = await ContentResolver.query('content://amzn_appstore/getUserAgeData');

Flutter

// 使用平台通道
final userData = await platform.invokeMethod('queryContentProvider', {
'uri': 'content://amzn_appstore/getUserAgeData'
});

Last updated: 2025年11月6日