### iOS 内购后端处理操作基本流程: 步骤1:App 下单,触发后台下单接口,**接口生成一个商户订单号并返回给 App。** 步骤2:App 拿到商户订单号之后调用 IPA 创建一个 IPA 交易,并且添加到支付队列。 然后 IAP 会调用 Apple ID 支付页面等待用户确认支付,IPA 和苹果自己的 IPA 服务器通讯,回调购买成功,并且把收据写入 App 沙盒。 步骤3: 然后 App 去沙盒获取收据并且下发到自己的服务器。 步骤4: **服务器去 IAP 服务器查询收据的有效性并且对应到某个订单号,把验证收据支付情况返回给 App。** 步骤5: App 根据返回的验证情况,来显示相应提示,然后 App 调用IAP 支付队列去结束该 IPA 交易。 <br><br> 根据以上流程,后端只需要做两个操作:一、生成订单号;二、验证收据 [收据验证下发数据-文档链接](https://developer.apple.com/documentation/appstorereceipts/requestbody) ``` //一、生成订单号 let outTradeId = 'wx' + Date.now().toString(); //二、验证收据 let receipt = req.body['receipt']; //服务端接收APP返回的凭证【一大串加密字符】 /*1.生产网址验证*/ let postData = JSON.stringify({"receipt-data": receipt}); request.post({ url: 'https://buy.itunes.apple.com/verifyReceipt', form: postData }, function (error, response, body) { if (!error && response.statusCode == 200) { let status = JSON.parse(body).status; if (status == 0) { //生产网址验证通过,进行商品开通的业务操作 ...... 业务代码...... //业务代码完成后,返回成功开通数据,至此,后端处理结束。 app.res.send('订单支付成功!'); } else if (status == 21007) { //沙盒再次验证 getSandbox(postData); } else { app.res.send('订单支付失败!'); } } else { app.res.send('订单支付失败!'); } }); /*2.沙盒验证*/ function getSandbox(datas) { request.post({ url: 'https://sandbox.itunes.apple.com/verifyReceipt', form: datas }, function (error, response, body) { if (!error && response.statusCode == 200) { let status = JSON.parse(body).status; if (status == 0) { //沙盒验证通过,生产网址验证通过,进行商品开通的业务操作 ...... 业务代码...... //业务代码完成后,返回成功开通数据,至此,后端处理结束。 app.res.send('订单支付成功!'); } else { app.res.send('订单支付失败!'); } } else { app.res.send('订单支付失败!'); } }); } ``` <br><br> 验证通过后苹果返回的 body 数据: ``` ~~~ { "status": 0, "environment": "Sandbox" "receipt": { "receipt_type": "ProductionSandbox", "adam_id": 0, "app_item_id": 0, "bundle_id": "com.BlueMobi.Phonics", "application_version": "1.5.0", "download_id": 0, "version_external_identifier": 0, "receipt_creation_date": "2018-06-28 14:08:26 Etc/GMT", "receipt_creation_date_ms": "1530194906000", "receipt_creation_date_pst": "2018-06-28 07:08:26 America/Los_Angeles", "request_date": "2018-08-05 04:50:58 Etc/GMT", "request_date_ms": "1533444658147", "request_date_pst": "2018-08-04 21:50:58 America/Los_Angeles", "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT", "original_purchase_date_ms": "1375340400000", "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles", "original_application_version": "1.0", "in_app": [ { "quantity": "1", "product_id": "*******", "transaction_id": "1000000404314890", //这个苹果的交易唯一标识符,但不是交易订单号(流水号),苹果不生成返回流水号,也不返回商品价格,所以对账很不友好! "original_transaction_id": "1000000404314890", "purchase_date": "2018-06-04 09:58:41 Etc/GMT", "purchase_date_ms": "1528106321000", "purchase_date_pst": "2018-06-04 02:58:41 America/Los_Angeles", "original_purchase_date": "2018-06-04 09:58:41 Etc/GMT", "original_purchase_date_ms": "1528106321000", "original_purchase_date_pst": "2018-06-04 02:58:41 America/Los_Angeles", "is_trial_period": "false" }, { "quantity": "1", "product_id": "*******", "transaction_id": "1000000404523773", "original_transaction_id": "1000000404523773", "purchase_date": "2018-06-05 02:21:26 Etc/GMT", "purchase_date_ms": "1528165286000", "purchase_date_pst": "2018-06-04 19:21:26 America/Los_Angeles", "original_purchase_date": "2018-06-05 02:21:26 Etc/GMT", "original_purchase_date_ms": "1528165286000", "original_purchase_date_pst": "2018-06-04 19:21:26 America/Los_Angeles", "is_trial_period": "false" } ] } } ~~~ ``` <br><br> **我如何得到购买的产品信息呢?** 注意返回数据的receipt.in\_app是一个数组,里面保存了所有未结束的交易,每一笔交易内,都会有一个product\_id用于自行映射相关的产品信息 <br><br>