您的位置:首页 > 移动开发

iOS游戏开发三:苹果内支付实现 In-app

2016-06-13 15:09 696 查看
iOS游戏开发三:苹果内支付实现 In-app

首先你必须熟悉内支付的流程,可以到网上搜搜看。

前几天因为需要做了个苹果的内支付,当中遇到了不少苦头,感觉网上的各种博客对内支付这一块都是点到即止,没有真真正正实现自己的需求。正所谓辛苦就有所得,通过东接西搬,终于内力小成,特与大家分享一下自己的经验。这里我假设你已经把商品的ID什么的都已经注册成功了,测试账号也有了。

下面直接贴代码了~~~~



[objc] view
plain copy

print?





//

// IAPHelperViewController.h

//

#import <UIKit/UIKit.h>

#import <StoreKit/StoreKit.h>

@interface IAPHelperViewController : UIViewController<SKProductsRequestDelegate,SKPaymentTransactionObserver>

{

NSString* kMyInAppIdentifier;

BOOL receiptValid;

UIActivityIndicatorView* spinner;

}

+ (IAPHelperViewController *) sharedIAPHelper;

- (void) requestProUpgradeProductData;

- (void) requestProductData;

- (void) buyGolds:(int)buyType;

- (BOOL) canInAppPayment;

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

- (void) purchasedTransaction:(SKPaymentTransaction *)transaction;

- (void) completeTransaction:(SKPaymentTransaction *)transaction;

- (void) failedTransaction:(SKPaymentTransaction *)transaction;

- (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;

- (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;

- (void) restoreTransaction:(SKPaymentTransaction *)transaction;

- (void) recordTransaction:(SKPaymentTransaction *)product;

- (void) verifyReceiptFromMyServer:(SKPaymentTransaction *)transaction;

@end



[objc] view
plain copy

print?





//

// IAPHelperViewController.m

//

#import "IAPHelperViewController.h"

#include "cocos2d.h"

using namespace cocos2d;

const static int IAP1p99 = flag1;//主要是标记用户点击了那个商品

const static int IAP2p99 = flag2;

const static int IAP3p99 = flag3;

const static int IAP4p99 = flag4;

const static int IAP5p99 = flag5;

#define MyServerURL @"your server address , not apple"

#define ProductOne @"product 1 id"

#define ProductThree @"....... 2 .."

#define ProductFive @"....... 3 .."

#define ProductFifteen @"....... 4 .."

#define ProductFifty @"...... 5 .."

#define MyFrint NSLog(@"\n%s %d\n",__FUNCTION__, __LINE__)

@interface IAPHelperViewController ()

@end

@implementation IAPHelperViewController

//定义单例变量

static IAPHelperViewController* singleton = nil;

//单例模式

+ (IAPHelperViewController *) sharedIAPHelper

{

MyFrint;

if (singleton == nil) {

singleton = [[IAPHelperViewController alloc] initWithNibName:nil bundle:nil];

}

return singleton;

}

//初始化 这里应该根据自己的情况初始化 我用的是C++写的界面 OC不鸟~~~~~~

- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

MyFrint;

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

receiptValid = NO;

}

return self;

}

//加载视图

- (void) viewDidLoad

{

MyFrint;

[super viewDidLoad];

self.view.backgroundColor = [UIColor orangeColor];

}

//请求升级数据

- (void) requestProUpgradeProductData

{

MyFrint;

NSSet* productIdentifiers = [NSSet setWithObjects:ProductOne, ProductThree, ProductFive, ProductFifteen, ProductFifty, nil nil];

SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];

request.delegate = self;

[request start];

}

//点击商品按钮

- (void) buyGolds:(int)buyType

{

MyFrint;//根据点击标记 找到对应的商品IDs

switch (buyType) {

case IAP1p99: { kMyInAppIdentifier = ProductOne; break; }

case IAP2p99: { kMyInAppIdentifier = ProductThree; break; }

case IAP3p99: { kMyInAppIdentifier = ProductFive; break; }

case IAP4p99: { kMyInAppIdentifier = ProductFifteen; break; }

case IAP5p99: { kMyInAppIdentifier = ProductFifty; break; }

default: break;

}

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

if ([self canInAppPayment]) {

NSLog(@"允许应用内支付");

//首先向AppStore请求恢复交易

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

} else {

NSLog(@"不允许应用内支付");

}

}

//判断是否可以应用内支付

- (BOOL) canInAppPayment

{

MyFrint;//你应该根据是否想让越狱的iOS设备允许内支付 

if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]){

NSLog(@"Jailbroken detected!");

return NO;

}

if ([SKPaymentQueue canMakePayments]) {

return YES;

} else {

return NO;

}

}

//输入正确的帐号后进入 (如果是测试 必须必须使用你注册的沙河账号和密码)

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentTransaction *)transaction

{

MyFrint;

[self requestProductData];

}

//请求购买的商品信息

- (void) requestProductData

{

MyFrint;

NSSet * set = [NSSet setWithObjects:kMyInAppIdentifier, nil nil];//可以添加多个商品ID

SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];

request.delegate = self;

[request start];

}

#pragma mark SKProductsRequestDelegate 请求协议 ----------------------------------------------------------

//收到产品信息

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

{

// NSArray *myProduct = response.products;

// NSLog(@"产品付费数量: %d", [myProduct count]);

// NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);

// SKPayment *payment = nil;

// // populate UI

// for(SKProduct *product in myProduct)

// {

// NSLog(@"\n\nproduct info");

// NSLog(@"SKProduct 描述信息%@", [product description]);

// NSLog(@"产品标题 %@" , product.localizedTitle);

// NSLog(@"产品描述信息: %@" , product.localizedDescription);

// NSLog(@"价格: %@" , product.price);

// NSLog(@"Product id: %@\n\n" , product.productIdentifier);

// payment = [SKPayment paymentWithProduct:product];

// }

MyFrint;

SKPayment* payment = [SKPayment paymentWithProduct:[response.products lastObject]];

NSLog(@"\nPayment:\n productIdentifier=%@, \nrequestData=%@, \nquanlity=%d, \n",payment.productIdentifier,[payment.requestData description],payment.quantity);

[[SKPaymentQueue defaultQueue] addPayment:payment];

[request release];//请求已经生效

}

//请求错误信息

- (void) request:(SKRequest *)request didFailWithError:(NSError *)error

{

MyFrint;

UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL)

message:[error localizedDescription]

delegate:nil

cancelButtonTitle:NSLocalizedString(@"Close",nil)

otherButtonTitles:nil];

[alerView show];

[alerView release];

[request release];//请求失效

}

- (void) purchasedTransaction:(SKPaymentTransaction *)transaction

{

MyFrint;

}

- (void) requestDidFinish:(SKRequest *)request

{

MyFrint;

}

//然后当用户输入正确的appStore帐号密码后进入(再次说明 如果是测试 必须是你注册的测试账号 不能使用真实的AppleID 否则后果~~~~)

//方法在新交易被创建或更新时都会被调用

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

{

MyFrint;

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

}

case SKPaymentTransactionStatePurchasing:

{//商品添加进列表

NSLog(@"商品添加进列表==");

break;

}

default:

break;

}

}

}

//玩家等待 这里我想加个转动条 但没成功OC不鸟呀

- (void) activityIndicatorRun

{

spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];

spinner.color = [UIColor whiteColor];

spinner.frame = CGRectMake(100, 180.0f, 137.0f, 137.0f);

[spinner startAnimating];

}

//玩家结束等待

- (void) activityIndicatorStop

{

[spinner stopAnimating];

}

//observer在用户成功购买后提供相应的product

- (void)completeTransaction:(SKPaymentTransaction *)transaction

{

MyFrint;

[self activityIndicatorRun];

[self verifyReceiptFromMyServer:transaction];//这个方法是内支付最重要的方法

[self activityIndicatorStop];

if (receiptValid) {

[self recordTransaction:transaction];

//提示服务器刷新数据 ---

CCNotificationCenter::sharedNotificationCenter()->postNotification(kGNetworkNotificationName_Shop_BuyCredit_Successed, NULL);

} else {

[self failedTransaction:transaction];

}

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

//处理还原购买 结束交易

- (void) restoreTransaction: (SKPaymentTransaction *)transaction

{

MyFrint;

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

//处理失败购买 结束交易

- (void) failedTransaction: (SKPaymentTransaction *)transaction

{

MyFrint;

if (transaction.error.code != SKErrorPaymentCancelled) {

NSLog(@"购买失败");

}

[objc] view
plain copy

print?





<span style="white-space:pre"> </span>//根据项目的实际运行情况看 下面的完全多余.

[objc] view
plain copy

print?





<pre code_snippet_id="105137" snippet_file_name="blog_20131209_2_9929406" name="code" class="objc"> //else {

// NSLog(@"用户取消购买");

//}



[objc] view
plain copy

print?





[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

//取消登陆帐号密码操作

- (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error

{

MyFrint;

}

//用户成功购买

- (void) recordTransaction:(SKPaymentTransaction *)product

{

MyFrint;

UIAlertView* view = [[UIAlertView alloc] initWithTitle:@"购买结果" message:@"购买成功" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil nil];

[view show];

[view release];

}

//向服务器请求验证

- (void) verifyReceiptFromMyServer:(SKPaymentTransaction *)transaction

{

MyFrint;

//初始化为合法

if ([transaction.payment.productIdentifier isEqualToString:kMyInAppIdentifier]) {

//base64 encode the receipt data for sending

if ([transaction.transactionReceipt base64Encoding] != nil) {

//将数据http post请求发送到我的服务器

//data=base64(json(post))

//字典内容

NSDictionary* postDict = [[NSDictionary alloc] initWithObjectsAndKeys:@"ios",@"mode",

@"verify",@"method",

[NSDictionary dictionaryWithObjectsAndKeys:[self base64Encode:transaction.transactionReceipt],@"receipt",@"YES",@"test", nil nil],@"params",

@"1136",@"uid", nil nil];

//字典转化为json数据

NSError* error = nil;

NSData* jsonData = [NSJSONSerialization dataWithJSONObject:postDict options:NSJSONWritingPrettyPrinted error:&error];

if([jsonData length]>0 && error == nil){

}else if([jsonData length] == 0 && error == nil){

NSLog(@"No data returned after serialization.");

receiptValid = NO;

}else if(error != nil){

NSLog(@"An error happened = %@",error);

receiptValid = NO;

}

//json数据base64

NSString* base64 = [self base64Encode:jsonData];

if ([base64 length]==0 || [base64 isEqualToString:@""]) {

NSLog(@"Base64 error");

receiptValid = NO;

}

NSURL* url = [NSURL URLWithString:MyServerURL];

NSMutableURLRequest* theRequest = [NSMutableURLRequest requestWithURL:url];

[theRequest setHTTPMethod:@"POST"];

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

[theRequest setHTTPBody:[[NSString stringWithFormat:@"data=%@", base64] dataUsingEncoding:NSUTF8StringEncoding]];

//发送同步请求 因为你将使用自己的服务器返回的数据来判断是否成功

NSURLResponse* response = [[NSURLResponse alloc] init];

NSError* myerror = [[NSError alloc] init];

NSMutableData* receiveData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&myerror];

//NSURLConnection* theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

//接收到服务器返回的数据

NSString *receiptStatus = [[NSString alloc] initWithBytes: [receiveData mutableBytes] length:[receiveData length] encoding:NSUTF8StringEncoding];

NSLog(@"\nreceiptStatus=%@",receiptStatus);

NSString* str = @"\"status\":0";

if ([receiptStatus length]==0 || [receiptStatus isEqualToString:@""]) {

receiptValid = NO;

}

if ([receiptStatus rangeOfString:str].location != NSNotFound) {

NSLog(@"Yes Yes Yes!!!");

receiptValid = YES;

} else {

receiptValid = NO;

}

[receiptStatus release];

[myerror release];

[response release];

[postDict release];

} else {

NSLog(@"当向服务器发送验证数据时出错!!!");

receiptValid = NO;

}

}

else

{

NSLog(@"无效的商品ID");

receiptValid = NO;

}

}

//将NSData64位编码

- (NSString*) base64Encode:(NSData *)theData

{

const uint8_t* input = (const uint8_t*)[theData bytes];

NSInteger length = [theData length];

static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];

uint8_t* output = (uint8_t*)data.mutableBytes;

NSInteger i;

for (i=0; i < length; i += 3) {

NSInteger value = 0;

NSInteger j;

for (j = i; j < (i + 3); j++) {

value <<= 8;

if (j < length) {

value |= (0xFF & input[j]);

}

}

NSInteger theIndex = (i / 3) * 4;

output[theIndex + 0] = table[(value >> 18) & 0x3F];

output[theIndex + 1] = table[(value >> 12) & 0x3F];

output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';

output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';

}

return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];

}

//收到内存警告释放资源

- (void) didReceiveMemoryWarning

{

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

//回收内存

-(void) dealloc

{

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听

[spinner release]; spinner = nil;

[super dealloc];

}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: