前言 說起內購,其實挺令開發者厭煩的,原因呢,先不說漏單的問題,首先蘋果要扣除30%的銷售額哦,可恨不?(我覺得可恨),有些想辦法先隱藏掉第三方支付(支付寶、微信等),等項目上線了,再跳過內購使用第三方支付,emmmm.......這個方法確實不錯,但是如果被蘋果發現了,APP內虛擬產品調用第三方支 ...
前言
說起內購,其實挺令開發者厭煩的,原因呢,先不說漏單的問題,首先蘋果要扣除30%的銷售額哦,可恨不?(我覺得可恨),有些想辦法先隱藏掉第三方支付(支付寶、微信等),等項目上線了,再跳過內購使用第三方支付,emmmm.......這個方法確實不錯,但是如果被蘋果發現了,APP內虛擬產品調用第三方支付,那好吧,直接下架吧(或許沒這麼慘,但會慘不忍睹),不要說發現不了,會有人舉報哦(別問我怎麼知道的);其次就是漏單問題的處理,這一直是個問題,我的項目里雖然做了處理,但是還是會避免不了漏單的,只是把漏單的幾率降到了很小,以確保我們維護,給大家分享下內購及漏單的處理。
內購集成
內購集成並不難,這裡我用了一個Git上封裝好的(IAPHelper),自己封裝也簡單(不想造那麼多輪子了),封裝的話,建議結合單例封裝,充值驗證都在單例裡面進行;當然也可以不封裝直接就用的,這裡不多說了。
支付邏輯
1.臨時單號
首先根據內購商品ID(此商品ID是在蘋果後臺建好的內購商品)、用戶信息(後臺要求),傳給伺服器獲取一個臨時單號,然後先將該臨時單號保存到一個變數里。
///獲取充值臨時單號 - (void)iapGetTemOrderIdWithProductId:(NSString *)productId{ self.productId = productId; [SVProgressHUD showWithStatus:@"請稍後..." ]; NSString *urlString = @""; [HttpTools getHttpRequestURL:urlString RequestSuccess:^(id repoes, NSURLSessionDataTask *task) { [SVProgressHUD dismiss]; NSDictionary *dicTem = [HttpTools respoesToDic:repoes]; if ([dicTem[@"code"] integerValue] == 1) { ///保存臨時單號 self.temporaryOrderId = dicTem[@"data"]; ///發起內購支付 [self iapStartRecharge]; } else{ [SVProgressHUD showErrorWithStatus:dicTem[@"errmsg"]]; [self errorPost:nil]; } } RequestFaile:^(NSError *error) { [SVProgressHUD showErrorWithStatus:[HttpTools error:error]]; [self errorPost:nil]; }]; }
2.蘋果充值
通過商品ID調取蘋果內購支付,蘋果充值成功後,在返回成功的方法里,首先將上一步中的臨時單號、用戶信息(這裡我取userId)、蘋果充值成功返回的data,三個參數一起存入本地(我採用資料庫存儲)後,然後驗證伺服器充值(如果蘋果充值驗證失敗,不必做任何操作)。
///發起內購支付 - (void)iapStartRecharge{ [SVProgressHUD showWithStatus:@"請稍後..."]; NSSet* dataSet = [[NSSet alloc] initWithObjects:self.productId, nil]; [IAPShare sharedHelper].iap = [[IAPHelper alloc] initWithProductIdentifiers:dataSet]; // 請求商品信息 [[IAPShare sharedHelper].iap requestProductsWithCompletion:^(SKProductsRequest* request,SKProductsResponse* response){ if(response.products.count > 0 ) { SKProduct *product = response.products[0]; [[IAPShare sharedHelper].iap buyProduct:product onCompletion:^(SKPaymentTransaction* trans){ if(trans.error){ [SVProgressHUD showErrorWithStatus:trans.error.userInfo.allValues[0]]; [self errorPost:nil]; } else if(trans.transactionState == SKPaymentTransactionStatePurchased) { NSLog(@"*********內部支付成功*********"); ///將臨時單號存在本地【此處做返回信息保存(臨時單號、用戶信息、返回的data)】 ///去伺服器驗證充值 } else if(trans.transactionState == SKPaymentTransactionStateFailed) { NSLog(@"*********支付失敗*********"); if (trans.error.code == SKErrorPaymentCancelled) { } else if (trans.error.code == SKErrorClientInvalid) { } else if (trans.error.code == SKErrorPaymentInvalid) { } else if (trans.error.code == SKErrorPaymentNotAllowed) { } else if (trans.error.code == SKErrorStoreProductNotAvailable) { } else{ } [SVProgressHUD showErrorWithStatus:trans.error.userInfo.allValues[0]]; [self errorPost:nil]; } }]; }else{ // ..未獲取到商品 [SVProgressHUD showErrorWithStatus:@"暫未獲取到商品"]; [self errorPost:nil]; } }]; }
3.伺服器驗證充值(上一步成功後驗證)
在蘋果充值成功後,根據充值成功返回的數據data、臨時單號、用戶信息(後臺要求)去伺服器驗證充值,如果驗證成功,將上一步存在本地資料庫的數據(臨時單號、用戶信息(這裡我取userId)、蘋果充值成功返回的data)刪除;如果充值失敗,即為漏單,但是已經將驗證伺服器充值的數據存在了本地資料庫,可再次嘗試,或者稍候嘗試,根據自己的提示操作而定。
///向伺服器驗證進行充值 - (void)iapPayOValidData:(NSString *)strReceipt temOrder:(NSString *)temOrder{ ///驗證充值 [SVProgressHUD showWithStatus:@"正在為您充值..."]; NSString *urlSting = @""; ///post data【驗證參數】 NSMutableDictionary *dicPost = [NSMutableDictionary dictionary]; [HttpTools postHttpRequestURL:urlSting RequestPram:dicPost RequestSuccess:^(id respoes) { [SVProgressHUD dismiss]; NSDictionary *dicValid = [HttpTools respoesToDic:respoes]; if ([dicValid[@"code"] integerValue] == 1) {
///刪除本地存的驗證信息【臨時單號、用戶信息、蘋果支付成功返回的data】 } else{ [self errorPost:dicValid[@"errmsg"]]; } } RequestFaile:^(NSError *erro) { [SVProgressHUD dismiss]; [self errorPost:[HttpTools error:erro]]; }]; }
結束
至此,整個內購充值流程已完畢,以上傳遞的參數、存儲的參數,是根據伺服器後臺要求,可根據自己伺服器後臺商量,怎麼做更好,如果大家有更好的方案,希望能借鑒!謝謝!
最後還是要說說,不管怎麼做漏單處理,總會有幾個漏單的,但是幾率很小,而且還想說,什麼時候可以有辦法躲過這30%的抽成.......