美文网首页
iOS 应用内购买的推介优惠、促销优惠、优惠代码的处理

iOS 应用内购买的推介优惠、促销优惠、优惠代码的处理

作者: zackzheng | 来源:发表于2024-03-31 11:10 被阅读0次

    苹果应用内购买的自动续订订阅,主要有三种优惠方式,三种可以同时提供。

    • 推介优惠(Introductory Offers)
    • 促销优惠(Promotional Offers)
    • 优惠代码(Offer Codes)

    其中促销优惠(Promotional Offer)是苹果在 2019 年出的一种促销优惠方案。

    最近开发的时候发现,网上几乎没有相关的文章,所以记录一下,方便其他人更快地实现。
    文章中提到的一些文档和链接都可以在最后一章“附录”中找到。
    关于应用内购买,可以查看我另一篇文章 iOS In-App Purchase(IAP) 流程与实现

    一、三种优惠的区别

    苹果在文档中介绍了几种优惠的区别:

    优惠对比中英.jpg

    跟产品沟通时,需要了解产品想要的是哪种优惠。网上对三种优惠的翻译都各不相同。

    二、实现

    下面主要讲下客户端的实现,服务端可以参考其他文档。

    2.1 配置

    苹果官方文档已经详细说明了如何配置和各种配置的注意点,这里就不再赘述和截图说明了。

    对于促销优惠,需要生成购买项目密钥(文档中有说明),然后下载私有密钥,后续需要用到。只能下载一次,请妥善保管已下载的密钥。

    2.2 客户端开发

    2.2.1 推介优惠

    是否享有推介优惠,是由苹果根据 Apple 账号决定的。
    不同产品希望的享有逻辑会不同,根据产品策略不同,会有不一样的开发流程。

    我们是最简单的场景,新用户都可以享受到推介优惠,不处理用户切换 Apple 账号的场景。
    客户端不用开发,配置后,点击购买,系统的购买弹窗上就会显示出优惠信息。复杂的业务逻辑在后端。

    试用三天

    2.2.2 促销优惠

    购买商品时可以传入商品支持的订阅优惠,在支付弹窗中就会显示相关信息。

    2.2.2.1 生成优惠 SKPaymentDiscount

    购买商品时,需要先生成一个优惠 SKPaymentDiscount。我们看下 SKPaymentDiscount 的初始化方法:

    public init(identifier: String, keyIdentifier: String, nonce: UUID, signature: String, timestamp: NSNumber)
    

    初始化方法中需要几个字段:

    1. identifier
      A string used to uniquely identify a discount offer for a product.
      优惠 ID,苹果后台新建的优惠最后的字段
      在 APP - 分发 - 营利(订阅)- 点击订阅组 - 点击某个订阅 - 订阅价格(有效的订阅优惠)- 点击优惠

    2. keyIdentifier
      A string that identifies the key used to generate the signature.
      密钥ID,苹果后台新建的密钥的ID
      在 用户和访问 - 集成 - 密钥(APP 内购买项目)- 密钥 ID

    3. nonce
      A universally unique ID (UUID) value that you define.
      UUID,服务器生成
      这种格式 58780c93-31e0-4a21-af9c-a34fec006c73。python 里是调用 uuid.uuid4()。

    4. signature
      A string representing the properties of a specific promotional offer, cryptographically signed.
      签名,服务器生成

    5. timestamp
      The date and time of the signature's creation in milliseconds, formatted in Unix epoch time.
      服务器时间戳,单位毫秒

    let discount = SKPaymentDiscount(identifier: xxx, keyIdentifier: xxx, nonce: xxx, signature: xxx, timestamp: NSNumber(integerLiteral: xxx))
    
    • 使用 python 生成签名进行自测

    先将上一章提到的“私有密钥”(SubscriptionKey_XXXXXXXXXX.p8)从 .p8 格式转成 .der 格式:

    openssl pkcs8 -nocrypt -in SubscriptionKey_xxxxxxxx.p8 -out cert.der -outform der
    

    再将以下 python 脚本保存在同个目录中,修改其中的 bundle_idkey_idproductofferapplication_username 并执行。

    脚本来自参考的文章,新增和修改了部分注释

    # 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' # 优惠 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)
    

    控制台打印结果中,第一个为签名,第二个为 nonce,第三个为 timestamp,第四个为 私钥 ID。此时将所有信息写死在代码中就可以自测购买流程了。

    2.2.2.2 使用优惠购买

    /// 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 优惠代码

    优惠代码比较简单,就不赘述,附录中有官方的相关文档可以查阅。

    三、附录

    相关文章

      网友评论

          本文标题:iOS 应用内购买的推介优惠、促销优惠、优惠代码的处理

          本文链接:https://www.haomeiwen.com/subject/xmeptjtx.html