iOS内购丢单处理及实现

本文探讨了iOS应用内购过程中可能出现的丢单情况及其解决方案。重点介绍了如何利用transactionReceipt和applicationUsername属性来确保交易成功并能正确地关联到用户。

源地址:http://www.aiuxian.com/article/p-1803307.html


iOS内购实现及测试Check List
在内购使用中存在的几种丢单的情况
1.客户端获取到交易回调后-(void) purchasedTransaction: (SKPaymentTransaction *)transaction 后在交易成功的情况下,要拿到
transactionReceipt凭证,给后台验证的时候用户推出。(用户已经付钱但商家还没给商品)


    解决方法:在支付之前需要通过自己的服务器创建订单,在交易成功回调之后,立马将该订单和本次交易凭证存储到数据库中。在用户下次登录的时候,要首先验证该数据库中的交易凭证是否都经过后台验证过并成功给玩家商品。


2.这种情况是当交易回调有延时或者没有成功回调的时候,用户推出游戏。这个时候没有回调的transaction,无法将transactionReceipt和自己创建的订单绑定,也就是无法知道交易的用户。(感觉苹果这边有BUG,起码在交易对象中包含用户的数据)。这个时候,用户再下次登录的时候可以获取到transaction,但无法确定该交易的用户。


   解决方法:在下次购买的时候,从购买队列中获取交易集合,对已经成功购买,但没下载的不需要重复购买,终止本地交易,将其存入已购买数据库中。


  但还有一个问题,对于上次没有回调回来的交易,我们无法处理,以为虽然拿到了交易集合,但只凭借交易对象是无法知道用户信息的,也就无法充值。也就是说无法避免的丢单问题.................


找到解决办法了:ios7 苹果增加了一个属性applicationusername,SKMutablepayment的属性,所以用户在发起支付的时候可以指定用户的username及自己生成的订单,这样用户再下次得到回调的时候就知道,此交易是哪个订单发起的了进而完成交易。回调中获取username。


transaction.payment.applicationUsername(订单)将该属性连同transactionReceipt 传给后台做验证。完美解决问题 perfect 

实现iOS应用内买功能(In-App Purchase)通常涉及客户端(iOS)与服务器端(Java)的协作。以下是Java后台用于验证苹果内收据的核心代码示例。 ### iOS验证流程概述 1. 客户端发起内请求,苹果返回 `receipt-data`。 2. 客户端将 `receipt-data` 发送至 Java 后台服务。 3. Java 服务将 `receipt-data` 提交到苹果服务器进行验证(沙盒或生产环境)。 4. 苹果返回验证结果,包含订信息、状态码等。 5. 根据验证结果处理业务逻辑,如发放商品、记录交易等。 ### Java 验证内收据核心代码 ```java import com.alibaba.fastjson.JSONObject; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.io.IOException; public class IAPReceiptValidator { // 苹果验证地址(沙盒环境) private static final String SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt"; // 苹果验证地址(生产环境) private static final String PRODUCTION_URL = "https://buy.itunes.apple.com/verifyReceipt"; public JSONObject verifyReceipt(String receiptData, boolean isProduction) throws IOException { String url = isProduction ? PRODUCTION_URL : SANDBOX_URL; try (CloseableHttpClient client = HttpClients.createDefault()) { HttpPost post = new HttpPost(url); post.setHeader("Content-Type", "application/json"); JSONObject param = new JSONObject(); param.put("receipt-data", receiptData); StringEntity entity = new StringEntity(param.toJSONString()); post.setEntity(entity); try (CloseableHttpResponse response = client.execute(post)) { String responseBody = EntityUtils.toString(response.getEntity()); return JSONObject.parseObject(responseBody); } } } public void processReceipt(String receiptData, boolean isProduction) { try { JSONObject result = verifyReceipt(receiptData, isProduction); int status = result.getIntValue("status"); if (status == 0) { // 验证成功,处理逻辑 JSONObject receipt = result.getJSONObject("receipt"); String transactionId = receipt.getString("transaction_id"); String productId = receipt.getString("product_id"); // 这里可以执行订记录更新、发放道具等操作 System.out.println("内成功,交易ID:" + transactionId + ",商品ID:" + productId)[^1]; } else { // 验证失败,根据 status 做相应处理 System.out.println("内失败,状态码:" + status); } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 关键说明 - **receipt-data** 是苹果返回的 Base64 编码字符串,需要原样传给服务器[^1]。 - 苹果返回的状态码 `status == 0` 表示验证通过,其他值则需参考官方文档进行错误处理。 - 在实际部署中应根据业务需求生成唯一订号,并在客户端和服务端同步记录[^4]。 - 对于防止问题,建议在 App 启动时监听内完成事件并做补处理,相关逻辑应在 iOS实现[^3]。 ### 示例调用方式 ```java IAPReceiptValidator validator = new IAPReceiptValidator(); validator.processReceipt("MIIVDAYJKoZIhvcNAQcCoIIU/T...", false); // false 表示使用沙盒测试 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值