根據公司的需求,我們的APP內是有內購的,從最開始開始做,到現在,也經歷了好些,我覺得有些地方的注意點還得寫寫.
內購的代碼,網上都有這里簡單的copy一下
首先,購買蘋果的商品,得確定一下,這個內購商品是否存在
-(void) request_products_list_from_apple:(NSArray *) productIDs{
NSSet *productSet = [NSSet setWithArray:productIDs];
SKProductsRequest *apple_request = [[SKProductsRequest alloc] initWithProductIdentifiers:productSet];
apple_request.delegate = self;
NSLog(@"buy---test");
[apple_request start];
}
這段代碼是發起獲取商品請求,productIDs,是在iTunes里建立商品的對應的ID ,如果有對應的商品會在下面這個代理回調中返回商品信息
-(void)productsRequest:(SKProductsRequest? *)request didReceiveResponse:(SKProductsResponse *)response{
NSArray *products = [response products];
if (products != nil && [products count]>0) {
for(SKProduct *product in products){
NSLog(@"product info");
NSLog(@"SKProduct 描述信息%@", [product description]);
NSLog(@"產品標題 %@" , product.localizedTitle);
NSLog(@"產品描述信息: %@" , product.localizedDescription);
NSLog(@"價格: %@" , product.price);
NSLog(@"Product id: %@" , product.productIdentifier);
}
}
}
確定商品存在以后就可以發起支付請求了,當然在獲取商品之前最好先添加觀察者
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
然后發起支付請求
SKPayment *payment = [SKPayment paymentWithProduct:buy_product];//這個buy_product就是你要購買的商品,從上面代理回調返回的商品中篩選出來的
[[SKPaymentQueue defaultQueue] addPayment:payment];
支付過程中發生的變化,都會在下面回調中出現
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *trans in transactions) {
switch (trans.transactionState) {
case SKPaymentTransactionStateFailed:
{
NSLog(@" trans Failed");
switch(trans.error.code) {
case? SKErrorUnknown:
errorMsg = @"無法連接iTunes Store(如有疑問,可以詢問蘋果客服)";
break;
case? SKErrorClientInvalid:
errorMsg = @"客戶端驗證錯誤";
break;
case SKErrorPaymentCancelled:
errorMsg = @"訂單已取消";
break;
case SKErrorPaymentNotAllowed:
errorMsg = @"當前蘋果設備無法購買商品(如有疑問,可以詢問蘋果客服)";
break;
case SKErrorPaymentInvalid:
errorMsg = @"購買商品標識無效";
break;
case SKErrorStoreProductNotAvailable:
errorMsg = @"在目前的商店內產品不可購買";
break;
case SKErrorCloudServicePermissionDenied:
errorMsg = @"用戶已不允許訪問云服務信息(如有疑問,可以詢問蘋果客服)";
break;
case SKErrorCloudServiceNetworkConnectionFailed:
errorMsg = @"設備沒有聯網";
break;
}
[[SKPaymentQueue defaultQueue] finishTransaction:trans];
}
break;
case SKPaymentTransactionStatePurchased:
{
NSLog(@" trans Purchased");
NSData *receiptData;
receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
if (receiptData != nil) {
NSDictionary *requestContents = @{
@"receipt-data": [receiptData base64EncodedStringWithOptions:0]
};
}
NSError *error;
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
NSString *base64_receipt = [[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding];//這個是最后的驗證信息,建議傳給服務端去驗證(本地建議用keychain保存)
[[SKPaymentQueue defaultQueue] finishTransaction: trans];
}
break;
case SKPaymentTransactionStateDeferred:
{
NSLog(@" trans Deferred");
}
break;
case SKPaymentTransactionStateRestored:
{
NSLog(@"恢復購買");
NSData *receiptData;
receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
NSString *receipt = [[NSString alloc] initWithData:receiptData encoding:NSUTF8StringEncoding];
[[SKPaymentQueue defaultQueue] finishTransaction:trans];
}
break;
case SKPaymentTransactionStatePurchasing:
{
NSLog(@" trans Purchasing");
}
break;
default:
{
NSLog(@"");
}
break;
}
}
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error{
NSLog(@"request fail");//請求失敗
}
-(void)requestDidFinish:(SKRequest *)request{
NSLog(@"request finish");//請求完成
}
上述過程基本就完成了內購的流程,其實也不難,但是,就這短短的流程之間就可能會發生好些問題,
在內購時,要加是否越獄的判斷,代碼順便也貼出來吧
#define USER_APP_PATH? ? ? ? ? ? ? ? @"/User/Applications/"
+(BOOL)isJailBreak{
//判斷文件是否存在
NSArray *arr = @[@"/Applications/Cydia.app",
@"/Library/MobileSubstrate/MobileSubstrate.dylib",
@"/bin/bash",
@"/usr/sbin/sshd",
@"/etc/apt"? ];
for (NSString *str in arr) {
if ([[NSFileManager defaultManager] fileExistsAtPath:str]) {
NSLog(@"The device is jail broken! path === %@",str);
return YES;
}
}
//return NO;
//判斷cydia應用是否存在
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]]) {
NSLog(@"The device is jail broken!");
return YES;
}
//? return NO;
//不越獄的機器沒有這個權限來判定的
if ([[NSFileManager defaultManager] fileExistsAtPath:USER_APP_PATH]) {
NSLog(@"The device is jail broken!");
NSArray *applist = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:USER_APP_PATH error:nil];
NSLog(@"applist = %@", applist);
return YES;
}
//? return NO;
//讀取環境變量
//? ? char *env = getenv("DYLD_INSERT_LIBRARIES");
//? ? NSLog(@"%s", env);
//? ? if (env) {
//? ? ? ? NSLog(@"The device is jail broken!");
//? ? ? ? return YES;
//? ? }
NSLog(@"The device is NOT jail broken!");
return NO;
}
內購完成,蘋果返回的驗證最好在服務端進行驗證,網絡不佳的情況下,本地最好保存在鑰匙串(keychain)中,保存在沙盒可能刪掉app,憑證就沒有了,這個憑證是非常重要的,內購的唯一依據,蘋果只管這個商品有沒有效,不會對購買的商品是否一致驗證,有的人可以利用現成有效的憑證刷單的
沙箱測試賬號,可以在調試狀態下,模擬真實購買流程,基本和正常賬號是一樣的,不過不能在線上版本使用
給蘋果審核商品的時候注意名稱,有敏感詞匯,會被拒
審核app版本的時候,最好注明哪些不是內購商品,否則容易被誤解,導致被拒
就先寫這些,以后有在補充...