我有一个示例项目,了解如何使用Apple的StoreKit,这样我就可以学习将自动更新订阅服务应用到我的应用程序和任何应用程序服务中。
问题是示例项目是在Swift 1.2中进行的,并且在将其转换为Swift 3时,我遇到了几个错误,但我遇到了2个警告和2个错误。希望有人可以帮助我。
此外,在将代码转换为Swift 3时,代码仍然有效吗?既然它老了?应用内购买是否有任何重大改变?
包含警告和错误的代码
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
var products = response.products
if (products.count != 0) {
for i in 0 ..< products.count
{
self.product = products[i] as? SKProduct
self.productsArray.append(product!)
}
self.tableView.reloadData()
} else {
print("No products found")
}
products = response.invalidProductIdentifiers
for product in products
{
print("Product not found: \(product)")
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("Transactions Restored")
var purchasedItemIDS = []
for transaction:SKPaymentTransaction in queue.transactions {
if transaction.payment.productIdentifier == "com.brianjcoleman.testiap1"
{
print("Consumable Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap2"
{
print("Non-Consumable Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap3"
{
print("Auto-Renewable Subscription Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap4"
{
print("Free Subscription Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap5"
{
print("Non-Renewing Subscription Product Purchased")
// Unlock Feature
}
}
let alert = UIAlertView(title: "Thank You", message: "Your purchase(s) were restored.", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
Store Kit的其余代码
var tableView = UITableView()
let productIdentifiers = Set(["com.brianjcoleman.testiap1", "com.brianjcoleman.testiap2", "com.brianjcoleman.testiap3", "com.brianjcoleman.testiap4", "com.brianjcoleman.testiap5"])
var product: SKProduct?
var productsArray = Array<SKProduct>()
func requestProductData()
{
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers:
self.productIdentifiers as Set<String>)
request.delegate = self
request.start()
} else {
let alert = UIAlertController(title: "In-App Purchases Not Enabled", message: "Please enable In App Purchase in Settings", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Settings", style: UIAlertActionStyle.default, handler: { alertAction in
alert.dismiss(animated: true, completion: nil)
let url: URL? = URL(string: UIApplicationOpenSettingsURLString)
if url != nil
{
UIApplication.shared.openURL(url!)
}
}))
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { alertAction in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
func buyProduct(_ sender: UIButton) {
let payment = SKPayment(product: productsArray[sender.tag])
SKPaymentQueue.default().add(payment)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case SKPaymentTransactionState.purchased:
print("Transaction Approved")
print("Product Identifier: \(transaction.payment.productIdentifier)")
self.deliverProduct(transaction)
SKPaymentQueue.default().finishTransaction(transaction)
case SKPaymentTransactionState.failed:
print("Transaction Failed")
SKPaymentQueue.default().finishTransaction(transaction)
default:
break
}
}
}
func deliverProduct(_ transaction:SKPaymentTransaction) {
if transaction.payment.productIdentifier == "com.brianjcoleman.testiap1"
{
print("Consumable Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap2"
{
print("Non-Consumable Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap3"
{
print("Auto-Renewable Subscription Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap4"
{
print("Free Subscription Product Purchased")
// Unlock Feature
}
else if transaction.payment.productIdentifier == "com.brianjcoleman.testiap5"
{
print("Non-Renewing Subscription Product Purchased")
// Unlock Feature
}
}
func restorePurchases(_ sender: UIButton) {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
的TableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cellFrame = CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: 52.0)
let retCell = UITableViewCell(frame: cellFrame)
if self.productsArray.count != 0
{
if indexPath.row == 5
{
let restoreButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: UIScreen.main.bounds.width - 20.0, height: 44.0))
restoreButton.titleLabel!.font = UIFont (name: "HelveticaNeue-Bold", size: 20)
restoreButton.addTarget(self, action: #selector(ViewController.restorePurchases(_:)), for: UIControlEvents.touchUpInside)
restoreButton.backgroundColor = UIColor.black
restoreButton.setTitle("Restore Purchases", for: UIControlState())
retCell.addSubview(restoreButton)
}
else
{
let singleProduct = productsArray[indexPath.row]
let titleLabel = UILabel(frame: CGRect(x: 10.0, y: 0.0, width: UIScreen.main.bounds.width - 20.0, height: 25.0))
titleLabel.textColor = UIColor.black
titleLabel.text = singleProduct.localizedTitle
titleLabel.font = UIFont (name: "HelveticaNeue", size: 20)
retCell.addSubview(titleLabel)
let descriptionLabel = UILabel(frame: CGRect(x: 10.0, y: 10.0, width: UIScreen.main.bounds.width - 70.0, height: 40.0))
descriptionLabel.textColor = UIColor.black
descriptionLabel.text = singleProduct.localizedDescription
descriptionLabel.font = UIFont (name: "HelveticaNeue", size: 12)
retCell.addSubview(descriptionLabel)
let buyButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width - 60.0, y: 5.0, width: 50.0, height: 20.0))
buyButton.titleLabel!.font = UIFont (name: "HelveticaNeue", size: 12)
buyButton.tag = indexPath.row
buyButton.addTarget(self, action: #selector(ViewController.buyProduct(_:)), for: UIControlEvents.touchUpInside)
buyButton.backgroundColor = UIColor.black
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.locale = Locale.current
buyButton.setTitle(numberFormatter.string(from: singleProduct.price), for: UIControlState())
retCell.addSubview(buyButton)
}
}
return retCell
}
答案 0 :(得分:2)
第一个函数中的两个问题都来自于before Swift 3,NSArrays的导入没有它们的泛型类型(即[SKProduct]
,而不是as? SKProduct
)。
简单地删除// Old
for i in 0 ..< products.count
{
self.product = products[i] as? SKProduct
self.productsArray.append(product!)
}
// New:
productsArray.append(contentsOf: products)
部分会修复警告,但在一次调用中添加所有内容会更清晰:
response.products
错误是因为虽然response.invalidProductIdentifiers
和[Any]
最初都是[SKProduct]
导入,但现在它们已被输入([String]
和// Old:
products = response.invalidProductIdentifiers
for product in products
// New:
for product in response.invalidProductIdentifiers
)。最简单的解决方案就是直接使用数组:
[String]
由于它只是打印,我可能只是直接打印数组。
第二个函数中的错误是因为编译器需要知道变量应该是什么类型的数组。从名称来看,我猜它本来是class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, SKProductsRequestDelegate, SKPaymentTransactionObserver {
enum Product: String {
case test1 = "com.brianjcoleman.testiap1"
case test2 = "com.brianjcoleman.testiap2"
case test3 = "com.brianjcoleman.testiap3"
case test4 = "com.brianjcoleman.testiap4"
case test5 = "com.brianjcoleman.testiap5"
static var allValues: [Product] {
return [.test1, .test2, .test3, .test4, .test5]
}
}
let tableView = UITableView()
var productsArray = [SKProduct]()
override func viewDidLoad()
{
super.viewDidLoad()
tableView.frame = self.view.frame
tableView.separatorColor = .clear
tableView.dataSource = self
tableView.delegate = self
self.view.addSubview(tableView)
SKPaymentQueue.default().add(self)
self.requestProductData()
}
override func viewWillDisappear(_ animated: Bool)
{
super.viewWillDisappear(animated)
SKPaymentQueue.default().remove(self)
}
// In-App Purchase Methods
func requestProductData()
{
if SKPaymentQueue.canMakePayments() {
let productIdentifiers = Set(Product.allValues.map { $0.rawValue })
let request = SKProductsRequest(productIdentifiers: productIdentifiers)
request.delegate = self
request.start()
} else {
let alert = UIAlertController(title: "In-App Purchases Not Enabled",
message: "Please enable In App Purchase in Settings",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Settings", style: .default, handler: { _ in
alert.dismiss(animated: true, completion: nil)
if let url = URL(string: UIApplicationOpenSettingsURLString) {
UIApplication.shared.openURL(url)
}
}))
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { _ in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse)
{
let products = response.products
if products.count != 0 {
productsArray.append(contentsOf: products)
self.tableView.reloadData()
} else {
print("No products found")
}
let invalidIdentifiers = response.invalidProductIdentifiers
if invalidIdentifiers.count > 0 {
print("Invalid product identifiers: \(invalidIdentifiers)")
}
}
func buyProduct(_ sender: UIButton)
{
let payment = SKPayment(product: productsArray[sender.tag])
SKPaymentQueue.default().add(payment)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
{
for transaction in transactions {
switch transaction.transactionState {
case .purchased,
.restored:
print("Transaction Approved")
print("Product Identifier: \(transaction.payment.productIdentifier)")
self.deliverProduct(transaction)
SKPaymentQueue.default().finishTransaction(transaction)
case .failed:
print("Transaction Failed")
SKPaymentQueue.default().finishTransaction(transaction)
case .deferred,
.purchasing:
break
}
}
}
func deliverProduct(_ transaction:SKPaymentTransaction)
{
}
func restorePurchases(_ sender: UIButton)
{
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue)
{
print("Transactions Restored")
for transaction in queue.transactions {
processTransaction(transaction: transaction)
}
let alert = UIAlertController(title: "Thank You",
message: "Your purchase(s) were restored.",
preferredStyle: .alert)
present(alert, animated: true)
}
private func processTransaction(transaction: SKPaymentTransaction)
{
guard let product = Product(rawValue: transaction.payment.productIdentifier) else {
print("Unknown product identifier: \(transaction.payment.productIdentifier)")
return
}
switch product {
case .test1:
print("Consumable Product Purchased")
// Unlock Feature
case .test2:
print("Non-Consumable Product Purchased")
// Unlock Feature
case .test3:
print("Auto-Renewable Subscription Product Purchased")
// Unlock Feature
case .test4:
print("Free Subscription Product Purchased")
// Unlock Feature
case .test5:
print("Non-Renewing Subscription Product Purchased")
// Unlock Feature
}
}
// Screen Layout Methods
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.productsArray.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cellFrame = CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: 52.0)
let retCell = UITableViewCell(frame: cellFrame)
if self.productsArray.count != 0 {
if indexPath.row == Product.allValues.count
{
let restoreButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: UIScreen.main.bounds.width - 20.0, height: 44.0))
restoreButton.titleLabel?.font = UIFont(name: "HelveticaNeue-Bold", size: 20)
restoreButton.addTarget(self, action: #selector(ViewController.restorePurchases(_:)), for: .touchUpInside)
restoreButton.backgroundColor = .black
restoreButton.setTitle("Restore Purchases", for: .normal)
retCell.addSubview(restoreButton)
} else {
let singleProduct = productsArray[indexPath.row]
let titleLabel = UILabel(frame: CGRect(x: 10.0, y: 0.0, width: UIScreen.main.bounds.width - 20.0, height: 25.0))
titleLabel.textColor = .black
titleLabel.text = singleProduct.localizedTitle
titleLabel.font = UIFont(name: "HelveticaNeue", size: 20)
retCell.addSubview(titleLabel)
let descriptionLabel = UILabel(frame: CGRect(x: 10.0, y: 10.0, width: UIScreen.main.bounds.width - 70.0, height: 40.0))
descriptionLabel.textColor = .black
descriptionLabel.text = singleProduct.localizedDescription
descriptionLabel.font = UIFont(name: "HelveticaNeue", size: 12)
retCell.addSubview(descriptionLabel)
let buyButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.width - 60.0, y: 5.0, width: 50.0, height: 20.0))
buyButton.titleLabel?.font = UIFont(name: "HelveticaNeue", size: 12)
buyButton.tag = indexPath.row
buyButton.addTarget(self, action: #selector(ViewController.buyProduct(_:)), for: .touchUpInside)
buyButton.backgroundColor = .black
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.locale = .current
buyButton.setTitle(numberFormatter.string(from: singleProduct.price), for: .normal)
retCell.addSubview(buyButton)
}
}
return retCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 52.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
if section == 0 {
return 64.0
}
return 32.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let ret = UILabel(frame: CGRect(x: 10, y: 0, width: self.tableView.frame.width - 20, height: 32.0))
ret.backgroundColor = .clear
ret.text = "In-App Purchases"
ret.textAlignment = .center
return ret
}
}
,但它没有被使用(因为同一行上的警告表示),所以你也可以删除该行。
完整的更新/现代化/统一风格的视图控制器:
{{1}}