苹果内购,整体来说不好用,支付速度特别慢,虚拟物品还要分成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];
    }
}