最近項目中要加進去虛擬幣和會員的功能 本以為特別簡單不就是幾十行代碼嘛 但是內購做下來 可把我坑慘了 有什么問題盡可留言 一定幫你們順利通過內購
文章末尾有內購遇見的bug 以及解決辦法
一 首先區分一下 Apple Pay 和內購完全是兩碼事
本來說集成內購的 但我們后臺大哥說可以使用apple pay 也是蘋果的支付系統 沒做過內購我以為就是一樣的 然后和我們超哥 三下五除二的把applepay集成進來的 然后也是線下測試 線上測試 一大堆 終于好了 開始提測 果然 因為applepay悲劇了 呵呵呵呵了
二 開始集成內購
1、先到iTunes Connect上填寫協議、稅務和銀行業務
如果你是外包公司,那么你可以讓你的客戶填寫這一堆信息;如果你只是是產品公司的技術開發人員,那么你可以讓項目負責人填寫這一堆信息;如果沒有如果,兄弟辛苦了,自己動手來吧。
先點擊Contact Info 的Set Up
進行十二步的時候可能有些銀行通過下面的Look up CNAPS Code方法查不到,就需要借助百度了,一定要準確查詢,否則會有問題。推薦一個地址
https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp
這一步需要注意的是,貨幣類型可能有歧義,看你是想收美元還是人民幣了,都說美元合適。不過,我做的時候為了避免事情,還是選擇了CNY,支持國產。還有一點,銀行賬號如果是對公的賬號,需要填寫公司的英文名稱,如果沒有的話,上拼音!然后點擊保存銀行信息就算ok了,然后退回到最開始的頁面
2 為app添加內購產品
在iTunes Connect在你要添加內購的app中,進入到功能頁面
在你點擊添加內購產品按鈕后會有彈框,提示你選擇類型,這個就要看你app的需求了
填寫完審核信息后,點擊右上角的“存儲”按鈕,就添加了一個內購產品~
3添加沙盒技術測試員
在iTunes Connect的用戶和智能中選擇“沙盒技術測試員”,填寫信息保存以后就有一個測試員了
直接魯代碼
#import <StoreKit/StoreKit.h>
@interface LLMIneCoinRechargeController ()<UIAlertViewDelegate,SKProductsRequestDelegate,SKPaymentTransactionObserver>
@property(nonatomic, strong)NSArray<LLMIneCoinRechargeModel *> *coinModelArr;
@property(nonatomic,copy)NSString * bvip;
@property(nonatomic,copy)NSString * coin;
@property(nonatomic, strong)SKProductsRequest *request;
@property(nonatomic,copy)NSString * productID;
@implementation LLMIneCoinRechargeController{
UIAlertView* _alertView;
NSString *coinStr;
}
- (void)viewDidLoad {
[super viewDidLoad];
//一定要 開啟內購檢測
[[SKPaymentQueue defaultQueue]addTransactionObserver:self];
}
// 在點擊事件中去添加代碼
- (void)payBtnClick:(UIButton *)sender{
__block LLMIneCoinRechargeModel *model = nil;
[self.coinModelArr enumerateObjectsUsingBlock:^(LLMIneCoinRechargeModel * obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (obj.selected) {
model = obj;
}
}];
if (!model) {
[HudManager showMessage:@"請選擇金額"];
return;
}
NSString *proID = [NSString stringWithFormat:@"charge%@",model.coinID];
WS(weakSelf);
if ([SKPaymentQueue canMakePayments]) {
[weakSelf requestProductData:proID];
weakSelf.productID = proID;
}else{
[HudManager showMessage:@"不允許程序內付費"];
}
}
// 收到請求信息
- (void)requestProductData:(NSString *)productID{
NSLog(@"-------------請求對應的產品信息----------------");
[SVProgressHUD showWithStatus:nil maskType:SVProgressHUDMaskTypeBlack];
NSArray *product = [[NSArray alloc] initWithObjects:productID,nil];
NSSet *nsset = [NSSet setWithArray:product];
_request = [[SKProductsRequest alloc]initWithProductIdentifiers:nsset];
_request.delegate = self;
[_request start];
}
// 收到返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSArray *product = response.products;
if (product.count == 0) {
[SVProgressHUD dismiss];
[HudManager showMessage:@"購買失敗"];
return;
}
SKProduct *prod = nil;
for (SKProduct *pro in product) {
if ([pro.productIdentifier isEqualToString:self.productID]) {
prod = pro;
}
}
// 發送購買請求
if (prod != nil) {
SKPayment *payment = [SKPayment paymentWithProduct:prod];
[[SKPaymentQueue defaultQueue]addPayment:payment];
}
}
// 失敗回調
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
[SVProgressHUD dismiss];
[HudManager showMessage:@"購買失敗"];
}
// 支付后的反饋信息
- (void)requestDidFinish:(SKRequest *)request{
[SVProgressHUD dismiss];
}
// 監聽購買結果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
for (SKPaymentTransaction *tran in transactions) {
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:
[self verifyPurchaseWithPaymentTransactionWith:tran];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@"商品已經添加進列表");
break;
case SKPaymentTransactionStateRestored:
NSLog(@"已經購買過商品");
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"購買失敗");
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
[HudManager showMessage:@"購買失敗"];
break;
default:
break;
}
}
}
/**
* 驗證購買,避免越獄軟件模擬蘋果請求達到非法購買問題
*
*/
-(void)verifyPurchaseWithPaymentTransactionWith:(SKPaymentTransaction *)tran{
//從沙盒中獲取交易憑證并且拼接成請求體數據
NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
NSString *receiptString = [receiptData base64EncodedStringWithOptions:0];
if (!receiptString) {
return;
}
// 將base64 編碼 發給后臺服務器 做驗證 以及是否是沙箱環境的參數
NSDictionary *dict = [NSDictionary universalParameteWithDictionary:@{@"receipt":receiptString,
@"sandbox":BOOLSandBox,
}];
[[LFBHTTPSessionManager manager]POSTwithURLString:KApplePay_Docheck parameters:dict success:^(id data) {
[self loadData];
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
} failed:^(NSError *error) {
// [HudManager showMessage:error.description];
}];
}
- (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
代碼基本上就上邊的了
四 、要注意的事項!
1.bundleID要與iTunes Connect上你App的相同,不然是請求不到產品信息的
2.在沙盒環境進行測試內購的時候,要使用沒有越獄的蘋果手機。
3.在沙盒環境下真機測試內購時,請去app store中注銷你的apple ID,不然發起支付購買請求后會直接case:SKPaymentTransactionStateFailed。使用沙盒測試員的賬號時不需要真正花錢的。
4.如果只添加了一個沙盒測試員賬號,當一個真機已經使用了這個賬號,另一個真機再使用這個賬號支付也是會發生錯誤的。那就去多建幾個沙盒測試員賬號使用不同的,反正也是免費的,填寫也很快。
5.監聽購買結果,當失敗和成功時代碼中要調用:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
該方法通知蘋果支付隊列該交易已完成,不然就會已發起相同 ID 的商品購買就會有此項目將免費恢復的提示。
1
uideline 3.1.1 - Business
We noticed that your app enables the purchase of content, services, or functionality in the app by means other than the in-app purchase API, which is not appropriate for the App Store.
解決辦法 這個被拒的原因很簡單了 是要要使用內購了
2 切記 內購和Apple Pay 是兩回事
3
We noticed that your in-app purchase product is set to an incorrect product type.
VIP is set to consumable.
Next Steps
Since the service offered by your app requires the user to make an advance payment to access the content or receive the service, please use the non-renewable subscription in-app purchase product type. Non-renewable subscription content must be made available to all iOS devices owned by a single user, as indicated in guideline 3.1.2 of the App Store Review Guidelines.
Note: The product type cannot be changed once an in-app purchase product has been created. Therefore, you will need to create a new in-app purchase product with the correct product type.
解決辦法 : 虛擬幣是消耗類型 但是一定要記住 會員VIP不是消耗類型的的 是非訂閱類型的 更改你的VIP類型
4
Guideline 3.1.2 - Business
Your app offers a content subscription but does not have a mechanism in place to support the requirement that the subscription content be available to the user on all of their iOS devices.
Next Steps
To resolve this issue, please modify your app to include an optional user registration feature to deliver subscription content to all of the user's iOS devices. Such user registration must be made optional, not required. We also recommend indicating that registering is required to access the subscription content from their other iOS devices - and providing a way to register later, if users wish to have access to this content at a future time.
這個被拒的原因就感覺比較奇葩了 不知道是不是因為vip是費續期訂閱的問題 因為我的項目中有游客入口 也就是不用登陸 也可以進去看到部分內容以及使用部分功能 : 所以應該是這個游客入口 和內購的一些規則沖突了
有兩種解決辦法:
1 就是游客模式 不能出現購買虛擬幣以及購買VIP的頁面 (我是這么改的 然后重新提交審核 就通過了)
2 有朋友是這么做的 也通過審核了 但個人感覺相對麻煩一點
就是 游客模式可以出現購買虛擬幣以及購買VIP的頁面 而且允許游客購買 購買后的憑證要保存在本地 然后當用戶登錄的時候 把這個憑證在發給服務器去驗證 驗證成功后 將虛擬幣或者是VIp加到當前賬戶上