這邊文章對(duì)于注冊流程和注意事項(xiàng)說的非常的詳細(xì)了但是里面還是有很多的坑,我自己封了一個(gè)類用于針對(duì)自己項(xiàng)目的使用地址如下
個(gè)人demo里面有個(gè)
屏幕快照 2019-03-25 上午10.28.18.png
里面需要注意的幾個(gè)點(diǎn):
#pragma mark - SKPaymentTransactionObserver // 監(jiān)聽購買結(jié)果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
[CXLoadingHud dismissHud];
for (SKPaymentTransaction *tran in transactions) {
//NSLog(@"%ld====",(long)tran.transactionState);
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased: //交易完成
//訂閱特殊處理
if(tran.originalTransaction){
//如果是自動(dòng)續(xù)費(fèi)的訂單originalTransaction會(huì)有內(nèi)容
NSLog(@"自動(dòng)續(xù)費(fèi)的訂單,originalTransaction = %@",tran.originalTransaction.transactionIdentifier);
//tran.originalTransaction.transactionIdentifier
//SKPaymentTransaction
[self completeTransaction:tran isAutomatically:YES];
//[self verifyPurchaseWithPaymentTransaction:tran isTestServer:NO];
}else{
//普通購買,以及 第一次購買 自動(dòng)訂閱 第一次自動(dòng)訂閱一定會(huì)走這個(gè)方法,如果訂購成功后一定會(huì)走上面的判斷
// NSLog(@"%@-------",tran.transactionIdentifier);
[self completeTransaction:tran isAutomatically:NO];
}
break;
case SKPaymentTransactionStatePurchasing://商品添加進(jìn)列表
#if DEBUG
//NSLog(@"%ld====",tran.error.code);
//NSLog(@"%@====",[[NSString alloc]initWithData:tran.payment.requestData encoding:NSUTF8StringEncoding]);
//[TDGAVirtualCurrency onChargeRequst:@"" iapId:@"" currencyAmount:0 currencyType:@"" virtualCurrencyAmount:0 paymentType:@""];
#endif
break;
case SKPaymentTransactionStateRestored://購買過
#if DEBUG
NSLog(@"已經(jīng)購買過商品");
#endif
// 消耗型不支持恢復(fù)購買
//[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
case SKPaymentTransactionStateFailed://交易失敗
如果tran.error 打印報(bào)錯(cuò)的話,沙盒測試的時(shí)候總是報(bào)無法連接itunes ,再確保你自己的前期準(zhǔn)備工作是ok的話,大概率都是蘋果自己的沙盒測試服務(wù)器自己gg了,經(jīng)歷過一次,坑爹的玩意,咋都找不出來,最后是蘋果自己的問題
NSLog(@"%@====",tran.error);
//SKErrorUnknown
[self failedTransaction:tran];
break;
default:
break;
}
}
}
// 交易結(jié)束
- (void)completeTransaction:(SKPaymentTransaction *)transaction isAutomatically:(BOOL)isAutomatically{
// Your application should implement these two methods.
// 票據(jù)的校驗(yàn)是保證內(nèi)購安全完成的非常關(guān)鍵的一步,一般有三種方式:
// 1、服務(wù)器驗(yàn)證,獲取票據(jù)信息后上傳至信任的服務(wù)器,由服務(wù)器完成與App Store的驗(yàn)證(提倡使用此方法,比較安全)我選擇的這種,但是會(huì)丟單,不過我暫時(shí)沒有處理,準(zhǔn)備用一個(gè)plist文件存儲(chǔ)下在app再次啟動(dòng)的時(shí)候請求下后臺(tái),不過這個(gè)只是減少了丟單率而且,蘋果的支付做得很垃圾
// 2、本地票據(jù)校驗(yàn)
// 3、本地App Store請求驗(yàn)證
// NSString * productIdentifier = transaction.payment.productIdentifier;
// NSString * receipt = [transaction.transactionReceipt base64EncodedString];
// if ([productIdentifier length] > 0) {
//
// }
NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
// 向自己的服務(wù)器驗(yàn)證購買憑證
//NSError *error;
//轉(zhuǎn)化為base64字符串
NSString *receiptString=[receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//網(wǎng)上轉(zhuǎn)換成base64后后臺(tái)一直解析不了需要如下處理除去receiptdata中的特殊字符
NSString *receipt1=[receiptString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
NSString *receipt2=[receipt1 stringByReplacingOccurrencesOfString:@"\r" withString:@""];
NSString *receipt3=[receipt2 stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
//最終將這個(gè)receipt3的發(fā)送給服務(wù)器去驗(yàn)證就沒問題啦!
//自動(dòng)訂閱(自動(dòng)續(xù)費(fèi)月卡)需要多加一個(gè)參數(shù)
NSString * product_id = transaction.payment.productIdentifier;
NSString * transaction_id = transaction.transactionIdentifier;
NSMutableDictionary * requestContents = [[NSMutableDictionary alloc]init];
#希望各位處理的時(shí)候能將 transaction_id 和 receipt都傳給后臺(tái)因?yàn)樘O果的receipt解析后里面有很多數(shù)據(jù),transaction_id能夠幫助后臺(tái)迅速定位最新的訂單,因?yàn)闇y試的時(shí)候發(fā)現(xiàn)receipt里面有個(gè)數(shù)組,一般是最后一條數(shù)據(jù)是最新的,但是坑爹的蘋果總是變,有時(shí)候是數(shù)組的第一條,所以transaction_id至關(guān)重要,而且在自動(dòng)訂閱和消耗性兩類中,自動(dòng)訂閱的 transaction_id2和transaction_id在第一次請求的時(shí)候是一致的,后面的話,要區(qū)分只能transaction_id所以這個(gè)傳給后臺(tái)至關(guān)重要
transaction_id2 = transaction.originalTransaction.transactionIdentifier;
NSString * transaction_id = transaction.transactionIdentifier;
[requestContents addEntriesFromDictionary:@{@"receipt": receipt3,@"password":secretKey,@"product_id":product_id,@"transaction_id":transaction_id,@"originalTransaction":transaction_id2}];
}else{
if (self.parmas.allKeys.count > 0) {
[requestContents addEntriesFromDictionary:@{@"receipt": receipt3,@"uid":self.parmas[@"uid"],@"amount":self.parmas[@"amount"],@"actorid":self.parmas[@"userRoleId"],@"server":self.parmas[@"serverId"],@"order_no":self.parmas[@"cpOrderNo"],@"password":secretKey,@"product_id":product_id,@"transaction_id":transaction_id}];
}
}
NSString * parameters = [self parameters:requestContents];
NSString * url = isAutomatically ? autoURL : consumptionURL;
NSURL *storeURL = [NSURL URLWithString:url];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:[parameters dataUsingEncoding:NSUTF8StringEncoding]];
[storeRequest setTimeoutInterval:30];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//服務(wù)器返回的responseObject是gbk編碼的字符串,通過gbk編碼轉(zhuǎn)碼就行了,轉(zhuǎn)碼方法如下:
NSString*gbkStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
//轉(zhuǎn)碼之后再轉(zhuǎn)utf8解析
NSDictionary * jsonDict = [NSJSONSerialization JSONObjectWithData:[gbkStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if (jsonDict.allKeys.count > 0) {
if ([[jsonDict objectForKey:@"code"]intValue] == 0) {
//[CXLoadingHud showHudWithText:@"購買成功" delay:2];
NSDictionary * dataDict = jsonDict[@"data"];
[[CXInformationCollect collectInfo]fb_mobile_purchase:dataDict[@"amount"] currency:@""];
[[CXInformationCollect collectInfo]af_purchase:@{@"amount":dataDict[@"amount"]}];
}else if ([[jsonDict objectForKey:@"code"]intValue] == 1){
[CXLoadingHud showHudWithText:@"服務(wù)器驗(yàn)簽失敗" delay:2];
}
}
}];
[dataTask resume];
//本地像蘋果app store驗(yàn)證,上面是像自己的服務(wù)器驗(yàn)證
//[self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
// 驗(yàn)證成功與否都注銷交易,否則會(huì)出現(xiàn)虛假憑證信息一直驗(yàn)證不通過,每次進(jìn)程序都得輸入蘋果賬號(hào)
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//[self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
}