プログラミング

エンジョイSwiftUIプログラミングその8(課金2:自動更新サブスクリプション)

今回は課金の2回目です。アプリ内継続課金の実装法について書いてみたいと思います。

手順

  1. Sandboxテスターの設定
  2. iOSデバイス(iPhone等)のAppStoreのSandboxアカウントの設定
  3. AppleStoreConnectアプリ内課金設定(プロダクトIDとApp用共有シークレットの取得)
  4. Cocoapodsの設定
  5. アプリ内課金のApp内での表示設定のガイド
  6. アプリ内コード(InAppPurchaseFlag, purchase関数、verifyPurchase関数)とAppDelegateの設定
  7. 実際の継続購入の画面

1.Sandboxテスターの設定

まずApple Store Connectにいきサインインします。(設定の仕方は前回のその7を参照してください)

そして、「ユーザーとアクセス」を選択し、画面が変わったら「Sandboxテスター」を選択します。そして、「+」ボタンを押してSandboxテスターのApple IDをいれて登録します。このIDは普段使っているApple IDとは別のものを入力します。

2.iOSデバイス(iPhone等)のAppStoreのSandboxアカウントの設定

次にテストする実機の設定をします。下の画面に沿って、App StoreのSANDBOXアカウントを先ほど登録したSandboxテスターのApple IDに設定します。

3.AppleStoreConnectアプリ内課金設定(プロダクトIDとApp用共有シークレットの取得)

App Store Connectに戻って、登録しておいた「マイApp」に戻ります。App内課金のセクションに行ってApp内課金の「+」をクリックして、新たな課金を登録します。

自動更新サブスクリプションを選択し、その後適当に「参照名」と「製品ID(重要:これが後に必要になりますのでメモしておきます)」を入力します。

その後、課金に必要な情報を入力していきます。ちなみに、App Storeプロモーションの赤枠のアイコンはアプリアイコンと同一では審査でリジェクトされるので、ユニークなアプリアイコンにする必要があります。また、審査に関する情報のスクリーンショットは実際の審査では課金画面を添付する必要がありますが、当面は適当なスクリーンショットを入力します。そして、他の空欄も「メタ情報が不足」と表示されないように全て入力します。

そして、サブスクリプション価格を入力します。また、最初の1ヶ月をトライアル(お試しオファー)を無料にするために「お試しオファー」でも設定すると良いです。

そしてApp内課金に戻って、赤枠の「App用共有シークレット」をクリックして今度は「共有シークレット」を取得します(重要:これもメモしておきます)。

4.Cocoapodsの設定

次にMacに戻り、Macに 「Cocoapods」を導入します。簡単に課金を実装するためのフレームワークである「SwiftyStoreKit」を導入するためです。

まず、Macのた「ターミナル」を開き、Cocapodsを導入するためのコマンドを入力します。

$ sudo gem update --system -n /usr/local/bin

$ sudo gem install -n /usr/local/bin cocoapods

$ pod setup

「マイApp」に登録していたXcodeのプロジェクトファイルのフォルダーを確認します。

そして、ターミナルから以下のようにコマンドを入力していきます。cd の後のプロジェクトのディレクトリはフォルダをドラッグしてドロップすると良いです。参考のためターミナルの実行結果とプロジェクトフォルダの状態の図も添付します。

ターミナルを開く

$ cd プロジェクトのディレクトリ
$ ls で内容を確認して
$ pod init
 
新しくできたpodファイルを開く
pod 'SwiftyStoreKit'
endの上にこれを書いて保存する


ターミナルに戻り
$ pod install
終わったら、
$ exit

ここで、白色のProject fileが作成されたことを確認してください。そして、この白いプロジェクトファイルでこの後コードを書いていきます。確認のため白いProject file を開いて、SwiftyStoreキットがインストールされていることを確認して下さい。

5.アプリ内課金のApp内での表示設定のガイド

では、これからはコードレベルでの実装について説明します。この実装についてはAppleの「自動更新サブスクリプションガイドライン」があります。

この中で、いくつか決まりがあります。特に審査の際にリジェクトされたのは、アプリが最初に起動した際に課金画面を表示してその内容を説明するようプログラミングする条件です。ですので、起動時に課金画面がでるようにコードする必要があります。

6.アプリ内コード(InAppPurchaseFlag, purchase関数、verifyPurchase関数)とAppDelegateの設定

では、実際のコードを見てみましょう。まず、SwiftyStoreKitを使うSwiftファイルでは「import SwiftyStoreKit」を先頭に入力します。

まずは課金に必要な道具として、課金のためのinAppPurchaseFlagフラグとpurchase関数とverifyPurchase関数を準備します。ここで最初にメモしておいた「製品ID(Product ID)」と「共有シークレット(sharedSecret)」を使用するので準備しておいてください。

//
//  InAppPurchaseView.swift
//  bFaaaPPager1
//
//  Created by 宍戸知行 on 2020/01/15.
//  Copyright © 2020 宍戸知行. All rights reserved.
//

import SwiftUI
import SwiftyStoreKit

//定期購読のためのフラグ

public var inAppPurchaseFlag = false


//InAppPurchase関数

//Purchaseの関数

func purchase (with PRODUCT_ID: String) {
    
    SwiftyStoreKit.purchaseProduct(PRODUCT_ID) { (result) in
        
        switch result {
            
        case .success(_):
            //購入が成功
            UserDefaults.standard.set(1, forKey: "buy")
            inAppPurchaseFlag = true
            //購入を検証
            verifyPurchase(with: PRODUCT_ID)
            
            break
            
        case .error(_):
            //購入失敗
            print("購入失敗errorです")
            break
        }
        
    }
    
}


func verifyPurchase (with PRODUCT_ID:String){
    
    let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "****************" )
    SwiftyStoreKit.verifyReceipt(using: appleValidator) {(result) in
        
        switch result {
            
        case .success(let receipt):
            
            //自動更新
            let purchaseResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: PRODUCT_ID, inReceipt: receipt)
            
            switch purchaseResult {
                
            case .purchased:
                
                UserDefaults.standard.set(1, forKey: "buy")
                inAppPurchaseFlag = true
                
                
            case .notPurchased:
                break
                
            case .expired( _, _):
                UserDefaults.standard.set(nil, forKey: "buy")
                inAppPurchaseFlag = false
                
               
                
            }
            
        case .error(let error):
            print (error)
            
        }
        
        
    }
}

では、まず、AppDelegateに記載するコードです。

//
//  AppDelegate.swift
//  bFaaaPPager1
//
//  Created by 宍戸知行 on 2019/11/15.
//  Copyright © 2019 宍戸知行. All rights reserved.
//

import UIKit
import SwiftyStoreKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        //SwiftyStoreKitの準備
        SwiftyStoreKit.completeTransactions(atomically: true) { (purchases) in
            
            for purchase in purchases {
                switch purchase.transaction.transactionState {
                case .purchased, .restored:
                    if purchase.needsFinishTransaction {
                        SwiftyStoreKit.finishTransaction(purchase.transaction)
                    }
                case .purchasing, .failed, .deferred:
                    break
                @unknown default:
                    print("unknown purchase error")
                }
            }
            
        }
        
        
        
        return true
    }

では、先ほど説明したように最初の起動画面(本アプリではListView.swift)に初回時にアプリ購入画面を表示するように、@State変数のフラグを準備して継続課金購入画面を出すようにします。

その購入画面は、例えば下のようなものです。

では、どこで購入を判断するのかですが、onAppearで画面が表示される際に、verifyPuchase関数とpurchase関数を以下のようにして使用するとよいでしょう。

  }//購入画面の最後のView
            }//ZStackの最後の}
                .onAppear{
                    
                    //まずinAppPurchaseを判断する
                    //receiptチェックする
                    verifyPurchase(with: "Product ID ***")
                   
                    if UserDefaults.standard.object(forKey: "buy") != nil {
                        
                        let count = UserDefaults.standard.object(forKey: "buy") as! Int
                        if count == 1 {
                            inAppPurchaseFlag = true
                        }
                        
                    } else {
                        inAppPurchaseFlag = false
                    }
                    
                    
                    
                    guard inAppPurchaseFlag  else {
                        
                        purchase(with: "Product ID ***")
                        
                        return
                    }
                    
                    print("InAppPurchaseがあります。inAppPurchaseFlagは\(inAppPurchaseFlag)す。")
                    
                   
                    //State変数に代入して画面を変更する
                    self.stateInAppPurchaseFlag = inAppPurchaseFlag
                    
                  

7.実際の継続購入の画面

では、これでアプリ内継続課金の実装ができたと思います。実際に実機で試してみましょう(シュミュレーターでは動作しません)。また、最初にSandboxテスターを設定しているので、そのままお手元のiPhone等でも普段お使いのApple IDを変更せずにテストすることができます。ちなみにTestFlightで課金をテストする場合はSandboxテスターでなくても課金のテストができます。では、実際の課金画面です。

今回は長くなりましたが、これでおしまいです。

関連記事一覧

コメント

この記事へのコメントはありません。