MerchantKit 0.14.0

MerchantKit 0.14.0

Benjamin MayoBenjamin Mayo 维护。



  • Benjamin Mayo

MerchantKit

一个面向 iOS 开发的现代 In-App Purchases 管理框架。

MerchantKit 极大地简化了独立开发者为了向应用添加付费组件所做的工作,包括跟踪已购买的产品、提供自动续订订阅、恢复交易等。

MerchantKit 专为具有有限购买产品集合的应用设计,是向应用添加一次性购买或持续订阅的“专业版”的绝佳方式。

示例代码片段

确定产品是否已购买

let product = merchant.product(withIdentifier: "iap.productidentifier")
print("isPurchased: \(merchant.state(for: product).isPurchased))"

购买产品

let task = merchant.commitPurchaseTask(for: purchase)
task.onCompletion = { result in 
    switch result {
        case .succeeded(_):
            print("purchase completed")
        case .failed(let error):
            print("\(error)")
    }
}

task.start()

当订阅过期时收到通知

public func merchant(_ merchant: Merchant, didChangeStatesFor products: Set<Product>) {
    if let subscriptionProduct = products.first(where: { $0.identifier == "subscription.protier" }) {
        let state = merchant.state(for: subscriptionProduct)
        
        switch state {
            case .isPurchased(let info):
                print("subscribed, expires \(info.expiryDate)")
            default:
                print("does not have active subscription")
        }
    }
}

项目目标

  • 直观简练的 API,支持非消耗性、消耗性和订阅内购。
  • 简化了应用程序中内购界面的开发,包括用于动态创建例如“每月 £2.99”或“七天免费试用”等字符串的本地化格式化程序。
  • 除苹果 iOS 随附的组件外,无外部依赖。该项目链接 FoundationStoreKitSystemConfigurationos 用于日志记录。
  • 优先考虑开发者的便利性和可访问性,而非安全性。MerchantKit 用户承认一定程度的盗版是不可避免的,不值得追查。
  • 宽宏大量的开源许可证。
  • 使用惯用语言结构与最新版本的 Swift 兼容。

当前的代码库处于不断变化中,该项目不保证 API 的稳定性。尽管如此,MerchantKit 是有用的、有效的,并且可能会为您节省时间。但话虽如此,MerchantKit 还远远没有完成。测试套件尚不完善。

安装

CocoaPods

要使用CocoaPods将MerchantKit集成到您的Xcode项目中,请在您的Podfile中指定它。

pod 'MerchantKit'

Carthage

要使用Carthage将MerchantKit集成到您的Xcode项目中,请在您的Cartfile中指定它。

github "benjaminmayo/merchantkit"

手动

编译MerchantKit框架并将其嵌入到您的应用程序中。您可以从Github下载源代码并将Xcode项目嵌入到您的应用程序中,但您需要手动升级到最新版本。

入门指南

  1. 在您的应用程序代理中导入 MerchantKit并在 application(_:, didFinishLaunchingWithOptions:)中创建一个 Merchant实例。提供一个配置(如 Merchant.Configuration.default)和一个代理。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    ...
    
    self.merchant = Merchant(configuration: .default, delegate: self)
    
    ...
}
  1. 尽快注册产品(通常在 application(_:, didFinishLaunchingWithOptions:)中)。您可能希望从文件中加载 Product结构,或者简单地以常量的形式在代码中声明它们。然后,这些常量可以在以后静态访问。
let product = Product(identifier: "iap.productIdentifier", kind: .nonConsumable)
let otherProduct = Product(identifier: "iap.otherProductIdentifier", kind: .subscription(automaticallyRenews: true)) 
self.merchant.register([product, otherProduct])
  1. 在脱离 application(_:, didFinishLaunchingWithOptions:)方法之前,在商家实例上调用 setup()。这告诉商家开始观察支付队列。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    ...
    
    self.merchant = Merchant(configuration: .default, delegate: self)    
    self.merchant.register(...)
    self.merchant.setup()
    
    ...
}
  1. 利润!或者something.

商户配置

Merchant 使用配置对象初始化;一个 Merchant.Configuration 的实例。该配置控制了如何验证收据并将产品状态持久化到存储。大多数应用程序可以直接使用 Merchant.Configuration.default 并获得预期的结果。如果您需要更定制化的功能,可以提供自己的 Merchant.Configuration

提示:MerchantKit 提供了一个内置的配置 Merchant.Configuration.usefulForTestingAsPurchasedStateResetsOnApplicationLaunch。在开发过程中,用于测试购买流程,因为这个配置不会将购买状态持久化到永久存储。您只需重新启动应用程序,就可以反复测试“购买”任何 Product,包括非消耗品。正如其难以记的名字所示,您不应该在生产应用程序中使用此配置。

商户代理

代理实现 MerchantDelegate 协议。该代理提供了在应用全局级别响应事件的途径。该 MerchantDelegate 协议声明了一些方法,但只需实现其中一个。

func merchant(_ merchant: Merchant, didChangeStatesFor products: Set<Product>) {
    // Called when the purchased state of a `Product` changes.
    
    for product in products {
        print("updated \(product)")
    }
}

代理可以选择接收加载状态更改事件以及处理由 App Store 外部发起的推广内购流程的定制化处理点。这两个方法的合理默认实现已经被提供。

产品接口控制器

Merchant 提供的任务让开发者可以通过反映 Swift 语法特性的接口访问核心的获取和购买产品操作。许多应用程序不需要直接实例化任务。ProductInterfaceController 是由 MerchantKit 提供的一个较高级别的 API,覆盖了许多项目的用例。在一个 iOS 应用中,用于显示升级界面的视图控制器将由一个单一 ProductInterfaceController 支持,该控制器封装了所有必要的产品和购买逻辑。

ProductInterfaceController 类包括展示 In-App Purchase 所需的常见行为。然而,它仍然足够抽象,不会固定于某种特定的用户界面外观或布局。

开发者只需提供要显示的产品列表,并告诉控制器获取数据。控制器通过 delegate 通知应用程序何时更新其自定义 UI。它处理数据加载、间歇性网络连接以及产品可用性和状态的变化。

请参阅示例项目,了解ProductInterfaceController的基本实现。

格式化工具

MerchantKit 包含了几个格式化工具,以帮助开发者向用户展示应用内购的价格。

PriceFormatter 是最简单的。只需给它一个Price对象,它就会返回如 '£3.99' 或 '$5.99' 的格式化字符串,遵循商店的区域设置。如果价格免费,您可以指定一个自定义字符串。SubscriptionPriceFormatter 接收一个 Price 和一个 SubscriptionDuration。相关的 Purchase 对象公开这些值,因此您可以轻松地将它们传递给格式化工具。它根据周期和订阅是否会自动续订生成如 '$0.99每月','£9.99每两周' 和 '$4.99一个月' 的字符串。

除了续订周期,订阅还可以包含免费试用期和其他促销活动。您可以使用SubscriptionPeriodFormatter来格式化应用程序中的文本标签。如果您在 iTunes Connect 中更改免费试用优惠,则标签将动态更新以反映更改的条款,而无需新的 App Store 二进制文件。例如

func subscriptionDetailsForDisplay() -> String? {
    guard let terms = purchase.subscriptionTerms, let introductoryOffer = terms.introductoryOffer else { return nil }
    
    let formatter = SubscriptionPeriodFormatter()
    
    switch introductoryOffer {
        case .freeTrial(let period): return "\(formatter.string(from: period)) Free Trial" // something like '7 Day Free Trial'
        default: ...
    }
}

PriceFormatter 在 App Store 支持的每个区域设置中都能使用。SubscriptionPriceFormatterSubscriptionPeriodFormatter 目前仅供少数语言使用。欢迎提供自愿翻译。

请参阅示例项目,该项目中可以实验 PriceFormatterSubscriptionPriceFormatter 的各种配置选项。

消耗型产品

Merchant 跟踪非消耗型和订阅产品的购买状态。消耗型产品被认为是过渡性购买,不会在首次购买时间之后记录。由于其特殊性质,必须以不同的方式处理。在创建 Merchant 时确保提供consumableHandler。这可以是任何符合 MerchantConsumableProductHandler 协议的对象。该协议有一个必需的方法

func merchant(_ merchant: Merchant, consume product: Product, completion: @escaping () -> Void) {
    self.addCreditsToUserAccount(for: product, completion: completion) // application-specific handling 
}

Merchant 将始终报告消耗型产品的状态为 PurchasedState.notPurchased。忘记实现代理方法会导致运行时致命错误。

待完成(无特定顺序)

  • 增加 SubscriptionPriceFormatterSubscriptionPeriodFormatter 的本地化数量。
  • 在示例项目中添加了大量文档,包括更多示例。
  • 支持内置购买可下载内容。
  • 可能还有很多我还没想出来的功能。

鸣谢

Benjamin Mayo 开发和管理,Twitter上的 @bzamayo