苹果内购,整体来说不好用,支付速度特别慢,虚拟物品还要分成30%,但是虚拟物品在IOS平台上必须用苹果内购,没办法,只能用了。注册流程就不说了,简单说下代码实现流程。
代码之前,请现在iTunes Connet操作,创建应用、创建商品、指定商品价格。注意事项:
- 1,Bundle ID一定不要搞错
- 2,商品分类(消耗品、不可消耗品、自动更新订阅品、非自动更新订阅品、免费订阅品)创建商品的时候一定要看清楚区别再创建。
- 3,产品id,(一般是字母、数字或下划线),购买商品就是要看产品id
- 4,设置税务和银行卡信息
以下是代码实现
1,确认用户是否允许苹果内购
//添加监听
- (void)viewDidLoad{
[super viewDidLoad];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
//检查权限 _productId 建议从服务器获取 不建议硬编码
- (void)buyProdution:(UIButton *)sender{
if ([SKPaymentQueue canMakePayments]) {
[self toBuy:_productId];
} else {
[self showMessage:@"用户禁止应用内付费购买"];
}
}
//结束之后移除监听
-(void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
2,发起购买
//查询用户购买的产品的信息
- (void)toBuy:(NSString *)productId {
NSArray *product = [[NSArray alloc] initWithObjects:productId, nil];
NSSet *set = [NSSet setWithArray:product];
SKProductsRequest * request = [[SKProductsRequest alloc]
initWithProductIdentifiers:set];
request.delegate = self;
[request start];
[self showHUD:@"正在购买,请稍后"];
}
//成功后的回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:
(SKProductsResponse *)response {
[self hideHUD];
NSArray *myProduct = response.products;
if (myProduct.count == 0) {
[self showMessage:@"无产品信息"];
return;
}
SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
//查询失败后的回调
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
[self hideHUD];
[self showHUD:@"查询失败"];
NSLog(@"%@",error);
}
3,购买后的回调
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)
transactions {
[self hideHUD];
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://交易完成
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed://交易失败
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored://已经购买过该商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing://商品添加进列表
[self showMessage:@"正在请求付费信息,请稍后"];
break;
default:
break;
}
}
}
4,失败、恢复等操作
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
if (transaction.error.code != SKErrorPaymentCancelled)
{
[self showHUD:@"用户取消交易"];
}else{
[self showHUD:@"购买失败,请重试"];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//购买失败 通知自己服务器
[self doRequest:@"failed"];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
NSLog(@"已经购买过该商品");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
//恢复购买 (非消耗品的时候 一定要有恢复购买)
-(void) paymentQueueRestoreCompletedTransactionsFinished:
(SKPaymentTransaction *)transaction{
[self doRequest:@"恢复数据"];
}
-(void) paymentQueue:(SKPaymentQueue *) paymentQueue
restoreCompletedTransactionsFailedWithError:(NSError *)error{
NSLog(@"error:%@", error);
}
4,购买成功
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
//获取购买凭证
NSData *receiptData = [NSData dataWithContentsOfURL:
[[NSBundle mainBundle] appStoreReceiptURL]];
NSString *receiptStr = [receiptData base64EncodedStringWithOptions:
NSDataBase64EncodingEndLineWithLineFeed];
//通知后台 结束购买
NSString *productid = transaction.payment.productIdentifier;
if ([productid length] > 0) {
[self doPostReceipt:receiptStr withIndex:0];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
常见掉单问题
苹果内购最常见问题,掉单。就是你在苹果付款成功,但是自己后台却不知道。我们的解决方法是,购买成功之后,本地记录凭证。通知后台,通知失败,再通知,往复三次。如果最终通知失败,可能因为网络等原因,凭证记录本地,下次启动app再往复通知,直至通知成功。通知成功之后,删掉本地凭证。当然后台也会做自己的判断
在说一下我们记录和删除凭证吧
4,记录删除凭证
//保存交易凭证
- (void)saveReceipt:(NSString *)receiptStr{
//沙盒/appleBuy/订单号.plist tradeNo是后台生成的订单号
NSString *savedPath = [NSString stringWithFormat:@"%@%@.plist",
AppleBuyFilePath,[appleBuyDic objectForKey:@"tradeNo"]];
if (appleBuyDic!=nil) {
NSDictionary *dic = @{
@"tradeNo":[appleBuyDic valueForKey:@"tradeNo"],
@"notifyUrl":[appleBuyDic valueForKey:@"notifyUrl"],
@"receipt":receiptStr
};
[dic writeToFile:savedPath atomically:YES];
}
}
//删除交易凭证
- (void)deleteReceipt:(NSString *)tradeNo{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *savedPath = [NSString stringWithFormat:@"%@%@.plist",
AppleBuyFilePath,tradeNo];
if ([fileManager fileExistsAtPath:savedPath])
{
[fileManager removeItemAtPath:savedPath error:nil];
}
}