#ios #swift #in-app-purchase #skpaymenttransaction
#iOS #быстрый #покупка в приложении #skpaymentтранзакция
Вопрос:
Моя проблема с iap начинается с того, что у пользователя нет способа оплаты. iap работают в изолированной среде (также прерывается симуляция) и в реальном мире. Но в реальном приложении (загруженном из appstore — я тестировал в ios 12 — iphone 6), если у меня нет приложения для оплаты, предупреждающего меня добавить его. Затем открывается приложение appstore (мое приложение переходит в фоновый режим), и я ввожу все функции кредитной карты для покупки. Все идет хорошо, и appstore подсказывает мне, что вы купили товар. Но после возврата к моему приложению (выведя его на передний план) ничего не происходит. Я не могу получить какую-либо информацию о транзакции. Даже я добавляю appdidbecomeactive observer, чтобы снова перехватывать незавершенные транзакции. И снова ничего… Затем я добавил функцию незавершенной транзакции в запуске приложения. если я завершу работу приложения и начну все сначала. Он улавливает незавершенную транзакцию и выполняет мои коды. Но пользователи, у которых нет способа оплаты, думают, что приложение не сработало, и просят вернуть деньги. Так что они правы, я возвращаю или меняю их базу данных. Как я могу справиться с этой проблемой? Я даже не могу протестировать его в песочнице. Каждый раз я даю цену Apple для тестирования. Пожалуйста, помогите мне.
Комментарии:
1. Похоже, что ваш метод делегата (наблюдателя) написан неправильно. Вероятно, вам не удается правильно завершить транзакцию. Но вы не показали нам этот метод, так что кто знает? Говорить о коде — это нормально, но вам также нужно показать код.
2. Мой делегат остается в MainViewController. Это не одноэлементный класс. Итак, я не запускал transactionobserver в appdelegate didFinishLaunchingWithOptions (может быть, это проблема. Но я даже не могу попробовать это в песочнице. скомпилируйте приложение, отправьте магазин, оплатите снова и снова …). Я предполагаю, что когда приложение переходит в appstore, делегат выдает неудачную транзакцию. и после возврата к моему приложению нового вызова не происходит. И не знаю, какой код я должен показать вам, чтобы объяснить мою проблему.
3. «Итак, я не запускал transactionobserver в appdelegate didFinishLaunchingWithOptions (может быть, это проблема» Да, это, безусловно, серьезная ошибка. Вы должны настроить обозреватель транзакций сразу после запуска приложения, на случай, если магазину потребуется связаться с вами во время запуска. Однако тот факт, что у вас возникает проблема, которая просто переходит в фоновый режим и возвращается на передний план, предполагает, что вы также неправильно написали метод observer.
4. Да. удаление делегата из viewcontroller и использование в качестве расширения класса, а также добавление didFinishLaunchingWithOptions, я думаю, решают проблему. все работает прямо сейчас. Спасибо.
Ответ №1:
otherViewcontroller
@objc func saveBtnTUI() {
mainVC.messageSN(subject: subjectTF.text!, explain: explainTV.text!)
}
я обрабатываю свое подключение к базе данных, чтобы открыть новый черновик в mainviewcontroller после этого вызова функции оплаты…
import StoreKit
MainViewcontroller, SKPaymentTransactionObserver
func pay() {
SKPaymentQueue.default().add(SKPayment(product: product)) SKPaymentQueue.default().add(self)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
...
case .purchased: complete(transaction: transaction); break
case .failed: fail(transaction: transaction); break
...
}
}
func complete(transaction: SKPaymentTransaction) {
print("complete...")
DispatchQueue.main.async { self.paymentID = transaction.transactionIdentifier!; self.paySN()}
SKPaymentQueue.default().finishTransaction(transaction); SKPaymentQueue.default().remove(self)
}
func fail(transaction: SKPaymentTransaction) {
DispatchQueue.main.async {self.view.viewWithTag(999)?.removeFromSuperview()}
if let err = transaction.error as? SKError {
if err.code != .paymentCancelled {
var mStr:String = "", statusStr:String = ""; print("fail", err.localizedDescription, err.code.self)
if err.code == .clientInvalid {mStr = "..."; statusStr = mStr}
else if err.code == .cloudServiceNetworkConnectionFailed {mStr = "..."; statusStr = mStr}
else if err.code == .cloudServicePermissionDenied {mStr = "..."; statusStr = mStr}
else if err.code == .cloudServiceRevoked {mStr = "..."; statusStr = mStr}
else if err.code == .paymentInvalid {mStr = "..."; statusStr = mStr}
else if err.code == .paymentNotAllowed {mStr = "..."; statusStr = mStr}
else if err.code == .storeProductNotAvailable {mStr = "..."; statusStr = mStr}
else {mStr = "..."; statusStr = "..."}
if #available(iOS 12.2, *) {
if err.code == .invalidOfferIdentifier {mStr = "..."; statusStr = mStr}
else if err.code == .invalidOfferPrice {mStr = "..."; statusStr = mStr}
else if err.code == .invalidSignature {mStr = "..."; statusStr = mStr}
else if err.code == .missingOfferParams {mStr = "..."; statusStr = mStr}
} else {
mStr = "..."; statusStr = "..."
}
let alert = UIAlertController(title: NSLocalizedString("ERROR", comment: ""), message: mStr, preferredStyle: .alert)
let cancelA = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .cancel, handler: nil); alert.addAction(cancelA)
self.present(alert, animated: true, completion: nil)
self.paymentStatusSN(status: "fail", message: statusStr)
}
else {print("..."); self.paymentStatusSN(status: "cancel", message: "...")}
}
else {
let alert = UIAlertController(title: NSLocalizedString("ERROR", comment: ""), message: "...", preferredStyle: .alert)
let cancelA = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .cancel, handler: nil); alert.addAction(cancelA)
self.present(alert, animated: true, completion: nil)
self.paymentStatusSN(status: "fail", message: "...")
}
SKPaymentQueue.default().finishTransaction(transaction); SKPaymentQueue.default().remove(self)
}