一般來說,開發(fā)人員剛接觸內(nèi)購旬昭,都會(huì)遇到流程不清楚篙螟、千頭萬緒。
如何一次性搞定內(nèi)購問題问拘?
一遍略、掌握內(nèi)購流程:
1、完成前期準(zhǔn)備工作
1)骤坐、接手內(nèi)購绪杏,一定要閱讀蘋果的《APP內(nèi)購買項(xiàng)目》文檔
2)、iTunesconnect后臺(tái)配置內(nèi)購項(xiàng)目
a或油、未配置過內(nèi)購的新項(xiàng)目寞忿,簽署 Paid Applications agreement(《付費(fèi)應(yīng)用程序協(xié)議》)
b、配置內(nèi)購項(xiàng)目顶岸,“App -->功能-->APP內(nèi)購買項(xiàng)目”
參考:創(chuàng)建及發(fā)布說明
3)腔彰、Xcode工程配置
開啟此選項(xiàng)App Store中APP的介紹界面顯示內(nèi)購的相關(guān)項(xiàng)目叫编,關(guān)閉則不顯示
4)、開發(fā)實(shí)現(xiàn)流程:
2霹抛、iTunesconnect創(chuàng)建產(chǎn)品
蘋果的內(nèi)購分以下四類商品:
1搓逾、消耗型項(xiàng)目
只可使用一次的產(chǎn)品,使用之后即失效杯拐,必須再次購買霞篡。
示例:釣魚 App 中的魚食。
2端逼、非消耗型項(xiàng)目
只需購買一次朗兵,不會(huì)過期或隨著使用而減少的產(chǎn)品。
示例:游戲 App 的賽道顶滩。
3余掖、自動(dòng)續(xù)期訂閱
允許用戶在固定時(shí)間段內(nèi)購買動(dòng)態(tài)內(nèi)容的產(chǎn)品。除非用戶選擇取消礁鲁,否則此類訂閱會(huì)自動(dòng)續(xù)期盐欺。
示例:每月訂閱提供流媒體服務(wù)的 App。
4仅醇、非續(xù)期訂閱
允許用戶購買有時(shí)限性服務(wù)的產(chǎn)品冗美。此 App 內(nèi)購買項(xiàng)目的內(nèi)容可以是靜態(tài)的。此類訂閱不會(huì)自動(dòng)續(xù)期析二。
示例:為期一年的已歸檔文章目錄訂閱粉洼。
首先,在“我的APP”——“功能”——“App內(nèi)購買項(xiàng)目”添加適合自己的商品:
二甲抖、開發(fā)實(shí)現(xiàn):
每個(gè)開發(fā)人員帳戶可在該帳戶的所有 App 中創(chuàng)建最多 10,000 個(gè) App 內(nèi)購買項(xiàng)目產(chǎn)品漆改。App 內(nèi)購買項(xiàng)目共有四種類型:消耗型、非消耗型准谚、自動(dòng)續(xù)期訂閱和非續(xù)期訂閱挫剑。
開源庫(XYIAPKit),使用此開源庫直接可省去“開發(fā)實(shí)現(xiàn)”這一步驟柱衔。
實(shí)現(xiàn)步驟主要包括三步:
1樊破、首先在項(xiàng)目工程中加入StoreKit.framework
2、加入頭文件#import <StoreKit/StoreKit.h>
3唆铐、遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate
步驟一:App Store請求內(nèi)購項(xiàng)
注意:此步驟建議在開始創(chuàng)建購買訂單前完成哲戚,這樣可以減少購買時(shí)查詢訂單的時(shí)間
1)、判斷用戶是否具備支付權(quán)限
if ([SKPaymentQueue canMakePayments]) {
//允許應(yīng)用內(nèi)付費(fèi)購買
}else {
//用戶禁止應(yīng)用內(nèi)付費(fèi)購買.
}
Indicates whether the user is allowed to make payments.
An iPhone can be restricted from accessing the Apple App Store. For example, parents can restrict their children’s ability to purchase additional content. Your application should confirm that the user is allowed to authorize payments before adding a payment to the queue. Your application may also want to alter its behavior or appearance when the user is not allowed to authorize payments.
2艾岂、創(chuàng)建一個(gè)商品查詢的請求顺少,productIdentifiers
指需要查詢的“產(chǎn)品ID”的數(shù)組
NSSet * set = [NSSet setWithArray:productIdentifiers];
SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
[request start];
查詢的結(jié)果將通過SKProductsRequestDelegate
得到查詢的結(jié)果
獲取商品的查詢結(jié)果
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response NS_AVAILABLE_IOS(3_0);
在此回調(diào)中我們可以拿到所查詢產(chǎn)品的信息,保存所查詢的信息,以供構(gòu)建購買時(shí)使用脆炎。
SKProductsResponse
// Array of SKProduct instances.
@property(nonatomic, readonly) NSArray<SKProduct *> *products NS_AVAILABLE_IOS(3_0);
// Array of invalid product identifiers.
@property(nonatomic, readonly) NSArray<NSString *> *invalidProductIdentifiers NS_AVAILABLE_IOS(3_0);
獲取請求完成和失敗的結(jié)果
- (void)requestDidFinish:(SKRequest *)request NS_AVAILABLE_IOS(3_0);
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error NS_AVAILABLE_IOS(3_0);
步驟二:開始構(gòu)建購買請求
1)梅猿、判斷請求的產(chǎn)品ID是否已獲取到它的產(chǎn)品信息SKProduct
,且是否可用秒裕。
若商品可用創(chuàng)建支付袱蚓;
若商品不可用提示用戶;
若商品尚未獲取它的產(chǎn)品信息几蜻,進(jìn)行“步驟一”操作
2)喇潘、創(chuàng)建支付
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
3)、添加支付交易的Observer
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
注意在適當(dāng)?shù)臅r(shí)候移除Observer
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
可以通過遵循SKPaymentTransactionObserver
協(xié)議來監(jiān)聽整個(gè)交易的過程
交易狀態(tài)發(fā)生改變時(shí)梭稚,包括狀態(tài)的改變颖低,交易的結(jié)束
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions NS_AVAILABLE_IOS(3_0);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://交易完成
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed://交易失敗
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored://已經(jīng)購買過該商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing: //商品添加進(jìn)列表
NSLog(@"商品添加進(jìn)列表");
break;
default:
break;
}
4)、校驗(yàn)票據(jù)
票據(jù)的校驗(yàn)是保證內(nèi)購安全完成的非常關(guān)鍵的一步弧烤,一般有三種方式:
1枫甲、服務(wù)器驗(yàn)證,獲取票據(jù)信息后上傳至信任的服務(wù)器扼褪,由服務(wù)器完成與App Store的驗(yàn)證(提倡使用此方法,比較安全)
2粱栖、本地票據(jù)校驗(yàn)
3话浇、本地App Store請求驗(yàn)證
a)、本地票據(jù)校驗(yàn)
本地票據(jù)校驗(yàn)的一般步驟
要驗(yàn)證收據(jù)闹究,請按順序執(zhí)行以下測試:
1.找到收據(jù)幔崖。
如果沒有收據(jù),則驗(yàn)證失敗渣淤。
2.驗(yàn)證收據(jù)是否由Apple 正確簽署
如果收據(jù)不是由 Apple 簽署赏寇,則驗(yàn)證失敗。
3.驗(yàn)證收據(jù)中的Bundle Identifier(數(shù)據(jù)包標(biāo)識(shí)符)與在Info.plist文件中含有您要的CFBundleIdentifier值的硬編碼常量相匹配价认。
如果兩者不匹配嗅定,則驗(yàn)證失敗。
4.驗(yàn)證收據(jù)中的版本標(biāo)識(shí)符字符串與在Info.plist文件中含有您要的CFBundleShortVersionString值(macOS)或
CFBundleVersion 值(iOS)的硬編碼常量相匹配用踩。
如果兩者不匹配渠退,則驗(yàn)證失敗。
5.按照“計(jì)算 GUID 的哈希(Hash)(第 8 頁)”所述計(jì)算GUID 的哈希(Hash)脐彩。
如果結(jié)果與收據(jù)中的哈希(Hash)不匹配碎乃,則驗(yàn)證失敗。
如果通過所有測試惠奸,則驗(yàn)證成功梅誓。
注意: Bundle Identifier(數(shù)據(jù)包標(biāo)識(shí)符)和版本標(biāo)識(shí)符字符串是UTF-8 字符串,而不僅僅是一系列字節(jié)。確保您相應(yīng)地編寫比較邏輯代碼梗掰。
如果您的 App 支持“批量購買計(jì)劃”嵌言,請檢查收據(jù)的有效日期。
b)愧怜、App Store驗(yàn)證:
1)呀页、獲取票據(jù)
- (NSString *)iapReceipt
{
NSString *receiptString = nil;
NSURL *rereceiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
if ([[NSFileManager defaultManager] fileExistsAtPath:[rereceiptURL path]]) {
NSData *receiptData = [NSData dataWithContentsOfURL:rereceiptURL];
receiptString = [receiptData base64EncodedStringWithOptions:0];
}
return receiptString;
}
如果此時(shí)未獲取到票據(jù)的信息,使用SKReceiptRefreshRequest
來刷新票據(jù)結(jié)果拥坛。
SKReceiptRefreshRequest *refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}];
refreshReceiptRequest.delegate = self;
[refreshReceiptRequest start];
- (void)requestDidFinish:(SKRequest *)request {
}
2)蓬蝶、請求驗(yàn)證
獲取到票據(jù)以后我們通過App Store來驗(yàn)證票據(jù)是否真實(shí)
沙盒狀態(tài)下使用:https://sandbox.itunes.apple.com/verifyReceipt來驗(yàn)證
生產(chǎn)環(huán)境下使用:https://buy.itunes.apple.com/verifyReceipt
常見的驗(yàn)證狀態(tài)代碼:
由于審核時(shí),審核人員為沙盒狀態(tài)猜惋,注意狀態(tài)碼“21007”
- (void)verifyRequestData:(NSString *)base64Data
url:(NSString *)url
transaction:(SKPaymentTransaction *)transaction
success:(void (^)(void))successBlock
failure:(void (^)(NSError *error))failureBlock
{
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setValue:base64Data forKey:@"receipt-data"];
[params setValue:self.sharedSecretKey forKey:@"password"];
NSError *jsonError;
NSData *josonData = [NSJSONSerialization dataWithJSONObject:params
options:NSJSONWritingPrettyPrinted
error:&jsonError];
if (jsonError) {
NSLog(@"verifyRequestData failed: error = %@", jsonError);
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
request.HTTPBody = josonData;
static NSString *requestMethod = @"POST";
request.HTTPMethod = requestMethod;
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (!data) {
NSError *wrapperError = [weakSelf unableVerifyReceiptError:error];
if (failureBlock != nil) failureBlock(wrapperError);
return;
}
NSError *jsonError;
NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (!responseJSON) {
NSLog(@"Failed To Parse Server Response");
if (failureBlock != nil) failureBlock(jsonError);
}
static NSString *statusKey = @"status";
NSInteger statusCode = [responseJSON[statusKey] integerValue];
static NSInteger successCode = 0;
static NSInteger sandboxCode = 21007;
if (statusCode == successCode) {
[weakSelf saveVerifiedReceipts:transaction response:responseJSON];
if (successBlock != nil) successBlock();
} else if (statusCode == sandboxCode) {
[weakSelf sandboxVerify:base64Data
transaction:transaction
success:successBlock
failure:failureBlock];
} else {
NSLog(@"Verification Failed With Code %ld", (long)statusCode);
NSError *serverError = [NSError errorWithDomain:XYStoreErrorDomain code:statusCode userInfo:nil];
if (failureBlock != nil) failureBlock(serverError);
}
});
});
}
3)丸氛、核實(shí)票據(jù)信息
a、非訂閱產(chǎn)品著摔,若返回結(jié)果正確缓窜,驗(yàn)證通過
b、訂閱產(chǎn)品需要驗(yàn)證訂閱是否過期
- (BOOL)checkIsSubscribed:(XYiTunesResponse *)iTunesResponse productId:(NSString *)productId
{
NSDate *expires_date;
for (XYInAppReceipt *appReceipt in iTunesResponse.latest_receipt_info) {
if ([appReceipt.product_id isEqualToString:productId] == NO) {
continue;
}
if (expires_date) {
expires_date = [expires_date laterDate:appReceipt.expires_date];
}else {
expires_date = appReceipt.expires_date;
}
}
// 不包含過期信息表示無自動(dòng)續(xù)期交易
if (!expires_date) {
return NO;
}
if (([expires_date timeIntervalSinceDate:iTunesResponse.receipt.request_date] > 0) && ([expires_date timeIntervalSinceDate:[NSDate date]] > 0)) {
// 1谍咆、對比請求時(shí)間
// 針對SKPaymentTransactionObserver的監(jiān)聽禾锤,當(dāng)交易信息發(fā)生更新時(shí),蘋果會(huì)自動(dòng)推送當(dāng)前的交易狀態(tài)摹察,
// 緩存票據(jù)更新時(shí)的請求時(shí)間恩掷,通過與過期時(shí)間對比來確定用戶的訂閱是否過期
// 此方式可以避免用戶修改系統(tǒng)時(shí)間造成的問題,也能保證及時(shí)的更新用戶訂閱狀況
// 也可使用獲取當(dāng)前外部服務(wù)器的時(shí)間供嚎,當(dāng)然需要異步操作黄娘,時(shí)間成本比較高
// 2、對比系統(tǒng)時(shí)間
// 防止訂閱后克滴,用戶強(qiáng)制斷網(wǎng)
return YES;
}
return NO;
}
@interface XYInAppReceipt : NSObject
/**
The default value is 1, the minimum value is 1, and the maximum value is 10.
*/
@property (nonatomic, assign) NSInteger quantity;
@property (nonatomic, copy) NSString *product_id;
@property (nonatomic, copy) NSString *transaction_id;
@property (nonatomic, copy) NSString *original_transaction_id;
@property (nonatomic, strong) NSDate *purchase_date;
@property (nonatomic, strong) NSDate *original_purchase_date;
/**
僅用于逼争,自動(dòng)續(xù)費(fèi)訂閱
true,表示處于 免費(fèi)試用 時(shí)期
如果已有票據(jù)中含有is_trial_period或者is_in_intro_offer_period為true劝赔,用戶不再具備有此項(xiàng)資格
For a subscription, whether or not it is in the free trial period.
This key is only present for auto-renewable subscription receipts. The value for this key is "true" if the customer’s subscription is currently in the free trial period, or "false" if not.
Note: If a previous subscription period in the receipt has the value “true” for either the is_trial_period or the is_in_intro_offer_period key, the user is not eligible for a free trial or introductory price within that subscription group.
*/
@property (nonatomic, assign) BOOL is_trial_period;
//**********************以上為四種內(nèi)購類型公共字段誓焦,下面字段為自動(dòng)續(xù)期訂閱獨(dú)有字段*********************
/**
This key is only present for auto-renewable subscription receipts.
Use this value to identify the date when the subscription will renew or expire, to determine if a customer should have access to content or service.
After validating the latest receipt, if the subscription expiration date for the latest renewal transaction is a past date, it is safe to assume that the subscription has expired.
*/
@property (nonatomic, strong) NSDate *expires_date;
/**
“1” - Customer canceled their subscription.
“2” - Billing error; for example customer’s payment information was no longer valid.
“3” - Customer did not agree to a recent price increase.
“4” - Product was not available for purchase at the time of renewal.
“5” - Unknown error
*/
@property (nonatomic, assign) NSInteger expiration_intent;
/**
對于訂閱過期的自動(dòng)續(xù)費(fèi)產(chǎn)品,蘋果是否會(huì)嘗試自動(dòng)續(xù)費(fèi)
For an expired subscription, whether or not Apple is still attempting to automatically renew the subscription.
“1” - App Store is still attempting to renew the subscription.
“0” - App Store has stopped attempting to renew the subscription.
This key is only present for auto-renewable subscription receipts. If the customer’s subscription failed to renew because the App Store was unable to complete the transaction, this value will reflect whether or not the App Store is still trying to renew the subscription.
*/
@property (nonatomic, assign) BOOL is_in_billing_retry_period;
/**
僅用于着帽,自動(dòng)續(xù)費(fèi)訂閱
true罩阵,表示處于 引導(dǎo)價(jià)格 時(shí)期
如果已有票據(jù)中含有is_trial_period或者is_in_intro_offer_period為true,用戶不再具備有此項(xiàng)資格
For an auto-renewable subscription, whether or not it is in the introductory price period.
This key is only present for auto-renewable subscription receipts. The value for this key is "true" if the customer’s subscription is currently in an introductory price period, or "false" if not.
Note: If a previous subscription period in the receipt has the value “true” for either the is_trial_period or the is_in_intro_offer_period key, the user is not eligible for a free trial or introductory price within that subscription group.
*/
@property (nonatomic, assign) BOOL is_in_intro_offer_period;
/**
退款操作時(shí)間
For a transaction that was canceled by Apple customer support, the time and date of the cancellation. For an auto-renewable subscription plan that was upgraded, the time and date of the upgrade transaction.
Treat a canceled receipt the same as if no purchase had ever been made.
A canceled in-app purchase remains in the receipt indefinitely. Only applicable if the refund was for a non-consumable product, an auto-renewable subscription, a non-renewing subscription, or for a free subscription.
*/
@property (nonatomic, strong) NSDate *cancellation_date;
/**
內(nèi)購取消的原因
“1” - Customer canceled their transaction due to an actual or perceived issue within your app.
“0” - Transaction was canceled for another reason, for example, if the customer made the purchase accidentally.
Use this value along with the cancellation date to identify possible issues in your app that may lead customers to contact Apple customer support.
*/
@property (nonatomic, copy) NSString *cancellation_reason;
/**
APP唯一標(biāo)識(shí)符
*/
@property (nonatomic, copy) NSString *app_item_id;
/**
This key is not present for receipts created in the test environment. Use this value to identify the version of the app that the customer bought
*/
@property (nonatomic, copy) NSString *version_external_identifier;
/**
This value is a unique ID that identifies purchase events across devices, including subscription renewal purchase events.
*/
@property (nonatomic, copy) NSString *web_order_line_item_id;
/**
The current renewal status for the auto-renewable subscription.
“1” - Subscription will renew at the end of the current subscription period.
“0” - Customer has turned off automatic renewal for their subscription.
This key is only present for auto-renewable subscription receipts, for active or expired subscriptions. The value for this key should not be interpreted as the customer’s subscription status. You can use this value to display an alternative subscription product in your app, for example, a lower level subscription plan that the customer can downgrade to from their current plan.
*/
@property (nonatomic, assign) NSInteger auto_renew_status;
/**
The current renewal preference for the auto-renewable subscription.
This key is only present for auto-renewable subscription receipts. The value for this key corresponds to the productIdentifier property of the product that the customer’s subscription renews. You can use this value to present an alternative service level to the customer before the current subscription period ends.
*/
@property (nonatomic, copy) NSString *auto_renew_product_id;
/**
The current price consent status for a subscription price increase.
“1” - Customer has agreed to the price increase. Subscription will renew at the higher price.
“0” - Customer has not taken action regarding the increased price. Subscription expires if the customer takes no action before the renewal date.
This key is only present for auto-renewable subscription receipts if the subscription price was increased without keeping the existing price for active subscribers. You can use this value to track customer adoption of the new price and take appropriate action.
*/
@property (nonatomic, assign) NSInteger price_consent_status;
*自動(dòng)續(xù)期訂閱
1)启摄、自動(dòng)續(xù)費(fèi)
購買流程上稿壁,自動(dòng)續(xù)費(fèi)訂閱與普通購買沒有區(qū)別;
主要的區(qū)別在于:除了第一次購買行為是用戶主動(dòng)觸發(fā)的歉备。后續(xù)續(xù)費(fèi)都是Apple自動(dòng)完成的傅是,一般在要過期的前24小時(shí)開始,蘋果會(huì)嘗試扣費(fèi),扣費(fèi)成功的話 會(huì)在APP下次啟動(dòng)的時(shí)候主動(dòng)推送給APP喧笔。
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
添加上面的監(jiān)聽就是非常必要的了帽驯。
如何處理首次訂閱以及續(xù)費(fèi)訂閱?
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://交易完成
// 訂閱特殊處理
if(transaction.originalTransaction){
// 如果是自動(dòng)續(xù)費(fèi)的訂單originalTransaction會(huì)有內(nèi)容
}else{
// 普通購買书闸,以及 第一次購買 自動(dòng)訂閱
}
break;
case SKPaymentTransactionStateFailed: //交易失敗
break;
case SKPaymentTransactionStateRestored: //已經(jīng)購買過該商品
break;
case SKPaymentTransactionStatePurchasing: //商品添加進(jìn)列表
break;
default:
break;
}
}
}
關(guān)鍵點(diǎn): 上面代碼可以看到尼变,通過transaction.originalTransaction
來判斷是否為續(xù)費(fèi)訂單,通過這個(gè)知識(shí)浆劲,對之后的支付統(tǒng)計(jì)及付費(fèi)跟蹤非常關(guān)鍵嫌术。
2)、推介促銷價(jià)(目前比較流行的套路)
主要分:隨用隨付牌借、隨用隨付度气、免費(fèi)試用
a、隨用隨付
如果您選擇“隨用隨付”膨报,則顧客將為選定時(shí)限的每個(gè)結(jié)算周期支付推介促銷價(jià)(例如磷籍,訂閱的標(biāo)準(zhǔn)價(jià)格為 9.99 美元,推介促銷價(jià)為前 3 個(gè)月每月 1.99 美元)现柠≡毫欤可設(shè)定以下時(shí)限:
1 周訂閱,1 至 12 周
1 個(gè)月訂閱够吩,1 至 12 個(gè)月
2 個(gè)月訂閱栅盲,2、4废恋、6、8扒寄、10 和 12 個(gè)月
3 個(gè)月訂閱鱼鼓,3、6该编、9 和 12 個(gè)月
6 個(gè)月訂閱迄本,6 和 12 個(gè)月
1 年訂閱,1 年
b课竣、提前支付
如果您選擇“提前支付”嘉赎,顧客將一次性支付選定時(shí)限的推介促銷價(jià)(例如,訂閱的標(biāo)準(zhǔn)價(jià)格為 9.99 美元于樟,推介促銷價(jià)為前 2 個(gè)月 1.99 美元)公条。可設(shè)定以下時(shí)限:1 個(gè)月迂曲、2 個(gè)月靶橱、3 個(gè)月、6 個(gè)月或 1 年。
c关霸、免費(fèi)試用
如果您選擇“免費(fèi)試用”传黄,則顧客在選定的時(shí)限內(nèi)免費(fèi)訪問訂閱。時(shí)限可以是 3 天队寇、1 周膘掰、2 周、1 個(gè)月佳遣、2 個(gè)月识埋、3 個(gè)月、6 個(gè)月或 1 年苍日。
推介促銷價(jià)是為回饋用戶的一個(gè)促銷方式惭聂,Apple推出后很受APP開發(fā)的歡迎。
當(dāng)然也是非常流行的套路相恃,我們了解一下這個(gè)地方套路的核心問題:
拿免費(fèi)試用來說辜纲,用戶一旦點(diǎn)擊了免費(fèi)試用后,免費(fèi)試用結(jié)束后拦耐,蘋果將自動(dòng)進(jìn)行扣款耕腾;
那么如果試用后不想購買而想退款的話,找到取消的地方就需要靠智商了杀糯,取消免費(fèi)試用的路徑隱藏的非常深扫俺。
四、內(nèi)購的測試問題
1)固翰、沙盒測試:非正式環(huán)境下測試需要添加沙盒測試員
您可以使用沙箱技術(shù)測試您的 App 和 App 內(nèi)購買項(xiàng)目狼纬,而無需創(chuàng)建財(cái)務(wù)交易。沙箱技術(shù)是一個(gè)使用 App Store 基礎(chǔ)架構(gòu)但不處理實(shí)際付款的測試環(huán)境骂际。它會(huì)返回交易疗琉,付款被視為已成功處理。
添加方式:
自動(dòng)續(xù)費(fèi)測試時(shí)需注意:
意思就是歉铝,沙箱環(huán)境 自動(dòng)續(xù)費(fèi)時(shí)間縮短了盈简,一周 對應(yīng) 三分鐘,一月 對應(yīng) 五分鐘太示。柠贤。。
購買完一個(gè)一周 類型訂閱类缤,就不要在APP不退出的情況等待了臼勉,必須3分鐘 或是 10分鐘后重新登錄,Apple才會(huì)主動(dòng)告知你結(jié)果餐弱,也就是第一點(diǎn)提到的坚俗。
沙箱環(huán)境自動(dòng)續(xù)費(fèi)是一定會(huì)自動(dòng)續(xù)費(fèi)的嗎镜盯?
不一定的,有時(shí)候會(huì)猖败,有時(shí)候不會(huì)速缆。所以要多測測,多建幾個(gè)測試賬號(hào)恩闻。
2)艺糜、若發(fā)現(xiàn)測試的商品無法進(jìn)行購買,或者無法調(diào)起付費(fèi)幢尚,可以檢驗(yàn)商品是否存在破停,或者是否正確等問題。
五尉剩、審核問題
添加自動(dòng)訂閱真慢,必須在訂閱路徑內(nèi)需包含以下信息:
1)、隱私協(xié)議及關(guān)于App的內(nèi)容
2)理茎、暴露自動(dòng)續(xù)費(fèi)的信息
– Information about the auto-renewable nature of the subscription
– Links to the privacy policy and terms of use