最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • PHP实现Apple和Google退款信息通知

    正文概述 转载于:掘金(BubbleTea)   2021-06-24   385

    退款的滥用

    针对退款,不同国家或地区会有不同的“无条件退款期限”,例如苹果

    • AppStore商店退款政策:
    • 在中国区AppStore的具体退款政策:一个ID有1次无条件退款条件,一年2次有条件退款,第3次退款会非常难。至于退款到账时间快为36小时,也有7-15个工作日退还。
    • 正是这些“漏洞”,所以出现专业的代充工作室,导致开发者坏账非常严重。特别是火爆的游戏代充和直播行业。

    退款的具体手段

    1. 利用淘宝店以代充打折的形式获取玩家的游戏账号,为玩家充值后申请退款。淘宝店获得充值金,玩家获得游戏商品,最终亏损的是游戏厂商。
    2. 收购消费过的App Store ID账号,收到的账号会被用来退款和直播打赏,主播可以自己刷火箭然后申请退款。

    针对海外支付,退款的方式主要是App Store和Google

    App Store

    • AppStore退款通知参考文档

    苹果会定期通知退款内容,当用户退款后苹果会调用配置的接口通知我们(被动接收)

    • 配置url
      1. 登录苹果后台 appstoreconnect.apple.com/
      2. 选择需要通知的app应用,点击侧边栏的综合->App信息
      3. 在AppStore服务器通知网址(URL)中配置我们的接口地址(必须为Https)
    苹果响应信息

    responsebody通知参数详细文档 从App Store在服务器通知中返回的是一条JSON数据的退款通知,例子:

    {
    	"notification_type": "REFUND",#触发通知的订阅事件。REFUND:退款
    	"environment": "PROD", #App Store生成收据的环境,可能是沙箱和生产环境
    	"latest_receipt": "",#不推荐使用。自2021年3月10日起,生产和沙箱环境中将不再提供此对象。
    	"latest_receipt_info": {},#不推荐使用。自2021年3月10日起,生产和沙箱环境中将不再提供此对象。
    	"unified_receipt": {
    		"status": 0,
    		"environment": "Production",
    		"latest_receipt_info": [{#最近100笔退款订单信息
    			"quantity": "1",
    			"product_id": "com.xxxxxx.xmios.60",
    			"transaction_id": "490022793443160", #苹果订单号
    			"purchase_date": "2021-04-01 18:04:09 Etc/GMT",
    			"purchase_date_ms": "1617300249000",
    			"purchase_date_pst": "2021-04-01 11:04:09 America/Los_Angeles",
    			"original_purchase_date": "2021-04-01 18:04:09 Etc/GMT",
    			"original_purchase_date_ms": "1617300249000",
    			"original_purchase_date_pst": "2021-04-01 11:04:09 America/Los_Angeles",
    			"is_trial_period": "false",
    			"original_transaction_id": "490000793443160",
    			"cancellation_date": "2021-04-02 16:24:42 Etc/GMT", #退款时间
    			"cancellation_date_ms": "1617380682000", #退款时间 精确到毫秒
    			"cancellation_date_pst": "2021-04-02 09:24:42 America/Los_Angeles",
    			"cancellation_reason": "1",
    			"in_app_ownership_type": "PURCHASED"
    		}],
    		"latest_receipt": "" #不推荐使用。自2021年3月10日起,生产和沙箱环境中将不再提供此对象。
    	},
    	"bid": "com.xxxxxx.xmios",
    	"bvrs": "2.20"
    }
    

    这里我主要关注两个字段

    1. cancellation_date(退款时间)
    2. transaction_id(苹果订单号)

    unified_receipt 存放着最近100笔退款订单信息,我们可以循环遍历数组,通过数组下的 transaction_id 从数据库中查到订单信息,结合 cancellation_date 保存到退款记录表。

    Google

    • Google退款通知参考文档

    需定期请求Google退款接口,获取退款数据(主动发起请求)

    • 获得访问权限

    想使用 Voided Purchases API,需要拥有查看财务信息的权限。可以使用 OAuth 客户端或服务帐号来提供授权。这里我使用的是服务帐号,在帐号中启用“查看财务报表”权限。

    1. 登录 Google Play 管理中心
    2. 点击服务帐号下的创建服务帐号,按照页面上的说明创建您的服务帐号。

    点击 add 创建密钥,创建JSON密钥,准备进行授权的API调用。 3. 在 Google Play 管理中心创建服务帐号后,点击完成。API权限会自动刷新。 4. 点击授予访问权,勾选财务数据(查看财务数据、订单和用户取消订阅时对调查问卷的书面回复)

    • 获得访问授权
      1. 创建一个JWT,这里我以php为例:
    class GoogleRefundCommand extends Command
    {
        protected $signature = 'google:refund {startTime?} {endTime?}';
    
        
        private $key =  "",//使用JSON里的密钥
     
        private $iss = ''; //服务帐户的电子邮件地址。
    
        private $sub = ''; //应用程序正在请求委派访问权限的用户的电子邮件地址。
    
        private $scope = 'https://www.googleapis.com/auth/androidpublisher';//以空格分隔的应用程序请求的权限列表。
    
        private $aud = 'https://oauth2.googleapis.com/token';//声明的预期目标的描述符。发出访问令牌请求时,此值始终为。https://oauth2.googleapis.com/token
    
        private $package_name = ['','',''];
    
        private $getTokenUrl = 'https://www.googleapis.com/androidpublisher/v3/applications/';
    
        private $getTokenMethod = '/purchases/voidedpurchases';
    
        private $client = "";
    
    
        public function __construct()
        {
            parent::__construct();
            $this->client = HttpAgent::getInstance();
        }
    
    
        private function base64url_encode($data)
        {
            return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
        }
    
    
        /**
         * 谷歌退款
         * 获取access_token 接口请求文档 https://developers.google.com/identity/protocols/oauth2/service-account
         * @return mixed
         */
        public function handle()
        {
            //只在线上执行
            if (config('app.env') != 'production') {
                Log::info('获取谷歌获取退款脚本执行时间:' . date('Y-m-d H:i:s'));
                return;
            }
            //头部
            $header = [
                'alg' => 'RS256', //生成signature的算法
                'typ' => 'JWT'    //类型
            ];
            $payload = ['iss' => $this->iss, 'sub' => $this->sub, 'scope' => $this->scope, 'aud' => $this->aud, 'iat' => time(), 'exp' => time() + 1800];
            //  {Base64url encoded JSON header}
            $jwtHeader = $this->base64url_encode(json_encode($header));
            //  {Base64url encoded JSON claim set}
            $jwtClaim = $this->base64url_encode(json_encode($payload));
            //  The base string for the signature: {Base64url encoded JSON header}.{Base64url encoded JSON claim set}
            openssl_sign($jwtHeader . "." . $jwtClaim, $jwtSig, $this->key, "sha256WithRSAEncryption");
            $jwtSign = $this->base64url_encode($jwtSig);
            //  {Base64url encoded JSON header}.{Base64url encoded JSON claim set}.{Base64url encoded signature}
            $jwtAssertion = $jwtHeader . "." . $jwtClaim . "." . $jwtSign;
            
            dd($jwtAssertion);
            // todo...
           $ret = $this->client->request('post', 'https://oauth2.googleapis.com/token', ['query' => [
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                'assertion' => $jwtAssertion,
            ]]);
        }
    }
    

    这里我们使用postman测试一下 1. 请求 oauth2.googleapis.com/token 接口 2.grant_type = urn:ietf:params:oauth:grant-type:jwt-bearer,assertion使用 $jwtAssertion 参数 PHP实现Apple和Google退款信息通知

    保存返回的授权令牌access_token 使用GET请求 https://www.gooyour_auth_tokengleapis.com/androidpublisher/v3/applications/your_package_name/purchases/voidedpurchases?access_token=

    PHP实现Apple和Google退款信息通知 startTime:您想在响应中看到的最早作废的购买交易的时间。默认情况下,startTime 设为 30 天以前。注意:这里的startTime是毫秒 maxResults:每个响应中出现的已作废购买交易的数量上限。默认情况下,此值为 1000。请注意,此参数的最大值也是 1000。 token: 之前响应中的继续令牌;可让您查看更多结果。

    Google响应信息

    Google响应信息文档

    {
      "tokenPagination": {
        "nextPageToken": "next_page_token"
      },
      "voidedPurchases": [
        {
          "kind": "androidpublisher#voidedPurchase",
          "purchaseToken": "some_purchase_token",
          "purchaseTimeMillis": "1468825200000",
          "voidedTimeMillis": "1469430000000",
          "orderId": "some_order_id",
          "voidedSource": "0",
          "voidedReason": "4"
        },
        {
          "kind": "androidpublisher#voidedPurchase",
          "purchaseToken": "some_other_purchase_token",
          "purchaseTimeMillis": "1468825100000",
          "voidedTimeMillis": "1470034800000",
          "orderId": "some_other_order_id",
          "voidedSource": "2",
          "voidedReason": "5"
        },
      ]
    }
    

    这里我主要关注两个字段 voidedTimeMillis(退款时间) orderId(Google订单号) voidedPurchases存放着maxResults条退款订单信息,如果结果数量超过了在 maxResults请求参数中指定的数量,响应就会包含一个 nextPageToken值,这里我写了一个递归函数判断 nextPageToken是否为空,非空则将该值传递给后续请求来查看更多结果。


    起源地下载网 » PHP实现Apple和Google退款信息通知

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元