柚子快報激活碼778899分享:iOS蘋果內(nèi)購(詳細(xì)步驟)
柚子快報激活碼778899分享:iOS蘋果內(nèi)購(詳細(xì)步驟)
注意 apple Pay 不是蘋果內(nèi)購
1.第一步,先到 App Store Connect 中 的 協(xié)議部分,去填寫信息,(這部分一般法務(wù)去解決)
(1)查看付費同意條款
(2)設(shè)置付費協(xié)議,添加賬戶,
(3)選擇報稅表等
(4)填寫聯(lián)系人
2.添加內(nèi)購項目 (這個需要開發(fā)參與)
(1)添加內(nèi)購項目
此處的產(chǎn)品ID 為唯一ID: ?一般的規(guī)則: ?bundleID.xxx ? ?;
(2)設(shè)置內(nèi)購項目類型
消耗型和非消耗型的區(qū)別是:
消耗型:可以重復(fù)多次購買
非消耗型:只能購買一次,不會過期,例如:永久會員等;
(3).設(shè)置名稱,可以自定義;
(4)按照要求設(shè)置銷售范圍,價格,稅務(wù)類別
(5)添加App Store 本地化版本;(只要是設(shè)置語言)
(6)App Store 推廣
此處推廣圖也要是唯一的,不能和其余的商品推廣圖一致;(不能包含alpha通道)
如果設(shè)計給的圖不合規(guī),可以嘗試把圖片用預(yù)覽打開后 導(dǎo)出 ,取消alpha ,導(dǎo)出即可使用;
(7)審核信息就是,商品在App 中的頁面位置截圖,以及描述
(8)存儲即可
此時我們已經(jīng)創(chuàng)建了這個商品,接下來就是在項目中獲取商品信息,并支付
3.在項目中的代碼操作:
邏輯: ?先通過后端的接口獲取到商品的產(chǎn)品ID,然后在頁面中發(fā)起購買請求,這個請求是向App Store發(fā)出的,整個過程不用與后端交互,等結(jié)果返回后,將支付憑證發(fā)給后端即可.
具體的代碼,可以參考:
#import
#import
typedef enum : NSUInteger {
ApplePayManagerTypeSuccess, // 購買成功
ApplePayManagerTypeFailed, // 購買失敗
ApplePayManagerTypeCancle, // 取消購買
ApplePayManagerTypeVerFailed, // 訂單校驗失敗
ApplePayManagerTypeVerSuccess, // 訂單校驗成功
ApplePayManagerTypeNotArrow, // 不允許內(nèi)購
} ApplePayManagerType;
typedef void (^IAPCompletionHandle)( ApplePayManagerType type,NSData * _Nullable data);
NS_ASSUME_NONNULL_BEGIN
@interface ApplePayManager : NSObject
@property (nonatomic, strong)UIView * targetView;
+ (instancetype)shareAPManager;
//開始內(nèi)購
- (void)startPurchWithDict:(NSDictionary *)purch completeHandle:(IAPCompletionHandle)handle;
#import "ApplePayManager.h"
#import "MineMemberInAppVerifyReceiptRequest.h"
@interface ApplePayManager ()
@property (nonatomic,copy) NSString * purchID;
@property (nonatomic,copy) IAPCompletionHandle handle;
@property (nonatomic,strong) NSDictionary * parmas;
@end
@implementation ApplePayManager
+(instancetype)shareAPManager{
static ApplePayManager *IAPManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
IAPManager = [[ApplePayManager alloc] init];
});
return IAPManager;
}
- (instancetype)init{
self = [super init];
if (self) {
// 購買監(jiān)聽寫在程序入口,程序掛起時移除監(jiān)聽,這樣如果有未完成的訂單將會自動執(zhí)行并回調(diào) paymentQueue:updatedTransactions:方法
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
- (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
#pragma mark - public 去蘋果服務(wù)器請求產(chǎn)品信息
-(void)startPurchWithDict:(NSDictionary *)purch completeHandle:(IAPCompletionHandle)handle{
if (purch.allKeys.count > 0) {
self.parmas = purch;
if ([purch objectForKey:@"productId"]) {
if ([SKPaymentQueue canMakePayments]) {
// 開始購買服務(wù)
self.purchID = [purch objectForKey:@"productId"];
self.handle = handle;
NSSet *nsset = [NSSet setWithArray:@[self.purchID]];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
[request start];
dispatch_async(dispatch_get_main_queue(), ^{
[self.targetView makeToastActivity:CSToastPositionCenter];
});
}else{
[self handleActionWithType:ApplePayManagerTypeNotArrow data:nil];
}
}
}
}
#pragma mark --收到產(chǎn)品返回信息 SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSArray *product = response.products;
if([product count] <= 0){
NSLog(@"--------------沒有商品------------------");
return;
}
SKProduct *p = nil;
for(SKProduct *pro in product){
if([pro.productIdentifier isEqualToString:self.purchID]){
p = pro;
break;
}
}
NSLog(@"productID:%@", response.invalidProductIdentifiers);
NSLog(@"產(chǎn)品付費數(shù)量:%lu",(unsigned long)[product count]);
NSLog(@"%@",[p description]);
NSLog(@"%@",[p localizedTitle]);
NSLog(@"%@",[p localizedDescription]);
NSLog(@"%@",[p price]);
NSLog(@"%@",[p productIdentifier]);
NSLog(@"發(fā)送購買請求");
//發(fā)送內(nèi)購請求
SKPayment *payment = [SKPayment paymentWithProduct:p];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
//請求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
// [self.targetView hideToastActivity];
NSLog(@"------------------錯誤-----------------:%@", error);
}
- (void)requestDidFinish:(SKRequest *)request{
// [self.targetView hideToastActivity];
NSLog(@"------------反饋信息結(jié)束-----------------");
}
#pragma mark - SKPaymentTransactionObserver // 監(jiān)聽購買結(jié)果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray
[self.targetView hideToastActivity];
for (SKPaymentTransaction *tran in transactions) {
NSLog(@"%ld====",(long)tran.transactionState);
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased: //交易完成
//訂閱特殊處理
if(tran.originalTransaction){
//如果是自動續(xù)費的訂單originalTransaction會有內(nèi)容
NSLog(@"自動續(xù)費的訂單,originalTransaction = %@",tran.originalTransaction.transactionIdentifier);
//tran.originalTransaction.transactionIdentifier
//SKPaymentTransaction
[self completeTransaction:tran isAutomatically:YES];
//[self verifyPurchaseWithPaymentTransaction:tran isTestServer:NO];
}else{
//普通購買,以及 第一次購買 自動訂閱
// NSLog(@"%@-------",tran.transactionIdentifier);
[self completeTransaction:tran isAutomatically:NO];
}
break;
case SKPaymentTransactionStatePurchasing://商品添加進(jìn)列表
//NSLog(@"%ld====",tran.error.code);
//NSLog(@"%@====",[[NSString alloc]initWithData:tran.payment.requestData encoding:NSUTF8StringEncoding]);
//[TDGAVirtualCurrency onChargeRequst:@"" iapId:@"" currencyAmount:0 currencyType:@"" virtualCurrencyAmount:0 paymentType:@""];
break;
case SKPaymentTransactionStateRestored://購買過
NSLog(@"已經(jīng)購買過商品");
// 消耗型不支持恢復(fù)購買
//[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
case SKPaymentTransactionStateFailed://交易失敗
NSLog(@"%@====",tran.error);
//SKErrorUnknown
[self failedTransaction:tran];
break;
default:
break;
}
}
}
/// AppStore 從促銷點擊購買處理
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product {
// 直接返回 NO,不交給蘋果處理
NSString *productID = product.productIdentifier;
NSLog(@"AppStore 促銷點擊購買: productIdentifier - %@", productID);
return YES;
}
#pragma mark - delegate
// 交易結(jié)束
- (void)completeTransaction:(SKPaymentTransaction *)transaction isAutomatically:(BOOL)isAutomatically{
NSLog(@"%@", transaction.description);
// Your application should implement these two methods.
// 票據(jù)的校驗是保證內(nèi)購安全完成的非常關(guān)鍵的一步,一般有三種方式:
// 1、服務(wù)器驗證,獲取票據(jù)信息后上傳至信任的服務(wù)器,由服務(wù)器完成與App Store的驗證(提倡使用此方法,比較安全)
// 2、本地票據(jù)校驗
// 3、本地App Store請求驗證
NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
// 向自己的服務(wù)器驗證購買憑證
//NSError *error;
//轉(zhuǎn)化為base64字符串
NSString *receiptString=[receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSLog(@"receipt ==== \n%@", receiptString);
//最終將這個receipt3的發(fā)送給服務(wù)器去驗證就沒問題啦!
//自動訂閱(自動續(xù)費月卡)需要多加一個參數(shù)
NSString * product_id = transaction.payment.productIdentifier;
NSString * transaction_id = transaction.transactionIdentifier;
NSMutableDictionary * requestContents = [[NSMutableDictionary alloc]init];
//訂閱特殊處理
if (isAutomatically) {
//如果是自動續(xù)費的訂單originalTransaction會有內(nèi)容
NSString * transaction_id2 = transaction.originalTransaction.transactionIdentifier;
NSString * transaction_id = transaction.transactionIdentifier;
// [requestContents addEntriesFromDictionary:@{@"receipt": receipt3,@"password":secretKey,@"product_id":product_id,@"transaction_id":transaction_id,@"originalTransaction":transaction_id2}];
}else{
if (self.parmas.allKeys.count > 0) {
// [requestContents addEntriesFromDictionary:@{@"receipt": receipt3,@"uid":self.parmas[@"uid"],@"amount":self.parmas[@"amount"],@"actorid":self.parmas[@"userRoleId"],@"server":self.parmas[@"serverId"],@"order_no":self.parmas[@"cpOrderNo"],@"password":secretKey,@"product_id":product_id,@"transaction_id":transaction_id}];
}
}
[self.targetView makeToastActivity:CSToastPositionCenter];
NSDictionary * dic = @{@"productId": product_id, @"transactionId": transaction_id, @"receipt": receiptString, @"isSandbox": @0};
[MineMemberInAppVerifyReceiptRequest requestWithDic:dic requestFinish:^(MineMemberInAppVerifyReceiptRequest * request) {
[self.targetView hideToastActivity];
int code = [[request.responseJson objectForKey:@"code"] intValue];
NSString * stateString = [request.responseJson objectForKey:@"msg"];
if (code == 200) {
[self handleActionWithType:ApplePayManagerTypeVerSuccess data:nil];
}else {
[self.targetView makeToast:@"校驗失敗" duration:2 position:CSToastPositionCenter];
}
} requestFailed:^(MineMemberInAppVerifyReceiptRequest *request) {
[self.targetView hideToastActivity];
[self.targetView makeToast:@"請求失敗" duration:2 position:CSToastPositionCenter];
}];
//本地像蘋果app store驗證,上面是像自己的服務(wù)器驗證
[self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
// 驗證成功與否都注銷交易,否則會出現(xiàn)虛假憑證信息一直驗證不通過,每次進(jìn)程序都得輸入蘋果賬號
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//[self verifyPurchaseWithPaymentTransaction:transaction isTestServer:NO];
}
// 交易失敗
- (void)failedTransaction:(SKPaymentTransaction *)transaction{
if (transaction.error.code != SKErrorPaymentCancelled) {
[self handleActionWithType:ApplePayManagerTypeFailed data:nil];
}else{
[self handleActionWithType:ApplePayManagerTypeCancle data:nil];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag{
//交易驗證
NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:recepitURL];
if(!receipt){
// 交易憑證為空驗證失敗
[self handleActionWithType:ApplePayManagerTypeVerFailed data:nil];
return;
}
// 購買成功將交易憑證發(fā)送給服務(wù)端進(jìn)行再次校驗
// [self handleActionWithType:ApplePayManagerTypeSuccess data:receipt];
NSError *error;
NSDictionary *requestContents = @{
@"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
if (!requestData) { // 交易憑證為空驗證失敗
[self handleActionWithType:ApplePayManagerTypeVerFailed data:nil];
return;
}
//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
//In the real environment, use https://buy.itunes.apple.com/verifyReceipt
NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";
if (flag) {
serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";
}
NSURL *storeURL = [NSURL URLWithString:serverString];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
// 無法連接服務(wù)器,購買校驗失敗
[self handleActionWithType:ApplePayManagerTypeVerFailed data:nil];
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) {
// 蘋果服務(wù)器校驗數(shù)據(jù)返回為空校驗失敗
[self handleActionWithType:ApplePayManagerTypeVerFailed data:nil];
}
// 先驗證正式服務(wù)器,如果正式服務(wù)器返回21007再去蘋果測試服務(wù)器驗證,沙盒測試環(huán)境蘋果用的是測試服務(wù)器
NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
if (status && [status isEqualToString:@"21007"]) {
// [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
}else if(status && [status isEqualToString:@"0"]){
// [self handleActionWithType:ApplePayManagerTypeVerSuccess data:nil];
}
}
}];
[dataTask resume];
// 驗證成功與否都注銷交易,否則會出現(xiàn)虛假憑證信息一直驗證不通過,每次進(jìn)程序都得輸入蘋果賬號
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
#pragma mark - private
- (void)handleActionWithType:(ApplePayManagerType)type data:(NSData *)data{
switch (type) {
case ApplePayManagerTypeSuccess:
NSLog(@"購買成功");
break;
case ApplePayManagerTypeFailed:
NSLog(@"購買失敗");
break;
case ApplePayManagerTypeCancle:
NSLog(@"用戶取消購買");
[self.targetView makeToast:@"用戶取消購買" duration:2 position:CSToastPositionCenter];
break;
case ApplePayManagerTypeVerFailed:
[self.targetView makeToast:@"訂單校驗失敗" duration:2 position:CSToastPositionCenter];
NSLog(@"訂單校驗失敗");
break;
case ApplePayManagerTypeVerSuccess:
NSLog(@"訂單校驗成功");
break;
case ApplePayManagerTypeNotArrow:
NSLog(@"不允許程序內(nèi)付費");
break;
default:
break;
}
if(_handle){
_handle(type,data);
}
}
上報完成即可
在App 提交審核的時候,要附帶著添加指定的內(nèi)購產(chǎn)品,
注意: 在未審核通過之前,這些商品,均是沙盒測試環(huán)境下的,支付并不會涉及金額交易,而且后端可以查詢到支付信息
柚子快報激活碼778899分享:iOS蘋果內(nèi)購(詳細(xì)步驟)
相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。