"SDK接入(3)之iOS內支付(In App Purchase)接入" 繼整理了Android平臺的SDK接入過程。再來分享下iOS平臺的內支付(In App Purchase)接入,作為筆者在游戲開發中實際遇到的,覺得有必要分享下,同時也當作是對工作的總結,就放在該SDK接入系列文章中了。 作者 ...
SDK接入(3)之iOS內支付(In-App Purchase)接入
繼整理了Android平臺的SDK接入過程。再來分享下iOS平臺的內支付(In-App Purchase)接入,作為筆者在游戲開發中實際遇到的,覺得有必要分享下,同時也當作是對工作的總結,就放在該SDK接入系列文章中了。
作者:AlphaGL。版權所有,歡迎保留原文鏈接進行轉載 :)
作為SDK接入系列,同時也是Android平臺的SDK接入有:
SDK接入(2)之Android Google Play內支付(in-app Billing)接入
SDK接入(1)之Android Facebook SDK接入
這裡提一點,SDK的接入,官方文檔肯定最詳細,最準確,而且有時效性,接入流程變化,API修改更新,肯定最終都以官方的為準。那麼,蘋果官方內支付(IAP)接入文檔地址為:
iOS內支付流程
1.商品種類
在瞭解蘋果IAP內支付之前,有必要先瞭解下蘋果的商品種類。在蘋果In-App Purchase Programming Guide文檔上寫明瞭,商品種類分為如下幾種。接過GooglePlay支付的會發現,這點還是很相似的。
(1)消耗類商品
每次使用都須從新購買。
(2)非消耗類商品
購買一次即可。系統會自己購買狀態,且會同步所有用戶設備都一直保持可用狀態。
(3)自動再生訂閱
例如:一本書的章節內容。
(4)非自動再生訂閱
例如:一個航班表。
(5)免費訂閱
例如:報刊雜誌等。
消耗類與非消耗類商品的區別:
訂閱類商品的區別:
2.支付流程
對於IAP整個下單到支付過程,下圖很形象的說明瞭該步驟:
(1) 應用向伺服器發送請求,獲得一份產品列表。
(2) 伺服器返回包含商品標識符
的列表。
(3) 應用向App Store發送請求,得到商品的信息。
(4) App Store返回商品信息。
(5) 應用把返回的商品信息顯示在UI界面上。
(6) 用戶選擇某個商品。
(7) 應用向App Store發送支付請求。
(8) App Store處理支付請求並返回交易完成信息。
(9) 應用從信息中獲得數據,併發送至伺服器。
(10) 伺服器紀錄數據,併進行校驗。
(11) 伺服器將數據發給App Store來驗證該交易的有效性。
(12) App Store對收到的數據進行解析,返回該數據和說明其是否有效的標識。
(13) 伺服器讀取返回的數據,確定用戶購買的內容。
(14) 伺服器將購買的內容傳遞給程式。
3.配置商品
(1)打開iTunes Connect後臺
用開發者帳號,登錄iTunes Connect,企業級用戶需用主開發者帳號。
(2)配置iTunes Connect
在iTunes Connect後臺添加應用,並配置App內購買項目
,由於我們游戲中的鑽石、金幣等都屬於消耗型商品,因此,直接選的這個。需註意下配置的Bundle id須和項目plist中的Bundle id一致。並添加沙箱測試帳號。
註意:商品Id不可重覆,如果刪除某個商品,以後這個商品的ID也不可用,即使它已經被刪除了;另外類型也不能改,選錯了只能重新增加一個商品。
iOS內支付接入
1. 項目工程引入StoreKit.framework
2. 這裡推薦一個叫IAPHelper
的開源封裝,有效的封裝支付流程,進一步簡化了接入的效率。所以,下麵也是基於該項目進行的接入。IAPHelper
可自行Github搜索。
(1)InAppRageIAPHelper.m。在init中初始化商品id列表。
// 原文:http://www.cnblogs.com/alphagl/
#import "InAppRageIAPHelper.h"
#import "InAppRageIAPHelper.h"
@implementation InAppRageIAPHelper
@synthesize orderInfo = _orderInfo;
static InAppRageIAPHelper * _sharedHelper;
+ (InAppRageIAPHelper *) sharedHelper {
if (_sharedHelper != nil) {
return _sharedHelper;
}
_sharedHelper = [[InAppRageIAPHelper alloc] init];
return _sharedHelper;
}
- (void)dealloc
{
[_orderInfo release];
_orderInfo = nil;
[super dealloc];
}
- (id)init {
NSSet *productIdentifiers = [NSSet setWithObjects:
@"com.game.test.10001",
@"com.game.test.10002",
@"com.game.test.10003",
@"com.game.test.10004",
@"com.game.test.10005",
nil];
if ((self = [super initWithProductIdentifiers:productIdentifiers])) {
}
return self;
}
@end
(2)註冊本地通知。一般在應用啟動時,添加如下代碼:(productsLoaded、productPurchased、productPurchaseFailed分別對應支付過程中三種載入中,支付完成,支付失敗狀態回調,可根據實際情況作對應的處理)
// 原文:http://www.cnblogs.com/alphagl/
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(productsLoaded:) name:kProductsLoadedNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(productPurchased:) name:kProductPurchasedNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(productPurchaseFailed:) name:kProductPurchaseFailedNotification object:nil];
[[InAppRageIAPHelper sharedHelper]requestProducts];
(3)發起支付。
// 原文:http://www.cnblogs.com/alphagl/
if ([SKPaymentQueue canMakePayments]) {
[[InAppRageIAPHelper sharedHelper]buyProductIdentifier:[self getItemId] game_order:[self getOrderId]];
} else {
// 不允許程式內付費購買
}
(4)支付成功的回調。這裡將AppStore返回的數據,進行Base64加密,然後再發送給游戲伺服器進行校驗。同時,本地也會存儲返回的票據receipt,防止在發送給伺服器過程中請求失敗,造成的充值成功但不到賬的漏單
現象。
// 原文:http://www.cnblogs.com/alphagl/
-(NSData*)receiptWithTransation:(SKPaymentTransaction*) transcation {
NSData *receipt = nil;
if ([[NSBundle mainBundle]respondsToSelector:@selector(appStoreReceiptURL)]) {
NSURL *receiptUrl = [[NSBundle mainBundle]appStoreReceiptURL];
receipt = [NSData dataWithContentsOfURL:receiptUrl];
} else {
if ([transcation respondsToSelector:@selector(transactionReceipt)]) {
receipt = [transcation transactionReceipt];
}
}
return receipt;
}
-(void)productPurchased:(NSNotification*) notification {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
SKPaymentTransaction *transaction = (SKPaymentTransaction*)notification.object;
NSData *receipt = [self receiptWithTransation:transaction];
NSString *base64Receipt = [receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
[[InAppRageIAPHelper sharedHelper].orderInfo setObject:[NSString stringWithFormat:@"%@", base64Receipt] forKey:@"originReceipt"];
NSString *m_params = [self makeHttpParams:base64Receipt];
if (m_params != nil) {
[self saveReceipt:m_params];
[self postGameServer:[self getPayUrl] params:m_params];
}
}
(5)漏單檢測。下次,啟動時,會進行漏單檢測。若存在本地票據receipt,就向游戲伺服器發起請求。直到游戲伺服器返回成功,再刪除本地的票據receipt。
// 原文:http://www.cnblogs.com/alphagl/
NSUserDefaults *userDefalut = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *receiptDict = [NSMutableDictionary dictionaryWithDictionary:[userDefalut objectForKey:@"receipts"]];
NSEnumerator *enumerator = [receiptDict objectEnumerator];
for (NSObject *obj in enumerator) {
[self postGameServer:[self getPayUrl] params:[NSString stringWithFormat:@"orderdata=%@",obj]];
}
(6)由於,我們的校驗是放在伺服器進行的,所以,這裡就不進行過多的介紹了。簡單說下,App Store正式環境校驗地址是https://buy.itunes.apple.com/verifyReceipt ,測試環境校驗地址是:https://sandbox.itunes.apple.com/verifyReceipt。
iOS支付安全問題
對於某些越獄設備來說,如果校驗流程有漏洞的話,使用某些神器,就能繞過Appstore的付費流程,偽造訂單,達到免支付體驗各種付費功能。
其中列舉如下神器:
(1)ap cracker:越獄軟體可以截獲付費請求,並直接返回付費成功。
(2)iap free: 截獲付費請求的同時,還能截獲客戶端發起的驗證請求 ,返回驗證成功的數據 ,返回的數據和官方的數據並不是完全一樣,可以識別出來是否作弊,但是不保證永久有效。
因此,首先在支付成功之後,要將支付成功返回的票據發送給伺服器,在伺服器端作驗證,根據伺服器的驗證結果來做相應的處理。其次,本地對應偽造的票據進行過濾。
技術交流QQ群:528655025
作者:AlphaGL
出處:http://www.cnblogs.com/alphagl/
版權所有,歡迎保留原文鏈接進行轉載 :)