集成和测试GetUserAgeData API
本页包含示例代码,展示了如何从您的应用访问GetUserAgeData API以及如何使用响应。示例代码提供了一个测试实现,可用于在2026年1月1日之前即时模拟实际API的行为。要开发和测试GetUserAgeData API集成,请使用AmazonUserDataClient类中提供的非生产环境值,并结合使用可提供模拟数据的TestContentProvider类。
概览
要在您的应用中集成GetUserAgeData API,请按照以下高层步骤操作:
- 如果使用模拟数据进行测试,请在测试所用应用的Android清单中注册
TestContentProvider类。 - 创建一个简单的Java对象来存放用户年龄数据。
- 创建一个帮助程序类,对提取自该Java对象的用户年龄数据进行建模。
- 实现
AmazonUserDataClient类,以查询用户年龄数据。 - 从您的应用中调用
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日之前调用,您将获得以下值之一:null、Exception或FEATURE_NOT_SUPPORTED。
AmazonUserDataClient
以下为示例代码,展示了如何从您的应用调用模拟GetUserAgeData API。
AUTHORITY和PATH字符串更新为其生产环境值。
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类。以下实现是完全独立的,不会与亚马逊应用商店交互。该类仅用于早期开发、单元测试或测试目的。它的预期用途既不是全栈集成测试,也不是用于生产环境。
通过实现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周岁且年龄已得到确认的用户。 |
|
| 2 | 响应:在无法确定年龄确认/同意的情况下,适用于任何用户。 |
|
| 3 | 响应:适用于年龄介于0到12周岁(包括0周岁和12周岁)之间的用户。 |
|
| 4 | 响应:适用于年龄介于13到15周岁(包括13周岁和15周岁)之间的用户。 |
|
| 5 | 响应:适用于年龄介于16到17周岁(包括16周岁和17周岁)之间的用户。 |
|
| 6 | 响应:适用于年龄确认法律不适用的所有情形。 |
|
| 7 | 响应:API返回APP_NOT_OWNED状态时。 |
|
| 8 | 响应:API返回INTERNAL_TRANSIENT_ERROR状态时。 |
|
| 9 | 响应:API返回INTERNAL_ERROR状态时。 |
|
| 10 | 响应:API返回FEATURE_NOT_SUPPORTED状态时。 |
|
在您的Android清单中注册TestContentProvider类
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日

