1. 程式人生 > >Unity呼叫iOS原生內購

Unity呼叫iOS原生內購

Unity在5.x以後的版本,都附帶了各種平臺的IAP(內購),網上一搜Unity IAP,就一大堆如何如何接入的教程,據說還挺方便的。本人也是用Unity 5.x,也曾經用了一下Unity的IAP,那為何現在還要討論呼叫iOS原生的IAP呢?

在這裡不得不吐槽一下Unity的IAP,雖然它目的是更加方便的讓遊戲接入支付,但接入過程,感覺也不是那麼的順利的。可能本人水平問題,接入這東西整整花費了一週時間(伺服器+客戶端)。首先文件挺簡略的,另外,就是網上教程都是單機向,沒涉及伺服器驗證。

還有的是,IAP是整合到Service上的,也就是說,用Unity IAP就得開Service,就得實時聯網,倘若斷網什麼的,就會報一大堆的錯誤!即使是匯入了package的。。。當然對於電信的同學來說,應該不存在這問題,本人也是在電信環境下,工作的很好的。但最近換了行動網路,一直連不上Service,我不得不一些巨集把呼叫IAP的程式碼遮蔽掉。。。

說到匯入package,我簡直無力吐槽,它就不會給你分一下平臺,各種平臺的東西都導進來,我本來只想接iOS的,結果包裡面包含了啥安卓,Tizen,小米,亂七八糟。。。

還有的是,如果協同工作,一起工作的小夥伴,還必須加入專案的組織,這對於獨立開發者來說,挺不方便的。

鑑於以上種種槽點,我把Unity IAP怒刪了。。。重新接入iOS原生的IAP。可能是因為只有老版本的Unity,才需要用原生的。文章也挺少的了。只有以下兩篇文章:

https://www.cnblogs.com/weiqiangwaideshijie/p/9103407.html

https://blog.csdn.net/dingxiaowei2013/article/details/52988354

上面兩篇文章寫的兩位大兄弟,其實程式碼差不多了,我也抄了大部分。實際除錯過程中,發現不少問題,首先程式碼有點不簡潔,另外就是支付回執處理有問題。這裡把我的貼出來分享一下。(程式碼是通的,Unity部分涉及到許多遊戲邏輯,就不貼了。)

IAPUnity.m

#import "IAPManager.h"

#import <Foundation/Foundation.h>

 

#if defined(__cplusplus)

extern "C" {

#endif

 

// 判定商品是否有效

bool IsProductAvailable(){

return [[IAPManager shareInstance] CanMakePayment];

}

 

// 請求獲得商品資訊

void RequestProductInfo(char* p){

NSString* list = [NSString stringWithUTF8String:p];

[[IAPManager shareInstance] requestProductData:list];

}

 

// 購買商品

void BuyProduct(char* p){

[[IAPManager shareInstance] buyRequest:[NSString stringWithUTF8String:p]];

}

// 處理一些未完成支付

void HandlePaymentQueue(){

[[IAPManager shareInstance] handlePaymentQueue];

}

 

#if defined(__cplusplus)

}

#endif

 

這裡面的函式,主要是供Unity呼叫的。購買商品調BuyProduct就可以了。注意的是,調BuyProduct之前最好調一下 HandlePaymentQueue,用來關閉一些未完成訂單,以免購買相同的商品的時候,蘋果彈出說商品已購買,需要恢復之類的提示。RequestProductInfo 其實這個是用來做驗證用的了,調不調也行。

 

IAPManager.h

#import <Foundation/Foundation.h>

#import <StoreKit/StoreKit.h>

 

@interface IAPManager : NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver>{

SKProduct *proUpgradeProduct;

SKProductsRequest *productsRequest;

}

 

+(id)shareInstance;

-(void)attachObserver;

-(BOOL)CanMakePayment;

-(void)requestProductData:(NSString *)productIdentifiers;

-(void)buyRequest:(NSString *)productIdentifier;

-(void)handlePaymentQueue;

-(NSString*) transactionInfo:(SKPaymentTransaction*)transaction;

 

@end

 

這個只是一個頭檔案。

 

IAPManager.m

 

#import "IAPManager.h"

 

static IAPManager* instance = nil;

 

@implementation IAPManager

 

+(id)shareInstance{

if (instance == nil){

instance = [[[self class] alloc] init];

[instance attachObserver];

}

return instance;

}

 

// 處理一些未完成的支付

-(void)handlePaymentQueue{

NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;

if (transactions.count > 0) {

// NSLog(@"transactions.count = %lu", (unsigned long)transactions.count);

for(SKPaymentTransaction* transaction in transactions){

if (transaction.transactionState == SKPaymentTransactionStatePurchased){

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

}

}

}

 

-(void) attachObserver{

NSLog(@"attachObserver");

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

 

-(BOOL) CanMakePayment{

return [SKPaymentQueue canMakePayments];

}

 

-(void) requestProductData:(NSString* )productIdentifiers{

NSArray* idArray = [productIdentifiers componentsSeparatedByString:@"\t"];

NSSet* idSet = [NSSet setWithArray:idArray];

[self sendRequest:idSet];

}

 

-(void) sendRequest:(NSSet* )idSet{

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

request.delegate = self;

[request start];

}

 

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

NSArray* products = response.products;

 

for (SKProduct* p in products){

UnitySendMessage("xxx", "AddProduct", [[self productInfo:p] UTF8String]);

}

 

for (NSString* invalidProductId in response.invalidProductIdentifiers){

NSLog(@"Invalid product id: %@", invalidProductId);

}

 

// [request autorelease];

}

 

-(void) buyRequest:(NSString*)productIdentifier{

SKPayment* payment = [SKPayment paymentWithProductIdentifier:productIdentifier];

[[SKPaymentQueue defaultQueue] addPayment:payment];

}

 

-(NSString*) productInfo:(SKProduct*)product{

NSArray* info = [NSArray arrayWithObjects:product.localizedTitle,

product.localizedDescription,

product.price,

product.productIdentifier,

nil];

return [info componentsJoinedByString:@","];

}

 

// 處理支付佇列

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

break;

default:

break;

}

}

}

 

// 支付動作轉字串

-(NSString*) transactionInfo:(SKPaymentTransaction*)transaction{

NSArray* info = [NSArray arrayWithObjects:transaction.payment.productIdentifier,

transaction.transactionIdentifier,

[transaction.transactionReceipt base64Encoding],

nil];

return [info componentsJoinedByString:@","];

}

 

// 支付完成回撥

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

NSLog(@"Complete transaction: transactionIdentifier = %@\n", transaction.transactionIdentifier);

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

// 直接呼叫Unity

UnitySendMessage("xxxx",

"OnSucess",

[[self transactionInfo:transaction] UTF8String]);

}

 

// 支付失敗回撥

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

NSLog(@"Failed transaction: %@", transaction.transactionIdentifier);

 

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

NSLog(@"!Cancelled");

}

 

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

 

UnitySendMessage("xxxx", "OnFailed", "");

}

 

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

NSLog(@"Restore transaction: %@", transaction.transactionIdentifier);

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

 

@end

 

這裡面主要註冊一些Unity的回撥函式。xxx是對應Unity裡面繫結支付程式碼的某個GameObject的名字。

這個裡面