合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
本章节主要介绍接入华为应用内支付的客户端开发步骤,以帮助您快速了解华为应用内支付提供的客户端接口及其使用方法。
在使用应用内支付之前,您的应用需要向HMS Core(APK)发送isEnvReady请求,以此判断用户当前登录的华为帐号所在的服务地是否在华为IAP支持结算的国家/地区中。
如果您的应用未接入华为帐号的登录接口,您可以通过该接口完成登录操作。
开发步骤如下:
发起isEnvReady请求,并设置两个回调监听来接收接口请求的结果。
当返回帐号未登录(OrderStatusCode.ORDER_HWID_NOT_LOGIN)时,可使用IapApiException对象的getStatus方法获取到一个Status对象,然后通过Status对象的startResolutionForResult方法拉起华为帐号登录页面,此后在Activity的onActivityResult方法中获取结果信息。从onActivityResult返回的Intent对象中解析出returnCode,当returnCode=OrderStatusCode.ORDER_STATE_SUCCESS时,则表示当前帐号所在服务地支持IAP,其他则表示此次请求有异常。
// 获取调用接口的Activity对象
final Activity activity = getActivity();
Task<IsEnvReadyResult> task = Iap.getIapClient(activity).isEnvReady();
task.addOnSuccessListener(new OnSuccessListener<IsEnvReadyResult>() {
@Override
public void onSuccess(IsEnvReadyResult result) {
// 获取接口请求的结果
String carrierId = result.getCarrierId();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
if (status.getStatusCode() == OrderStatusCode.ORDER_HWID_NOT_LOGIN) {
// 未登录帐号
if (status.hasResolution()) {
try {
// 6666是您自定义的常量
// 启动IAP返回的登录页面
status.startResolutionForResult(activity, 6666);
} catch (IntentSender.SendIntentException exp) {
}
}
} else if (status.getStatusCode() == OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED) {
// 用户当前登录的华为帐号所在的服务地不在华为IAP支持结算的国家/地区中
}
} else {
// 其他外部错误
}
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 6666) {
if (data != null) {
// 使用parseRespCodeFromIntent方法获取接口请求结果
int returnCode = IapClientHelper.parseRespCodeFromIntent(data);
}
}
}// 获取调用接口的Activity对象 val activity: Activity = getActivity() val task = Iap.getIapClient(activity).isEnvReady task.addOnSuccessListener { result -> // 获取接口请求的结果 val carrierId = result.carrierId }.addOnFailureListener { e -> if (e is IapApiException) { val apiException = e as IapApiException val status: Status = apiException.status if (status.getStatusCode() === OrderStatusCode.ORDER_HWID_NOT_LOGIN) { // 未登录帐号 if (status.hasResolution()) { try { // 6666是您自定义的常量 // 启动IAP返回的登录页面 status.startResolutionForResult(activity, 6666) } catch (exp: SendIntentException) { } } } else if (status.getStatusCode() === OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED) { // 用户当前登录的华为帐号所在的服务地不在华为IAP支持结算的国家/地区中 } } else { // 其他外部错误 } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == 6666) { if (data != null) { // 使用parseRespCodeFromIntent方法获取接口请求结果 val returnCode = IapClientHelper.parseRespCodeFromIntent(data) } } }
若您的应用提供PMS商品,则需要在华为AppGallery Connect网站上完成商品的配置。商品配置完成后,您需要在您的应用中使用obtainProductInfo接口来获取此类商品的详细信息。
开发步骤如下:
obtainProductInfo每次只能查询一种类型的商品。
List<String> productIdList = new ArrayList<>();
// 查询的商品必须是您在AppGallery Connect网站配置的商品
productIdList.add("ConsumeProduct1001");
ProductInfoReq req = new ProductInfoReq();
// priceType: 0:消耗型商品; 1:非消耗型商品; 2:订阅型商品
req.setPriceType(0);
req.setProductIds(productIdList);
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用obtainProductInfo接口获取AppGallery Connect网站配置的商品的详情信息
Task<ProductInfoResult> task = Iap.getIapClient(activity).obtainProductInfo(req);
task.addOnSuccessListener(new OnSuccessListener<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
// 获取接口请求成功时返回的商品详情信息
List<ProductInfo> productList = result.getProductInfoList();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});val productIdList: MutableList<String> = ArrayList()
// 查询的商品必须是您在AppGallery Connect网站配置的商品
productIdList.add("ConsumeProduct1001")
val req = ProductInfoReq()
// priceType: 0:消耗型商品; 1:非消耗型商品; 2:订阅型商品
req.setPriceType(0)
req.productIds = productIdList
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用obtainProductInfo接口获取AppGallery Connect网站配置的商品的详情信息
val task = Iap.getIapClient(activity).obtainProductInfo(req)
task.addOnSuccessListener { result ->
// 获取接口请求成功时返回的商品详情信息
val productList = result.getProductInfoList()
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}PMS商品指在华为AppGallery Connect网站上配置的商品,支持消耗型、非消耗型和订阅型商品。您的应用可通过createPurchaseIntent接口发起此类商品的购买请求。开发步骤如下:
// 构造一个PurchaseIntentReq对象
PurchaseIntentReq req = new PurchaseIntentReq();
// 通过createPurchaseIntent接口购买的商品必须是您在AppGallery Connect网站配置的商品
req.setProductId("CProduct1");
// priceType: 0:消耗型商品; 1:非消耗型商品; 2:订阅型商品
req.setPriceType(0);
req.setDeveloperPayload("test");
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用createPurchaseIntent接口创建托管商品订单
Task<PurchaseIntentResult> task = Iap.getIapClient(activity).createPurchaseIntent(req);
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
// 获取创建订单的结果
Status status = result.getStatus();
if (status.hasResolution()) {
try {
// 6666是您自定义的常量
// 启动IAP返回的收银台页面
status.startResolutionForResult(activity, 6666);
} catch (IntentSender.SendIntentException exp) {
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});// 构造一个PurchaseIntentReq对象
val req = PurchaseIntentReq()
// 通过createPurchaseIntent接口购买的商品必须是您在AppGallery Connect网站配置的商品。
req.setProductId("CProduct1")
// priceType: 0:消耗型商品; 1:非消耗型商品; 2:订阅型商品
req.setPriceType(0)
req.setDeveloperPayload("test")
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用createPurchaseIntent接口创建托管商品订单
val task = Iap.getIapClient(activity).createPurchaseIntent(req)
task.addOnSuccessListener { result ->
// 获取创建订单的结果
val status: Status = result.status
if (status.hasResolution()) {
try {
// 6666是您自定义的常量
// 启动IAP返回的收银台页面
status.startResolutionForResult(activity, 6666)
} catch (exp: SendIntentException) {
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}IAP SDK的InAppPurchaseData类可用于解析InAppPurchaseData字符串,您可使用该类构造一个InAppPurchaseData对象并从该对象中获取相关信息。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null");
return;
}
// 调用parsePurchaseResultInfoFromIntent方法解析支付结果数据
PurchaseResultInfo purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data);
switch(purchaseResultInfo.getReturnCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
// 用户取消
break;
case OrderStatusCode.ORDER_STATE_FAILED:
case OrderStatusCode.ORDER_STATE_DEFAULT_CODE:
case OrderStatusCode.ORDER_PRODUCT_OWNED:
// 检查是否存在未发货商品
break;
case OrderStatusCode.ORDER_STATE_SUCCESS:
// 支付成功
String inAppPurchaseData = purchaseResultInfo.getInAppPurchaseData();
String inAppPurchaseDataSignature = purchaseResultInfo.getInAppDataSignature();
// 使用您应用的IAP公钥验证签名
// 若验签成功,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性,验证一致后发货
// 若用户购买商品为消耗型商品,您需要在发货成功后调用consumeOwnedPurchase接口进行消耗
break;
default:
break;
}
}
}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null")
return
}
// 调用parsePurchaseResultInfoFromIntent方法解析支付结果数据
val purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data)
when (purchaseResultInfo.returnCode) {
OrderStatusCode.ORDER_STATE_CANCEL -> {
}
OrderStatusCode.ORDER_STATE_FAILED, OrderStatusCode.ORDER_PRODUCT_OWNED, OrderStatusCode.ORDER_STATE_DEFAULT_CODE -> {
}
OrderStatusCode.ORDER_STATE_SUCCESS -> {
// 支付成功
val inAppPurchaseData = purchaseResultInfo.inAppPurchaseData
val inAppPurchaseDataSignature = purchaseResultInfo.inAppDataSignature
}
else -> {
}
}
}
}非PMS商品支付仅支持消耗型商品和非消耗型商品。您的应用可通过createPurchaseIntentWithPrice接口发起购买请求。开发步骤如下:
Iap在IapApiException对象中携带了一个Status对象,可通过其startResolutionForResult方法拉起华为帐号登录页面,用户操作结果通过Activity的onActivityResult方法回调。onActivityResult方法返回的Intent对象中携带的returnCode字段即为登录的结果,您可使用parseRespCodeFromIntent方法获取该字段。
用户登录成功后,您需要重新调用createPurchaseIntentWithPrice接口才能完成支付。
可通过返回的IapApiException对象中的status拉起华为支付协议页面,处理方法同未登录场景。
若购买为消耗型商品,说明您的应用此前可能存在掉单的场景,需要触发补单操作,具体请参见消耗型商品的补单流程。若购买为非消耗型商品,则不能再次进行购买,请确认应用是否已经发货。
IAP SDK的InAppPurchaseData类可用于解析InAppPurchaseData字符串,您可使用该类构造一个InAppPurchaseData对象并从该对象中获取相关信息。
具体的示例代码如下:
// 构造PurchaseIntentWithPriceReq对象
PurchaseIntentWithPriceReq req = new PurchaseIntentWithPriceReq();
req.setCurrency("CNY");
req.setDeveloperPayload("test");
// priceType: 0: 消耗型; 1: 非消耗型
req.setPriceType(0);
req.setSdkChannel("1");
req.setProductName("test");
req.setAmount("1.00");
req.setProductId("ConsumableProduct1");
req.setServiceCatalog("XXX");
req.setCountry("CN");
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用createPurchaseIntentWithPrice接口
Task<PurchaseIntentResult> task = Iap.getIapClient(activity).createPurchaseIntentWithPrice(req);
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
// 获取支付结果
String paymentData = result.getPaymentData();
String paymentSignature = result.getPaymentSignature();
// 验证paymentData的签名
String publicKey = "XXX";
// CipherUtil为自定义类,需要自定义doCheck方法
if (CipherUtil.doCheck(paymentData, paymentSignature, publicKey)) {
// 如果成功,则启动请求返回的IAP收银台页面
Status status = result.getStatus();
if (status.hasResolution()) {
try {
status.startResolutionForResult(activity, 6666);
} catch (IntentSender.SendIntentException exp) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
switch (returnCode) {
case OrderStatusCode.ORDER_HWID_NOT_LOGIN:
case OrderStatusCode.ORDER_NOT_ACCEPT_AGREEMENT:
// 帐号未登录或用户不同意支付协议
Status status = apiException.getStatus();
if (status != null && status.hasResolution()) {
try {
status.startResolutionForResult(activity, 8888);
} catch (IntentSender.SendIntentException exp) {
}
}
break;
case OrderStatusCode.ORDER_PRODUCT_OWNED:
// 检查是否存在未交付的商品
break;
default:
break;
}
}
}
});
// 支付结果回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null");
return;
}
PurchaseResultInfo purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data);
switch(purchaseResultInfo.getReturnCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
// 用户取消支付
break;
case OrderStatusCode.ORDER_STATE_FAILED:
case OrderStatusCode.ORDER_STATE_DEFAULT_CODE:
case OrderStatusCode.ORDER_PRODUCT_OWNED:
// 检查是否存在未交付的商品
break;
case OrderStatusCode.ORDER_STATE_SUCCESS:
// 支付成功
String inAppPurchaseData = purchaseResultInfo.getInAppPurchaseData();
String inAppPurchaseDataSignature = purchaseResultInfo.getInAppDataSignature();
// 使用您应用的IAP公钥验证签名
// 若验签成功,必须校验InAppPurchaseData中的productId、price、currency等信息一致性,验证一致后发货
// 若用户购买商品为消耗型商品,您需要在发货成功后调用consumeOwnedPurchase接口进行消耗
break;
default:
break;
}
return;
}
if (requestCode == 8888) {
int returnCode = IapClientHelper.parseRespCodeFromIntent(data);
if (returnCode == OrderStatusCode.ORDER_STATE_SUCCESS) {
// 请求成功,需要再次发起createPurchaseIntentWithPrice请求
}
return;
}
}// 构造PurchaseIntentWithPriceReq对象
val req = PurchaseIntentWithPriceReq()
req.setCurrency("CNY")
req.setDeveloperPayload("test")
// priceType: 0: 消耗型; 1: 非消耗型
req.setPriceType(0)
req.setSdkChannel("1")
req.setProductName("test")
req.setAmount("1.00")
req.setProductId("ConsumableProduct1")
req.setServiceCatalog("XXX")
req.setCountry("CN")
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用createPurchaseIntentWithPrice接口
val task = Iap.getIapClient(activity).createPurchaseIntentWithPrice(req)
task.addOnSuccessListener { result ->
// 获取支付结果
val paymentData = result.getPaymentData()
val paymentSignature = result.getPaymentSignature()
// 验证paymentData的签名
val publicKey = "XXX"
// CipherUtil为自定义类,需要自定义doCheck方法
if (CipherUtil.doCheck(paymentData, paymentSignature, publicKey)) {
// 如果成功,则启动请求返回的IAP收银台页面
val status: Status = result.status
if (status.hasResolution()) {
try {
status.startResolutionForResult(activity, 6666)
} catch (exp: SendIntentException) {
}
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val returnCode = apiException.statusCode
when (returnCode) {
OrderStatusCode.ORDER_HWID_NOT_LOGIN, OrderStatusCode.ORDER_NOT_ACCEPT_AGREEMENT -> {
// 帐号未登录或用户不同意支付协议
val status: Status? = apiException.status
if (status != null && status.hasResolution()) {
try {
status.startResolutionForResult(activity, 8888)
} catch (exp: SendIntentException) {
}
}
}
OrderStatusCode.ORDER_PRODUCT_OWNED -> {
}
else -> {
}
}
}
}
// 支付结果回调
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == 6666) {
if (data == null) {
Log.e("onActivityResult", "data is null")
return
}
val purchaseResultInfo = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data)
when (purchaseResultInfo.returnCode) {
OrderStatusCode.ORDER_STATE_CANCEL -> {
}
OrderStatusCode.ORDER_STATE_FAILED, OrderStatusCode.ORDER_PRODUCT_OWNED, OrderStatusCode.ORDER_STATE_DEFAULT_CODE -> {
}
OrderStatusCode.ORDER_STATE_SUCCESS -> {
// 支付成功
val inAppPurchaseData = purchaseResultInfo.inAppPurchaseData
val inAppPurchaseDataSignature = purchaseResultInfo.inAppDataSignature
}
else -> {
}
}
return
}
if (requestCode == 8888) {
val returnCode = IapClientHelper.parseRespCodeFromIntent(data)
if (returnCode == OrderStatusCode.ORDER_STATE_SUCCESS) {
// 请求成功,需要再次发起createPurchaseIntentWithPrice请求
}
return
}
}用户完成一次支付之后,您需要根据购买数据InAppPurchaseData的purchaseState字段来判断订单是否已成功支付。若purchaseState为已支付(取值为0),您需要发放相应的商品或提供相应的服务,此后需要向华为IAP发送发货确认请求。
在成功发货并记录已发货的商品的purchaseToken之后,您的应用需要使用consumeOwnedPurchase接口消耗该商品,以此通知华为应用内支付服务器更新商品的发货状态。发送consumeOwnedPurchase请求时,请在请求参数中携带purchaseToken。应用成功执行消耗之后,华为应用内支付服务器会将相应商品重新设置为可购买状态,用户即可再次购买该商品。
// 构造ConsumeOwnedPurchaseReq对象
ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
String purchaseToken = "";
try {
// purchaseToken需从购买信息InAppPurchaseData中获取
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
} catch (JSONException e) {
}
req.setPurchaseToken(purchaseToken);
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 消耗型商品发货成功后,需调用consumeOwnedPurchase接口进行消耗
Task<ConsumeOwnedPurchaseResult> task = Iap.getIapClient(activity).consumeOwnedPurchase(req);
task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
@Override
public void onSuccess(ConsumeOwnedPurchaseResult result) {
// 获取接口请求结果
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});// 构造ConsumeOwnedPurchaseReq对象
val req = ConsumeOwnedPurchaseReq()
var purchaseToken = ""
try {
// purchaseToken需从购买信息InAppPurchaseData中获取
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
purchaseToken = inAppPurchaseDataBean.purchaseToken
} catch (e: JSONException) {
}
req.setPurchaseToken(purchaseToken)
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 消耗型商品发货成功后,需调用consumeOwnedPurchase接口进行消耗
val task = Iap.getIapClient(activity).consumeOwnedPurchase(req)
task.addOnSuccessListener {
// 获取接口请求结果
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}若您的应用为用户提供非消耗型商品,可在应用启动时通过obtainOwnedPurchases接口获取用户已购的非消耗型商品的购买信息,格式请参见InAppPurchaseData。若返回的购买信息列表不为空,请确认每个购买信息的purchaseState字段。若purchaseState为0,您需要提供相应的商品服务。
开发步骤如下:
IAP SDK的InAppPurchaseData类可用于解析InAppPurchaseData字符串,您可使用该类构造一个InAppPurchaseData对象并从该对象中获取相关信息。
// 构造一个OwnedPurchasesReq对象
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// priceType: 1:非消耗型商品
ownedPurchasesReq.setPriceType(1);
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用obtainOwnedPurchases接口
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// 获取接口请求结果
if (result != null && result.getInAppPurchaseDataList() != null) {
for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
String inAppSignature = result.getInAppSignature().get(i);
// 您需要使用您的应用的IAP公钥验证inAppPurchaseData的签名
// 如果验签成功,为避免资金损失,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性
// 验证一致后,请检查支付状态
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
int purchaseState = inAppPurchaseDataBean.getPurchaseState();
} catch (JSONException e) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});// 构造一个OwnedPurchasesReq对象
val ownedPurchasesReq = OwnedPurchasesReq()
// priceType: 1:非消耗型商品
ownedPurchasesReq.setPriceType(1)
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用obtainOwnedPurchases接口
val task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq)
task.addOnSuccessListener { result ->
// 获取接口请求结果
if (result != null && result.getInAppPurchaseDataList() != null) {
for (i in result.getInAppPurchaseDataList().indices) {
val inAppPurchaseData = result.getInAppPurchaseDataList()[i]
val inAppSignature = result.getInAppSignature()[i]
// 您需要使用您的应用的IAP公钥验证inAppPurchaseData的签名
// 如果验签成功,为避免资金损失,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性
// 验证一致后,请检查支付状态
try {
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
val purchaseState = inAppPurchaseDataBean.purchaseState
} catch (e: JSONException) {
}
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}在应用提供服务前,始终应该先判断用户已购的订阅型商品的状态,以决定是否应该提供对应的服务。
可通过下面的方式获取购买数据InAppPurchaseData。
对依赖当期续费情况的业务(比如:视频会员),若purchaseState为0且InApppurchaseData.subIsvalid为true,则始终应该为用户提供商品对应的服务。
开发步骤如下:
// 构造一个OwnedPurchasesReq对象
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// priceType: 2:订阅型商品
ownedPurchasesReq.setPriceType(2);
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用obtainOwnedPurchases接口
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// 获取接口请求结果
if (result != null && result.getInAppPurchaseDataList() != null) {
for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
String inAppSignature = result.getInAppSignature().get(i);
// 您需要使用您的应用的IAP公钥验证inAppPurchaseData的签名
// 如果验签成功,为避免资金损失,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性
// 验证一致后,请检查支付状态和订阅状态
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
int purchaseState = inAppPurchaseDataBean.getPurchaseState();
boolean isSubValid = inAppPurchaseDataBean.isSubValid();
} catch (JSONException e) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});// 构造一个OwnedPurchasesReq对象
val ownedPurchasesReq = OwnedPurchasesReq()
// priceType: 2:订阅型商品
ownedPurchasesReq.setPriceType(2)
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用obtainOwnedPurchases接口
val task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq)
task.addOnSuccessListener { result ->
// 获取接口请求结果
if (result != null && result.getInAppPurchaseDataList() != null) {
for (i in result.getInAppPurchaseDataList().indices) {
val inAppPurchaseData = result.getInAppPurchaseDataList()[i]
val inAppSignature = result.getInAppSignature()[i]
// 您需要使用您的应用的IAP公钥验证inAppPurchaseData的签名
// 如果验签成功,为避免资金损失,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性
// 验证一致后,请检查支付状态和订阅状态
try {
val inAppPurchaseDataBean = InAppPurchaseData(inAppPurchaseData)
val purchaseState = inAppPurchaseDataBean.purchaseState
val isSubValid = inAppPurchaseDataBean.isSubValid
} catch (e: JSONException) {
}
}
}
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val status: Status = apiException.status
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}对其他自定义业务,如果需要往期的续费情况(比如:杂志订阅),可以通过IapClient.obtainOwnedPurchaseRecord查询所有订阅型商品的收据,收据格式同InAppPurchaseData。
如果订阅型商品为已购状态,且商品有效时间段匹配上您合法的服务提供时间段,则应该提供商品对应的服务。
本质上,所有的订阅型商品都可以通过这种方式去判断是否应该提供服务。
对于消耗型商品,可使用obtainOwnedPurchaseRecord接口获取用户所有已消耗的商品信息。若提供订阅型商品,也可使用该接口获取用户的订阅收据。
// 构造一个OwnedPurchasesReq对象
OwnedPurchasesReq req = new OwnedPurchasesReq();
// priceType: 0:消耗型商品; 2:订阅型商品
req.setPriceType(0);
// 获取调用接口的Activity对象
final Activity activity = getActivity();
// 调用obtainOwnedPurchaseRecord接口
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchaseRecord(req);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// 获取接口请求的结果
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
int returnCode = apiException.getStatusCode();
} else {
// 其他外部错误
}
}
});// 构造一个OwnedPurchasesReq对象
val req = OwnedPurchasesReq()
// priceType: 0:消耗型商品; 2:订阅型商品
req.setPriceType(0)
// 获取调用接口的Activity对象
val activity: Activity = getActivity()
// 调用obtainOwnedPurchaseRecord接口
val task = Iap.getIapClient(activity).obtainOwnedPurchaseRecord(req)
task.addOnSuccessListener {
// 获取接口请求的结果
}.addOnFailureListener { e ->
if (e is IapApiException) {
val apiException = e as IapApiException
val returnCode = apiException.statusCode
} else {
// 其他外部错误
}
}