iOS连续订阅IAP自动续订服务端接入流程

news/2025/1/15 21:54:01/

业务逻辑

 注意:

  1. 同一Apple 账号生成续订订单的原始交易ID(original_transaction_id)一致

  2. 服务端处理交易过程 :要确定一个交易ID(transaction_id)只能完成一笔订单,处理完该交易的订单之后,该交易ID记录标识为处理完成状态

  3. 服务端可以通过用户购买凭证(receipt_data)查询用户所有交易记录 查询到的数据有in_app、latest_receipt_info、pending_renewal_info

  4. 连续订阅主要用到数据是latest_receipt_info,里面有所有的续订记录。

  5. 如果里面的交易有cancellation_date字段,说明该交易已经被退款。

  6. pending_renewal_info里面的auto_renew_status字段用于标识用户是否开通自动订阅;0:已关闭;1:已开通。

在接收 App Store的续订、取消、退款通知时,因为选择的版本2(version 2 notification)的通知,版本二通知是jwt编码实现。

所以需要解码,方法如下:

<?phpclass IapNotifyController extends Controller
{public function notify(Request $request){$post_data = $request->getContent();$data = json_decode($post_data,true);$data = $data['signedPayload'];$data = $this->verifyToken($data);$data['signedTransactionInfo'] = $this->verifyToken($data['data']['signedTransactionInfo']);$data['signedRenewalInfo'] = $this->verifyToken($data['data']['signedRenewalInfo']);if($data) {/*通知类型https://developer.apple.com/documentation/appstoreservernotifications/notificationtypeCONSUMPTION_REQUEST 表示客户针对消耗品内购发起退款申请DID_CHANGE_RENEWAL_PREF 对其订阅计划进行了更改 如果subtype是UPGRADE,则用户升级了他们的订阅;如果subtype是DOWNGRADE,则用户将其订阅降级或交叉分级DID_CHANGE_RENEWAL_STATUS 通知类型及其subtype指示用户对订阅续订状态进行了更改DID_FAIL_TO_RENEW 一种通知类型及其subtype指示订阅由于计费问题而未能续订DID_RENEW 一种通知类型,连同其subtype指示订阅成功续订EXPIRED 一种通知类型及其subtype指示订阅已过期GRACE_PERIOD_EXPIRED 表示计费宽限期已结束,无需续订,因此您可以关闭对服务或内容的访问OFFER_REDEEMED 一种通知类型,连同其subtype指示用户兑换了促销优惠或优惠代码。 subtype DID_RENEWPRICE_INCREASE 一种通知类型,连同其subtype指示系统已通知用户订阅价格上涨REFUND 表示 App Store 成功为消耗性应用内购买、非消耗性应用内购买、自动续订订阅或非续订订阅的交易退款REFUND_DECLINED 表示 App Store 拒绝了应用开发者发起的退款请求RENEWAL_EXTENDED 表示 App Store 延长了开发者要求的订阅续订日期REVOKE表示 用户有权通过家庭共享获得的应用内购买不再通过共享获得SUBSCRIBED 一种通知类型,连同其subtype指示用户订阅了产品1. 用户主动取消订阅notificationType:DID_CHANGE_RENEWAL_STATUS2. 用户取消订阅,又重新开通连续订阅notificationType: SUBSCRIBED  subtype: RESUBSCRIBE3. 用户首次开通订阅notificationType: SUBSCRIBED  subtype: INITIAL_BUY*/$notification_type = $data['notificationType'];$transactionData = $data['signedTransactionInfo'];$product_id = $transactionData['productId'];$sub_type = isset($data['subtype']) ? $data['subtype'] : '';$original_transaction_id = $transactionData['originalTransactionId'];  // //原始交易ID$transaction_id = $transactionData['transactionId'];  //  //交易的标识$expires_date = date('Y-m-d H:i:s',$transactionData['expiresDate']/1000);//todo 记录通知log//查询原始交易绑定的用户IDif (in_array($notification_type, ['DID_RENEW','SUBSCRIBED'])) {//开通成功以及续订成功处理交易}//用户退款处理交易if (in_array($notification_type, ['REFUND'])) {}//用户取消订阅或者订阅过期if (in_array($notification_type, ['EXPIRED','DID_FAIL_TO_RENEW'])|| ($notification_type == 'DID_CHANGE_RENEWAL_STATUS')) {$is_renew = 0;if(($notification_type == 'DID_CHANGE_RENEWAL_STATUS') && $sub_type == 'AUTO_RENEW_ENABLED'){//开通订阅成功}elseif (($notification_type == 'DID_CHANGE_RENEWAL_STATUS') && $sub_type == 'AUTO_RENEW_DISABLED'){//取消订阅成功}//更新用户订阅状态}}}/*** 验证token是否有效,默认验证exp,nbf,iat时间* @param string $Token 需要验证的token* @return bool|string*/public static function verifyToken($Token){$tokens = explode('.', $Token);if (count($tokens) != 3)return false;list($base64header, $base64payload) = $tokens;//获取jwt算法$base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);if (empty($base64decodeheader['alg']) || $base64decodeheader['alg'] != 'ES256')return false;$payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);return $payload;}/*** base64UrlEncode   https://jwt.io/  中base64UrlEncode编码实现* @param string $input 需要编码的字符串* @return string*/private static function base64UrlEncode($input){return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));}/*** base64UrlEncode  https://jwt.io/  中base64UrlEncode解码实现* @param string $input 需要解码的字符串* @return bool|string*/private static function base64UrlDecode($input){$remainder = strlen($input) % 4;if ($remainder) {$addlen = 4 - $remainder;$input .= str_repeat('=', $addlen);}return base64_decode(strtr($input, '-_', '+/'));}}

参考文章:IAP 自动续费后端接入指南_theCrucian的博客-CSDN博客

iOS自动续订订阅开发----验证收据和状态回调JSON解析 - 简书


http://www.ppmy.cn/news/748584.html

相关文章

iOS开发,自动续期订阅的坑

自动续期订阅相较于普通内购&#xff0c;需要一个共享密钥&#xff0c;这个共享密钥在申请内购时获得。秘钥用于向苹果服务器请求收据信息。 购买过程不再赘述。 购买成功后&#xff0c;自动续期订阅最大的问题在于购买成功后是否续期成功&#xff0c;和到期时间。 解决这个…

ios订阅_iOS订阅测试分步指南

ios订阅 Testing a subscription can be as challenging as developing it. In this article, we will go over the complete process of subscription testing. 测试订阅与开发订阅一样具有挑战性。 在本文中,我们将介绍订阅测试的完整过程。 Fist of all, to do any type o…

iOS 自动续期订阅 恢复购买

恢复购买 内购有4种&#xff1a;消耗型项目&#xff0c;非消耗型&#xff0c;自动续期订阅&#xff0c;非续期订阅。 其中”非消耗型“和”自动续期订阅“需要提供恢复购买的功能&#xff0c;例如创建一个恢复按钮&#xff0c;不然审核很可能会被拒绝。 //调起苹果内购恢复接…

ios自动订阅服务器,任何(早期)iOS自动续订订阅体验

kitschmaster.. 53 我让它在沙盒中运行,几乎上线了...... 应该使用服务器来验证收据. 在服务器上,您可以使用收据数据记录设备udid,因为收据始终是新生成的,并且它将在多个设备上运行,因为收据总是新生成的. 在设备上,不需要存储任何敏感数据,也不应该:) 每当应用程序出现时,应…

iOS 自动续期订阅,订阅升级降级、订阅时间、退收费处理

自动续期订阅群组设置概述 设置自动续期订阅与设置其他 App 内购买项目类型不同。每个自动续期订阅产品需创建为订阅群组的一部分并为其分配等级。您对订阅群组的设置将决 定顾客如何订阅您的内容或服务、如何在不同订阅间转换、何时计费&#xff0c;以及您的收益率。有关订阅业…

力扣 47. 全排列 II

题目来源&#xff1a;https://leetcode.cn/problems/permutations-ii/description/ C题解1&#xff1a;这道题需要有两个不同的数组来标记使用过的元素&#xff0c;一个存放同层使用过的元素&#xff0c;根据元素数值来判断&#xff0c;范围为[-10,10]&#xff0c;在同层更新即…

cleanmymac x怎么取消订阅

如果Mac 电脑经常卡机、死机、速度很慢&#xff0c;跳出“存储过满”等问题&#xff0c;那么就需要用到世界上最受欢迎的电脑清理软件之一CleanMyMac X&#xff0c;它提供免费试用版&#xff0c;会告诉您可以释放多少磁盘空间&#xff0c;使用更多功能的完整版更能优化和保护 M…

IOS内购自动续费订阅测试

一、IOS 内购类型 1、消耗型商品&#xff1a; 只可使用一次的产品&#xff0c;使用之后即失效&#xff0c;必须再次购买。 示例&#xff1a;抽奖券。 2、非消耗型商品&#xff1a; 只需购买一次&#xff0c;不会过期或随着使用而减少的产品。 示例&#xff1a;游戏 App 的赛道…