IOS IAP内置付费

2025-11-05 13:07:36

1、创建APPID,就是唯一标识这个APP的identifer.

登录开发中心,https://developer.apple.com/devcenter/ios/index.action网站好像改版了,跟网上的教程都不一致),依次点击红框里的链接,选择右上角的+号,创建一个唯一的ID,一般是域名的倒写加上一些其他的东西,反正唯一就行了。这里取com.baidu.test

IOS IAP内置付费

IOS IAP内置付费

2、创建测试用的空APP,(就是没有实际的程序,只是用来测试内置付费的)

还是登录开发中心,如上1图,选择iTunes connect,登入。框1进去后是你所有的APP,框2帐号,测试帐号管理,框3是银行卡 税率等信息,这个务必要写完整。

IOS IAP内置付费

3、先说框3,你的银行信息必须是完整的,像下图那样。否则你在创建产品列表时,产品的种类就可能只有免费订阅,消耗品,非消耗品等是看不见的。

IOS IAP内置付费

4、框1 MYAPP。进去后顶上有个+号,就是新建APP,上面有提示,一步一步填写就行了,有些信息是不必要的,你可以save一下,看看有没有报错什么的。顶部会有一行链接,如图,我只填了price和inAPP purchase。inAPP purchase就是设置你的产品列表的地方,点开后如图,点击create,创建一个假的商品,也可以很多个,产品的ID必须是唯一的,可以用你的APPID+产品名什么的。这里假设是com.baidu.test.product1

IOS IAP内置付费

5、框2,用来创建沙盒测试帐号,选择下图红框,填入一个邮箱地址,随便编,还有密码,邮箱不需要验证的。这里假设是sahetester@qq.com 这一步做完,准备工作就做好了,然后就是编码了。

IOS IAP内置付费

6、先说一下IAP的大致流程,如图,首先你得先有一个在iTunes设置的产品列表,这样才知道向iTunes请求什么商品,这个列表可以硬编码,或者放到服务器上动态获取,然后拿着这个列表通过apple的API去请求产品,返回后显示到界面,用户操作发起一个购买请求,成功或失败会有相应的回调方法,成功的时候applestore会产生一个收据,这个收据可以反馈给服务器用来向store验证,然后就是服务器向玩家发放道具什么的。这里说的非常粗,详见代码。对于交易恢复restoreTransaction,我不是特别理解这个概念,网上找到一张图2,有更明白的欢迎指教。

刚搜了一下,有一条:

恢复交易信息(Transactions)当transaction被处理并从队列移除之后,正常情况下,程序就再也看不到它们了。 如果你的程序提供的是非消耗性的或是订阅类的商品,就必须提供restore的功能,使用户可以在其他设备上重新存储购买信息。

是不是说,如果这个商品是非消耗品,购买完成之后,再次拿着它的ID去请求它就请求不到了??????所以才需要恢复????

IOS IAP内置付费

IOS IAP内置付费

7、代码的编写需要导入StoreKit.framework,需要用到它的SKPayment,SKPaymentQueue,SKPaymentTransaction,SKPaymentTransactionObserver类。

8、假设我们已经有了一个产品列表:

NSSet *productIdentifiers = [NSSet setWithObjects:@"com.baidu.test.product1", nil];

2.我们用这个列表去向商店请求商品的具体信息,这个请求通过类

SKProductsRequest完成:

创建SKProductsRequest对象,

SKProductsRequest * _request=

[[[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers] autorelease];

创建后还不能立即请求,因为我们要回收结果,所以要实现一些的回调方法。在网上找了找,说是设置代理delegate,自己强行理解了下,这个delegate和java C#里的接口差不多,规定一套实现者必须执行的动作,我学objectC才第2天,理解的不好请指教。那么这个代理该怎么设置呢:

_request.delegate = self;咋一看的晕晕的,把自己设成代理,然后看了下所在类的声明:黑体部分应该就是所谓的代理了,它里面有一些方法必须实现,这些方法在合适的时机被回调。

@interface IAPHelper : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver> {

 @protected

    NSSet * _productIdentifiers;    

    NSArray * _products;

    NSMutableSet * _purchasedProducts;

    SKProductsRequest * _request;

}

然后是发送请求:[_request start];

整个方法是这样的:

- (void)requestProducts {

    

    self.request = [[[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers] autorelease];

    _request.delegate = self;//设置回调代理对象

    [_request start];//请求

    

}

回调方法:这里只实现了成功时的回调,如果请求不成功的,可以实现request:didFailWithError:

//请求成功的回调

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

    

    NSLog(@"Received products results...");   

    self.products = response.products;//接收列表

    self.request = nil;  //Null,释放内存

    //发送消息给界面,界面要接收消息,必须得先监听才可以。

    [[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:_products];    

}

9、假设我们成功取到了产品列表,那么接下列就是要显示到界面上了。显示代码就略过了。接下来要做的就是用户操作后发出购买请求:

因为产品的信息都在self.products中,用户点击后我们取出对应的产品ID,创建一个购买对象,放入队列中,关键代码如下:

//SKPayment对象

SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];

 //加载到队列中

  [[SKPaymentQueue defaultQueue] addPayment:payment];

剩下的事情由apple来完成,但是交易的状态还是要获取的,获取状态通过添加监视:监视最好在创建类实例,或者程序加载时就加上。

[[SKPaymentQueue defaultQueue] addTransactionObserver:参数];因为IAPHelper: NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>实现了SKPaymentTransactionObserver代理协议(就是实现了交易状态改变时的回调方法),所以『参数』应该设置为IAPHelper的实例。具体是哪个方法呢?

我只找到一个:

//当发生交易事务时回调该方法,该方法根据对应状态调用合适的方法

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

{

    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];

                NSLog(@"已经购买过该商品");

                

            default:

                break;

        }

    }

}

到这里基本上就算完了。

10、还有一个收据问题,只有交易状态是成功(SKPaymentTransactionStatePurchased或者恢复(SKPaymentTransactionStateRestored)时,才会产生收据

Receipt,他保存本次交易的详细内容,是transaction对象的一个属性。

怎么获取呢?网上找了半天,_iOS_6_1之前的版本,保存在

transaction.transactionReceipt.bytes,好像是2进制,得转码什么的,新版本通过NSBundle的一个方法appStoreReceiptURL来获取。

拿到2进制的收据经过base64编码之后就是向Appstore验证交易是不是真的生效了。沙盒的验证地址是"https://sandbox.itunes.apple.com/verifyReceipt";正式的验证地址是https://buy.itunes.apple.com/verifyReceipt,代码大致像这样:

NSString* receipt64 = [self encode64:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];

    NSLog(@"receipt64== %@",receipt64);

    

    /*本地验证

    NSString *URL=@"https://sandbox.itunes.apple.com/verifyReceipt";

    //https://buy.itunes.apple.com/verifyReceipt

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];// autorelease];

    [request setURL:[NSURL URLWithString:URL]];

    [request setHTTPMethod:@"POST"];

    //设置contentType

    [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    //设置Content-Length

    [request setValue:[NSString stringWithFormat:@"%d", [receipt64 length]] forHTTPHeaderField:@"Content-Length"];

    

    NSDictionary* body = [NSDictionary dictionaryWithObjectsAndKeys:receipt64, @"receipt-data", nil];

    

    SBJsonWriter* w = [SBJsonWriter new];

    [request setHTTPBody:[[w stringWithObject:body] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];

    

    NSHTTPURLResponse *urlResponse=nil;

    NSError *errorr=nil;

    NSData *receivedData = [NSURLConnection sendSynchronousRequest:request

                                                 returningResponse:&urlResponse

                                                             error:&errorr];

    

    //解析

    NSString *results=[[NSString alloc]initWithBytes:[receivedData bytes] length:[receivedData length] encoding:NSUTF8StringEncoding];

    NSLog(@"-Himi-  %@",results);

    NSDictionary*dic = [results JSONValue];

    

    if([[dic objectForKey:@"status"] intValue]==0){//注意,status=@"0" 是验证收据成功

       NSLog(@"valid ok");

    }

11、网上还说发起购买时最好先判断一些内置购买能不能用,通过

if([SKPaymentQueue canMakePayments])  

{  

    ...//Display a store to the user  

}  

else 

{  

    ...//Warn the user that purchases are disabled.  

12、还有就是我对于恢复交易的理解:restoreTransaction,如果你有一个商品是一次性的,玩家已经购买过,因为某种原因玩家的设备丢失了这个商品,这时候可以通过apple提供的API帮助玩家找回丢失的商品。具体流程是:

通过

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];发起恢复,

商品成功恢复会回调 paymentQueueRestoreCompletedTransactionsFinished方法,失败会回调paymentQueue:restoreCompletedTransactionsFailedWithError:方法。

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢