1.內購——應用內購買
我所說的內購——也可以說是應用內購買
大家都知道通過蘋果應用程序商店有三種主要賺錢的方式:
1.直接收費(與國內大部分用戶的消費習慣相悖,如果要收費,直接收高的,別收6塊錢)
2.廣告(降低用戶體驗 應用程序名稱帶Lite可以添加廣告)
3.內購
至於設計哪些賣錢?產品經理需要認真考慮和調研的。記錄用戶行為是可以幫助產品經理確認哪些收費!
所以要做好游戲,一定要研究心理,要研究哲學,哈哈。
2.內購的類別有哪幾種呢?
在游戲中我們經常用到的主要由分兩種:
非消耗品(Nonconsumable)買了就有,頭銜,功能
指的是在游戲中一次性購買並擁有永久訪問權的物品或服務。非消耗品物品可以被用戶再次下載,並且能夠在用戶的所有設備上使用
消耗品(Consumable),買了就用,用了就沒
專為支持可消耗的物品或服務設計的,消耗品購買不可被再次下載,根據其特點,消耗品不能在用戶的設備之間跨設備使用,除非自定義服務在用戶的賬號之間共享這些信息
3.添加內購功能
3.1在iTunes Connect中給自己的應用添加消耗品定義
3.2在iTunes Connect中給自己的應用添加定義的商品
3.3要使用內購,需要導入StoreKit框架
定義好的商品
#define kIAPBomb @"airplay.10bombs"
#define kIAPBullet @"airplay.laserBullet"
1. 實例化請求時,必須指定有效的identifiers集合,之所以如此處理,主要是為了確保提交的內購商品真的通過了蘋果的審批,處於可用狀態!
2. 要想獲取到准確的可用產品集合,需要通過代理方法實現
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
3. 越獄用戶無法測試內購,但是可以購買
1 @interface ITViewController () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
2 {
3 // 產品字典
4 NSMutableDictionary *_productDict;
5 }
復制代碼
1 - (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 [self requestProducts];
6
7 // 設置購買隊列的監聽器
8 [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
9 }
復制代碼
3.4.詢問蘋果的服務器能夠銷售哪些商品
復制代碼
#pragma mark 詢問蘋果的服務器能夠銷售哪些商品
- (void)requestProducts
{
// 能夠銷售的商品
NSSet *set = [[NSSet alloc] initWithObjects:kIAPBomb, kIAPBullet, nil];
// "異步"詢問蘋果能否銷售
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
// 啟動請求
[request start];
}
復制代碼
3.5.獲取詢問結果,成功采取操作把商品加入可售商品字典裡
復制代碼
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
if (_productDict == nil) {
_productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];
}
for (SKProduct *product in response.products) {
// 激活了對應的銷售操作按鈕,相當於商店的商品上架允許銷售
NSLog(@"%@", product.productIdentifier);
if ([product.productIdentifier isEqualToString:kIAPBullet]) {
_bulletButton.enabled = YES;
}
if ([product.productIdentifier isEqualToString:kIAPBomb]) {
_bombButton.enabled = YES;
}
// 填充商品字典
[_productDict setObject:product forKey:product.productIdentifier];
}
}
復制代碼
3.6.用戶決定購買商品
復制代碼
1 #pragma mark - 用戶決定購買商品
2 - (void)buyProduct:(SKProduct *)product
3 {
4 // 要購買產品(店員給用戶開了個小票)
5 SKPayment *payment = [SKPayment paymentWithProduct:product];
6
7 // // 設置購買隊列的監聽器
8 // [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
9
10 // 去收銀台排隊,准備購買(異步網絡)
11 [[SKPaymentQueue defaultQueue] addPayment:payment];
12 }
復制代碼
復制代碼
1 - (IBAction)purchaseProducts
2 {
3 [self buyProduct:_productDict[kIAPBullet]];
4 }
5
6 - (IBAction)purchaseBomb:(id)sender
7 {
8 [self buyProduct:_productDict[kIAPBomb]];
9 }
復制代碼
3.7.判斷購買狀態是否成功
復制代碼
#pragma mark - SKPaymentTransaction Observer
#pragma mark 購買隊列狀態變化
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
// 調試
for (SKPaymentTransaction *transaction in transactions) {
NSLog(@"隊列狀態變化 %@", transaction);
// 如果小票狀態是購買完成
if (SKPaymentTransactionStatePurchased == transaction.transactionState) {
NSLog(@"購買完成 %@", transaction.payment.productIdentifier);
// 更新界面或者數據,把用戶購買得商品交給用戶
// ...
// 驗證購買憑據
[self verifyPruchase];
// 將交易從交易隊列中刪除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
} else if (SKPaymentTransactionStateRestored == transaction.transactionState) {
NSLog(@"恢復成功 %@", transaction.payment.productIdentifier);
// 更新界面或者數據,把用戶購買得商品交給用戶
// ...
// 將交易從交易隊列中刪除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
}
復制代碼
3.8.給用戶提供恢復功能(因為在不同設備上永久性商品可能會出現需要恢復購買的情況)
#pragma mark - 恢復商品
- (void)restorePurchase
{
// 恢復已經完成的所有交易.(僅限永久有效商品)
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
3.9.驗證購買(防止第三方插件漏洞)iOS7新特性
提示:雖然蘋果在iOS7提升了購買憑據的安全性,但是處於金錢考慮,購買完成後,一定要做憑據的驗證工作。
復制代碼
1 #pragma mark 驗證購買憑據
2 - (void)verifyPruchase
3 {
4 // 驗證憑據,獲取到蘋果返回的交易憑據
5 // appStoreReceiptURL iOS7.0增加的,購買交易完成後,會將憑據存放在該地址
6 NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
7 // 從沙盒中獲取到購買憑據
8 NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
9
10 // 發送網絡POST請求,對購買憑據進行驗證
11 NSURL *url = [NSURL URLWithString:ITMS_SANDBOX_VERIFY_RECEIPT_URL];
12 // 國內訪問蘋果服務器比較慢,timeoutInterval需要長一點
13 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
14
15 request.HTTPMethod = @"POST";
16
17 // 在網絡中傳輸數據,大多情況下是傳輸的字符串而不是二進制數據
18 // 傳輸的是BASE64編碼的字符串
19 /**
20 BASE64 常用的編碼方案,通常用於數據傳輸,以及加密算法的基礎算法,傳輸過程中能夠保證數據傳輸的穩定性
21 BASE64是可以編碼和解碼的
22 */
23 NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
24
25 NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
26 NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
27
28 request.HTTPBody = payloadData;
29
30 // 提交驗證請求,並獲得官方的驗證JSON結果
31 NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
32
33 // 官方驗證結果為空
34 if (result == nil) {
35 NSLog(@"驗證失敗");
36 }
37
38 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
39
40 NSLog(@"%@", dict);
41
42 if (dict != nil) {
43 // 比對字典中以下信息基本上可以保證數據安全
44 // bundle_id&application_version&product_id&transaction_id
45 NSLog(@"驗證成功");
46 }
47 }