質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

0回答

548閲覧

swiftで課金(IAP)を実装しているのですが分からないことがあります。

po_tato

総合スコア97

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

1クリップ

投稿2017/11/06 03:16

編集2022/01/12 10:55

IOSでアプリ内課金を実装しています。
よくある形のアプリ内で使用できるポイントを課金アイテムとしています。
今までリリースしてきたアプリにも同じ方法で実装していて大半は
うまくいっているのですが(正常に機能している)、
アイテムを購入したのにポイントが反映されないなどのバグも起きているのも現状です。
通信エラーが絡んでたまたま起きたバグかと思っていましたが、最近はそれが多くなって
いるので何かおかしいところがあるのではないかと感じ質問させていただきました。

ちなみにこの課金システムは消耗型で、レシートを自サーバに保存する方法をとっています。
作成したのは自分ではないのですが、このサイトを参考にしたと思われます。
リンク内容

何か問題がある箇所や変更した方がいい箇所などございますでしょうか?
アドバイスを頂ければ幸いでございます。
よろしくお願い致します。

課金部分のソースは以下となります。

override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if SKPaymentQueue.default().transactions.count>0 { for tempTransaction:SKPaymentTransaction in SKPaymentQueue.default().transactions { if tempTransaction.transactionState != .purchasing{ SKPaymentQueue.default().finishTransaction(tempTransaction) } } } } func tap(_ sender:UIGestureRecognizer) { let tag = (sender.view?.tag)! - 1 print(self.productid[tag]) product_id = self.productid[tag] let setdata:Set<String> = [product_id] //アプリ内課金許可されているかチェック if SKPaymentQueue.canMakePayments() { print(SKPaymentQueue.canMakePayments()) let data = SKProductsRequest(productIdentifiers: setdata) data.delegate = self // 購入処理中にUIAlertControllerを表示させる let alert = UIAlertController(title: "処理中", message: "(self.count[tag])コインの購入処理中です", preferredStyle: .alert) present(alert, animated: true, completion: nil) self.alert = alert data.start() } } //課金アイテム取得後に呼ばれるメソッド。didReceiveに取得した情報 func productsRequest(_: SKProductsRequest, didReceive: SKProductsResponse){ let data = didReceive.products let indata = didReceive.invalidProductIdentifiers if indata.count == 0 { SKPaymentQueue.default().add(self) for product_data:SKProduct in data { let request_data = SKPayment(product: product_data) SKPaymentQueue.default().add(request_data) } }else{ print("abcde(indata)") } } func priceStringFromProduct(product: SKProduct!) -> String { let numberFormatter = NumberFormatter() numberFormatter.formatterBehavior = .behavior10_4 numberFormatter.numberStyle = .currency numberFormatter.locale = product.priceLocale return numberFormatter.string(from: product.price)! } func idStringFromProduct(product: SKProduct!) -> String { let numberFormatter = NumberFormatter() numberFormatter.formatterBehavior = .behavior10_4 numberFormatter.numberStyle = .currency //numberFormatter.s = product.productIdentifier return product.productIdentifier } func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction:SKPaymentTransaction in transactions{ print("transaction.error",transaction.error) switch transaction.transactionState { case .purchasing: print("purchasing") case .purchased: print("purchased") if let receiptUrl:URL = Bundle.main.appStoreReceiptURL{ if let receiptData:NSData = NSData(contentsOf: receiptUrl){ let receiptBase64Str: String = receiptData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: UInt(0))) print("receiptBase64Strrr",receiptBase64Str) param = 自サバのapiurl+receiptBase64Str receipt = receiptBase64Str } } if product_id == "pranA" { //計測SDKの記述 } //planB~planEまで同じ処理 print(param) let purchase1 = sub_purchase(url_dom: "自社サーバに登録するためのapiのurl", url_param: param) purchase1.get(){json in print("purchase1(json)") } let purchase2 = sub_purchase2(url_dom: "https://sandbox.itunes.apple.com/verifyReceipt",url_param: receipt) purchase2.get(){json in print("purchase2(json)") } queue.finishTransaction(transaction) //先に出てるalertを閉じる alert?.dismiss(animated: true, completion: nil) alert = nil case .failed: print("失敗","failed") DispatchQueue.main.async { self.alert?.dismiss(animated: true, completion: nil) self.alert = nil let newAlert = UIAlertController(title: "購入がキャンセルされました", message: nil, preferredStyle: .alert) let action = UIAlertAction(title: "OK", style: .default) { action in self.alert = nil } newAlert.addAction(action) self.present(newAlert, animated: true, completion: nil) self.alert = newAlert } case .restored: print("復元中","restored") queue.finishTransaction(transaction) default: queue.finishTransaction(transaction) break } } } func paymentQueue(_ queue: SKPaymentQueue,removedTransactions transactions: [SKPaymentTransaction]){ SKPaymentQueue.default().remove(self) print("トランザクション個数",queue.transactions.count) print("トランザクション削除","removedtransactions") /*let request = SKReceiptRefreshRequest.init() request.delegate = self request.start()*/ } func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError: Error){ print("エラー",restoreCompletedTransactionsFailedWithError) } func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue){ print("リストア",queue) }
import Foundation import UIKit class sub_purchase1 { var url_dom = "" var url_param = "" init(url_dom: String,url_param: String){ self.url_dom = url_dom self.url_param = url_param } func get(_ callback: @escaping (_ json:AnyObject) -> Void){ let url = URL(string: url_dom) let config = URLSessionConfiguration.default let session = URLSession(configuration: config) let request = NSMutableURLRequest(url: url!) request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"content-type") request.httpBody = url_param.data(using: String.Encoding.utf8) let task = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error)in do{ let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject print("error: (json["err_msg"])") callback(json) }catch{ print("error serializing JSON: (error)") } }) task.resume() } }
import Foundation import UIKit class sub_purchase2 { var url_dom = "" var url_param = "" init(url_dom: String,url_param: String){ self.url_dom = url_dom self.url_param = url_param } func get(_ callback: @escaping (_ json:AnyObject) -> Void){ let url = URL(string: url_dom) let config = URLSessionConfiguration.default let session = URLSession(configuration: config) let requestContents: NSDictionary = ["receipt-data": url_param] as NSDictionary var requestData = NSData() do { requestData = try JSONSerialization.data(withJSONObject: requestContents, options: JSONSerialization.WritingOptions.prettyPrinted) as NSData } catch { print("error serializing JSON: (error)") } let request = NSMutableURLRequest(url: url!) request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"content-type") request.httpBody = requestData as Data//url_param.data(using: String.Encoding.utf8) let task = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error)in do{ let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject //print(json) callback(json) }catch{ print("error serializing JSON: (error)") } }) task.resume() } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問