しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

StoreKit2のサンプルコードを動かしてみる

今回は下URLからダウンロードできるStoreKit2のサンプルコードを動かしてみました。

developer.apple.com

StoreKit2は旧来のStoreKitを改良したもので、シンプルなコードで購入処理が記述できるようになっています。
ただしiOS15限定以上なので利用する際はアプリの対象OSを15以上にするか旧StoreKitと併用する必要があります。

StoreKitの概要 - Apple Developer

StoreKit2の処理

商品情報の取得方法は下の通りです。
こちらはサンプルコードを少し分かりやすく改変したものになります。
StoreKit2ではawaitを使う事でブロックやDelegateを使わずに取得できるようになりました。

let products = try? await Product.products(for: ["com.example"])

購入処理下の通りです。
purchaseメソッドだけで購入できるので今までに比べて非常に楽になりそうです。

戻り値の型はVerificationResultなのでswitch文でTransactionを取得してfinishさせています。

func purchase(_ product: Product) async throws -> Transaction? {
    //Begin a purchase.
    let result = try await product.purchase()

    switch result {
    case .success(let verification):
        let transaction = try checkVerified(verification)

        //Deliver content to the user.
        await updatePurchasedIdentifiers(transaction)

        //Always finish a transaction.
        await transaction.finish()

        return transaction
    case .userCancelled, .pending:
        return nil
    default:
        return nil
    }
}

func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
    //Check if the transaction passes StoreKit verification.
    switch result {
    case .unverified:
        //StoreKit has parsed the JWS but failed verification. Don't deliver content to the user.
        throw StoreError.failedVerification
    case .verified(let safe):
        //If the transaction is verified, unwrap and return it.
        return safe
    }
}

過去の購入情報はTransactionのlatestメソッドで取得する事ができます。
購入時同様、VerificationResult型が返ってくるのでswitch文で取得して検証しています。

func isPurchased(_ productIdentifier: String) async throws -> Bool {
    //Get the most recent transaction receipt for this `productIdentifier`.
    guard let result = await Transaction.latest(for: productIdentifier) else {
        //If there is no latest transaction, the product has not been purchased.
        return false
    }

    let transaction = try checkVerified(result)

    //Ignore revoked transactions, they're no longer purchased.

    //For subscriptions, a user can upgrade in the middle of their subscription period. The lower service
    //tier will then have the `isUpgraded` flag set and there will be a new transaction for the higher service
    //tier. Ignore the lower service tier transactions which have been upgraded.
    return transaction.revocationDate == nil && !transaction.isUpgraded
}

func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
    //Check if the transaction passes StoreKit verification.
    switch result {
    case .unverified:
        //StoreKit has parsed the JWS but failed verification. Don't deliver content to the user.
        throw StoreError.failedVerification
    case .verified(let safe):
        //If the transaction is verified, unwrap and return it.
        return safe
    }
}

まとめ

簡単に動かしてみましたが従来に比べて処理がシンプルになりそうで良かったです。
シンプルんになっただけでなく返金対応が増えていたり継続課金の検証が簡単だったりするようなので実際に使う時は更に詳しく調べていきたいと思いました。