轉(zhuǎn)載于:https://15tar.com/ios/2017/10/09/convert-paid-app-to-freemium-with-iap.html
前段時(shí)間上線(xiàn)我的第一個(gè)收費(fèi)App——瓦工助手,雖然有下載酷师,但一天一兩個(gè)的下載量實(shí)在是有點(diǎn)太少脾猛。于是打算把付費(fèi)下載改成付費(fèi)加應(yīng)用內(nèi)購(gòu)買(mǎi)的模式,看看下載量和收益是否有提升蹬跃。下面記錄一下將收費(fèi)改成免費(fèi)加內(nèi)購(gòu)的最佳實(shí)現(xiàn)方式宗挥。
因?yàn)槭侵笆歉顿M(fèi)下載的靶壮,讓已購(gòu)買(mǎi)的用戶(hù)再來(lái)應(yīng)用內(nèi)購(gòu)買(mǎi)是不合適的维费,所以需要解決的一個(gè)核心問(wèn)題是如何識(shí)別用戶(hù)是否已經(jīng)購(gòu)買(mǎi)過(guò)App果元。
Apple提供了API(appStoreReceiptURL)可以獲取App購(gòu)買(mǎi)的Receipt,包括App購(gòu)買(mǎi)和In App Purchase犀盟,具體文檔可以參考官方的 Receipt Validation Programming Guide 而晒。簡(jiǎn)單來(lái)說(shuō),appStoreReceiptURL會(huì)返回App的購(gòu)買(mǎi)的版本(original_application_version)及應(yīng)用內(nèi)購(gòu)買(mǎi)的詳細(xì)信息(in_app)阅畴,這里關(guān)鍵的是original_application_version倡怎,它記錄的是用戶(hù)下載App時(shí)的應(yīng)用版本,對(duì)應(yīng)App的CFBundleVersion(注意不是CFBundleShortVersionString)贱枣,而且只在A(yíng)pp Store版本的App上才會(huì)返回正確的值监署,其它情況返回的都是1.0,連TestFlight也是纽哥,這個(gè)很不方便調(diào)試焦匈。
通過(guò)比對(duì)original_application_version與啟用IAP的第一個(gè)版本號(hào)就可以方便的控制是否需要應(yīng)用內(nèi)購(gòu)買(mǎi)了。
如果自己手動(dòng)去請(qǐng)求appStoreReceiptURL獲取receipt信息會(huì)比較麻煩昵仅,這里我使用的是一個(gè)第三方庫(kù):SwiftyStoreKit,大大簡(jiǎn)化了流程,推薦使用摔笤!
使用SwiftyStoreKit只需要下面簡(jiǎn)單的代碼就能夠獲取Receipt信息了:
let appleValidator = AppleReceiptValidator(service: .production)
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: Constants.iapSharedSecret, forceRefresh: false) { result in
switch result {
case .success(let receipt):
log.info("Verify receipt Success: \(receipt)")
let receiptJSON = JSON(receipt)
// 是否之前付費(fèi)下載
if let orignalVersion = receiptJSON["receipt"]["original_application_version"].string,
Int(orignalVersion) ?? 0 < Constants.iapStartVersion {
IAPHelper.markPurchasedApp(purchased: true)
log.info("Already purchased the App")
} else {
IAPHelper.markPurchasedApp(purchased: false)
}
// 是否應(yīng)用內(nèi)購(gòu)買(mǎi)
if let inAppReceipts = receiptJSON["receipt"]["in_app"].array,
inAppReceipts.count > 0 {
IAPHelper.markPurchasedInApp(purchased: true)
log.info("Already in-app purchased")
} else {
IAPHelper.markPurchasedInApp(purchased: false)
}
case .error(let error):
log.error("Verify receipt Failed: \(error)")
}
}
簡(jiǎn)單介紹解釋一下:
-
Constants.iapStartVersion
是內(nèi)購(gòu)開(kāi)始的第一個(gè)版本够滑,如果版本號(hào)小于這個(gè)值說(shuō)明是下載的之前版本,直接跳過(guò)內(nèi)購(gòu)吕世; - 關(guān)于
in_app
的處理彰触,因?yàn)槲业腁pp只有一個(gè)內(nèi)購(gòu)Item,所以這里只判斷了數(shù)組的長(zhǎng)度命辖,你可能需要對(duì)product_id 進(jìn)行更細(xì)致的處理况毅; -
IAPHelper
對(duì)整個(gè)邏輯做了簡(jiǎn)單封裝,詳細(xì)見(jiàn)這個(gè)Gist尔艇,應(yīng)該可以拿來(lái)直接用尔许。
說(shuō)點(diǎn)題外話(huà),瓦工助手從付費(fèi)App改成免費(fèi)加內(nèi)購(gòu)已經(jīng)有一個(gè)星期左右的時(shí)間了终娃,下載量確實(shí)呈指數(shù)級(jí)增長(zhǎng)味廊,但收入?yún)s下降了,這跟我的IAP設(shè)置有關(guān)棠耕,目前我的設(shè)置是管理一臺(tái)VPS免費(fèi)余佛,管理多臺(tái)VPS才需要內(nèi)購(gòu),而大部分用戶(hù)都是只有一臺(tái)VPS的窍荧。所以辉巡,往往產(chǎn)品的設(shè)計(jì)比技術(shù)本身更重要。:)
很多人可能見(jiàn)不到production環(huán)境下的Receipt數(shù)據(jù)到底長(zhǎng)啥樣蕊退,在這里貼一個(gè)出來(lái):
["status": 0, "receipt": {
"adam_id" = 1267833691;
"app_item_id" = 1267833691;
"application_version" = 31;
"bundle_id" = "com.0x1024.Bandwagon";
"download_id" = 62034015496213;
"in_app" = (
{
"is_trial_period" = false;
"original_purchase_date" = "2017-10-08 02:55:13 Etc/GMT";
"original_purchase_date_ms" = 1507431313000;
"original_purchase_date_pst" = "2017-10-07 19:55:13 America/Los_Angeles";
"original_transaction_id" = 220000373453498;
"product_id" = "bangon_iap";
"purchase_date" = "2017-10-08 02:55:13 Etc/GMT";
"purchase_date_ms" = 1507431313000;
"purchase_date_pst" = "2017-10-07 19:55:13 America/Los_Angeles";
quantity = 1;
"transaction_id" = 220000373453498;
}
);
"original_application_version" = 31;
"original_purchase_date" = "2017-10-08 02:47:56 Etc/GMT";
"original_purchase_date_ms" = 1507430876000;
"original_purchase_date_pst" = "2017-10-07 19:47:56 America/Los_Angeles";
"receipt_creation_date" = "2017-10-08 02:55:13 Etc/GMT";
"receipt_creation_date_ms" = 1507431313000;
"receipt_creation_date_pst" = "2017-10-07 19:55:13 America/Los_Angeles";
"receipt_type" = Production;
"request_date" = "2017-10-09 02:35:01 Etc/GMT";
"request_date_ms" = 1507516501916;
"request_date_pst" = "2017-10-08 19:35:01 America/Los_Angeles";
"version_external_identifier" = 823885941;
}, "environment": Production]