蘋(píng)果應(yīng)用內(nèi)購(gòu)買的自動(dòng)續(xù)訂訂閱,主要有三種優(yōu)惠方式珍剑,三種可以同時(shí)提供掸宛。
- 推介優(yōu)惠(Introductory Offers)
- 促銷優(yōu)惠(Promotional Offers)
- 優(yōu)惠代碼(Offer Codes)
其中促銷優(yōu)惠(Promotional Offer)是蘋(píng)果在 2019 年出的一種促銷優(yōu)惠方案。
最近開(kāi)發(fā)的時(shí)候發(fā)現(xiàn)招拙,網(wǎng)上幾乎沒(méi)有相關(guān)的文章唧瘾,所以記錄一下,方便其他人更快地實(shí)現(xiàn)别凤。
文章中提到的一些文檔和鏈接都可以在最后一章“附錄”中找到饰序。
關(guān)于應(yīng)用內(nèi)購(gòu)買,可以查看我另一篇文章 iOS In-App Purchase(IAP) 流程與實(shí)現(xiàn)规哪。
一求豫、三種優(yōu)惠的區(qū)別
蘋(píng)果在文檔中介紹了幾種優(yōu)惠的區(qū)別:
- 英文 Auto-renewable subscriptions - providing-subscription-offers
- 中文 自動(dòng)續(xù)期訂閱 - 在 App 中實(shí)現(xiàn)推介促銷優(yōu)惠
跟產(chǎn)品溝通時(shí),需要了解產(chǎn)品想要的是哪種優(yōu)惠。網(wǎng)上對(duì)三種優(yōu)惠的翻譯都各不相同蝠嘉。
二最疆、實(shí)現(xiàn)
下面主要講下客戶端的實(shí)現(xiàn),服務(wù)端可以參考其他文檔蚤告。
2.1 配置
- 自動(dòng)續(xù)訂訂閱的優(yōu)惠設(shè)置說(shuō)明
為自動(dòng)續(xù)期訂閱設(shè)置推介促銷優(yōu)惠
為自動(dòng)續(xù)期訂閱設(shè)置促銷優(yōu)惠
為自動(dòng)續(xù)期訂閱設(shè)置優(yōu)惠代碼
蘋(píng)果官方文檔已經(jīng)詳細(xì)說(shuō)明了如何配置和各種配置的注意點(diǎn)努酸,這里就不再贅述和截圖說(shuō)明了。
對(duì)于促銷優(yōu)惠杜恰,需要生成購(gòu)買項(xiàng)目密鑰(文檔中有說(shuō)明)获诈,然后下載私有密鑰,后續(xù)需要用到心褐。只能下載一次烙荷,請(qǐng)妥善保管已下載的密鑰。
2.2 客戶端開(kāi)發(fā)
2.2.1 推介優(yōu)惠
是否享有推介優(yōu)惠檬寂,是由蘋(píng)果根據(jù) Apple 賬號(hào)決定的终抽。
不同產(chǎn)品希望的享有邏輯會(huì)不同,根據(jù)產(chǎn)品策略不同桶至,會(huì)有不一樣的開(kāi)發(fā)流程昼伴。
我們是最簡(jiǎn)單的場(chǎng)景,新用戶都可以享受到推介優(yōu)惠镣屹,不處理用戶切換 Apple 賬號(hào)的場(chǎng)景圃郊。
客戶端不用開(kāi)發(fā),配置后女蜈,點(diǎn)擊購(gòu)買持舆,系統(tǒng)的購(gòu)買彈窗上就會(huì)顯示出優(yōu)惠信息。復(fù)雜的業(yè)務(wù)邏輯在后端伪窖。
2.2.2 促銷優(yōu)惠
購(gòu)買商品時(shí)可以傳入商品支持的訂閱優(yōu)惠逸寓,在支付彈窗中就會(huì)顯示相關(guān)信息。
2.2.2.1 生成優(yōu)惠 SKPaymentDiscount
購(gòu)買商品時(shí)覆山,需要先生成一個(gè)優(yōu)惠 SKPaymentDiscount竹伸。我們看下 SKPaymentDiscount 的初始化方法:
public init(identifier: String, keyIdentifier: String, nonce: UUID, signature: String, timestamp: NSNumber)
初始化方法中需要幾個(gè)字段:
identifier
A string used to uniquely identify a discount offer for a product.
優(yōu)惠 ID,蘋(píng)果后臺(tái)新建的優(yōu)惠最后的字段
在 APP - 分發(fā) - 營(yíng)利(訂閱)- 點(diǎn)擊訂閱組 - 點(diǎn)擊某個(gè)訂閱 - 訂閱價(jià)格(有效的訂閱優(yōu)惠)- 點(diǎn)擊優(yōu)惠keyIdentifier
A string that identifies the key used to generate the signature.
密鑰ID簇宽,蘋(píng)果后臺(tái)新建的密鑰的ID
在 用戶和訪問(wèn) - 集成 - 密鑰(APP 內(nèi)購(gòu)買項(xiàng)目)- 密鑰 IDnonce
A universally unique ID (UUID) value that you define.
UUID勋篓,服務(wù)器生成
這種格式 58780c93-31e0-4a21-af9c-a34fec006c73。python 里是調(diào)用 uuid.uuid4()魏割。signature
A string representing the properties of a specific promotional offer, cryptographically signed.
簽名譬嚣,服務(wù)器生成timestamp
The date and time of the signature's creation in milliseconds, formatted in Unix epoch time.
服務(wù)器時(shí)間戳,單位毫秒
let discount = SKPaymentDiscount(identifier: xxx, keyIdentifier: xxx, nonce: xxx, signature: xxx, timestamp: NSNumber(integerLiteral: xxx))
- 使用 python 生成簽名進(jìn)行自測(cè)
先將上一章提到的“私有密鑰”(SubscriptionKey_XXXXXXXXXX.p8)從 .p8 格式轉(zhuǎn)成 .der 格式:
openssl pkcs8 -nocrypt -in SubscriptionKey_xxxxxxxx.p8 -out cert.der -outform der
再將以下 python 腳本保存在同個(gè)目錄中钞它,修改其中的 bundle_id拜银、key_id殊鞭、product、offer盐股、application_username 并執(zhí)行。
腳本來(lái)自參考的文章耻卡,新增和修改了部分注釋
# pip3 install ecdsa
import json
import uuid
import time
import hashlib
import base64
from ecdsa import SigningKey
from ecdsa.util import sigencode_der
bundle_id = 'com.xxx.xxx' # bundle ID
key_id = 'XXXXXXXXXX' # 私鑰 ID
product = 'sp_3' # 訂閱商品 ID
offer = '3day_test' # 優(yōu)惠 ID
application_username = '' # Should be the same you use when making purchases
nonce = uuid.uuid4()
timestamp = int(round(time.time() * 1000))
payload = '\u2063'.join([bundle_id,
key_id,
product,
offer,
application_username,
str(nonce), # Should be lower case
str(timestamp)])
# Read the key file
with open('cert.der', 'rb') as myfile:
der = myfile.read()
signing_key = SigningKey.from_der(der)
signature = signing_key.sign(payload.encode('utf-8'),
hashfunc=hashlib.sha256,
sigencode=sigencode_der)
encoded_signature = base64.b64encode(signature)
print(str(encoded_signature, 'utf-8'), str(nonce), str(timestamp), key_id)
控制臺(tái)打印結(jié)果中疯汁,第一個(gè)為簽名,第二個(gè)為 nonce卵酪,第三個(gè)為 timestamp幌蚊,第四個(gè)為 私鑰 ID。此時(shí)將所有信息寫(xiě)死在代碼中就可以自測(cè)購(gòu)買流程了溃卡。
2.2.2.2 使用優(yōu)惠購(gòu)買
/// StoreKit
let payment = SKMutablePayment(product: product)
payment.applicationUsername = usernameHash
payment.paymentDiscount = discountOffer
SKPaymentQueue.default().add(payment)
/// SwiftyStoreKit
SwiftyStoreKit.purchaseProduct(product, quantity: 1, paymentDiscount: paymentDiscount, completion: { [weak self] result in
})
其中 product 需要自行去獲取溢豆,下面是使用 StoreKit 和 SwiftyStoreKit 去獲取的代碼:
/// StoreKit
let productRequest = SKProductsRequest(productIdentifiers: Set<String>(arrayLiteral: productId))
productRequest.delegate = self
productRequest.start()
extension XXX: SKProductsRequestDelegate {
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
if let product = response.products.first { /// 獲取返回的商品
}
}
}
/// SwiftyStoreKit
SwiftyStoreKit.retrieveProductsInfo([productId], completion: { result in
if let product = result.retrievedProducts.first {
}
})
2.2.3 優(yōu)惠代碼
優(yōu)惠代碼比較簡(jiǎn)單,就不贅述瘸羡,附錄中有官方的相關(guān)文檔可以查閱漩仙。
三、附錄
官方 - 自動(dòng)續(xù)期訂閱 - 在 App 中實(shí)現(xiàn)推介優(yōu)惠(介紹文檔)
英文 Auto-renewable subscriptions - providing-subscription-offers
中文 自動(dòng)續(xù)期訂閱 - 在 App 中實(shí)現(xiàn)推介促銷優(yōu)惠官方 - 推介優(yōu)惠(開(kāi)發(fā)文檔)
中文 在 App 中實(shí)現(xiàn)推介促銷優(yōu)惠
英文 implementing_introductory_offers_in_your_app官方 - 促銷優(yōu)惠(開(kāi)發(fā)文檔)
setting_up_promotional_offers
implementing_promotional_offers_in_your_app
generating_a_signature_for_promotional_offers
generating_a_promotional_offer_signature_on_the_server官方 - 優(yōu)惠代碼(開(kāi)發(fā)文檔)
implementing_offer_codes_in_your_app官方 - 自動(dòng)續(xù)訂訂閱的優(yōu)惠設(shè)置說(shuō)明(說(shuō)明文檔)
為自動(dòng)續(xù)期訂閱設(shè)置推介促銷優(yōu)惠
為自動(dòng)續(xù)期訂閱設(shè)置促銷優(yōu)惠
為自動(dòng)續(xù)期訂閱設(shè)置優(yōu)惠代碼官方 - ReceiptFields
-
蘋(píng)果內(nèi)購(gòu)之推介促銷優(yōu)惠和訂閱優(yōu)惠
優(yōu)惠對(duì)比.jpg