#ios #swift #in-app-purchase #app-store
#iOS #swift #покупка в приложении #app-store
Вопрос:
Всем доброго дня!
Проблема в следующем: когда я тестирую приложение в изолированной среде, все работает нормально. И приложение появляется в App Store и вылетает при попытке покупки. Покупка не является расходным материалом.
Некоторые факты, которые могут навести на правильную мысль:
- Сбой происходит после строк: let payment = SKPayment (product: subscription.product); SKPaymentQueue.default().Добавить(платеж)
- Приложение вылетает не «мгновенно», а через ~ 1 секунду, что означает, что оно вылетает после некоторого ответа от сервера
- Окно с вводом пароля, логина, подтверждением покупки не появляется на экране. Сбой происходит до этого.
- Это приложение было размещено в App Store в качестве обновления старого. Оно было создано в новом проекте, в котором идентификатор пакета был изменен на идентификатор пакета старого приложения.
- Все покупки в itunesconnect одобрены модератором, они отображаются в App Store.
class BillingManager: NSObject {
static let sessionIdSetNotification = Notification.Name("SubscriptionServiceSessionIdSetNotification")
static let optionsLoadedNotification = Notification.Name("SubscriptionServiceOptionsLoadedNotification")
static let restoreSuccessfulNotification = Notification.Name("SubscriptionServiceRestoreSuccessfulNotification")
static let purchaseSuccessfulNotification = Notification.Name("SubscriptionServiceRestoreSuccessfulNotification")
private override init() { }
private static var instance: BillingManager?
/** создает 1 объект или возвращает текущий (синглтон) */
static func shared() -> BillingManager {
if instance == nil {
instance = BillingManager()
}
return instance!
}
var isPro: Bool {
/** Здесь проверяем дату подписки по UserDefaults */
var subscriptionAccess = false
if let purchase = UserDefaults.standard.string(forKey: "purchaseDate") {
if let expires = UserDefaults.standard.string(forKey: "expiresDate") {
if let purchaseDate = dateFormatter.date(from: purchase), let expiresDate = dateFormatter.date(from: expires) {
subscriptionAccess = (purchaseDate...expiresDate).contains(Date())
}
}
}
return (currentSubscription != nil) || subscriptionAccess || UserDefaults.standard.bool(forKey: "forever.subscription")
}
var hasReceiptData: Bool {
return loadReceipt() != nil
}
var currentSessionId: String? {
didSet {
NotificationCenter.default.post(name: BillingManager.sessionIdSetNotification, object: currentSessionId)
}
}
var currentSubscription: PaidSubscription?
var options: [Subscription]? {
didSet {
NotificationCenter.default.post(name: BillingManager.optionsLoadedNotification, object: options)
}
}
func loadSubscriptionOptions() {
let productIDs = Set([InAppType.month.rawValue,
InAppType.halfYear.rawValue,
InAppType.year.rawValue,
InAppType.forever.rawValue,
InAppType.discountedForever.rawValue])
let request = SKProductsRequest(productIdentifiers: productIDs)
request.delegate = self
request.start()
}
func purchase(subscription: Subscription) {
let payment = SKPayment(product: subscription.product)
SKPaymentQueue.default().add(payment)
}
func restorePurchases() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
func uploadReceipt(completion: ((_ success: Bool) -> Void)? = nil) {
if let receiptData = loadReceipt() {
Service.shared.upload(receipt: receiptData) { [weak self] (result) in
guard let strongSelf = self else { return }
switch result {
case .success(let result):
strongSelf.currentSessionId = result.sessionId
strongSelf.currentSubscription = result.currentSubscription
completion?(true)
case .failure(let error):
print("🚫 Receipt Upload Failed: (error)")
completion?(false)
}
}
}
}
private func loadReceipt() -> Data? {
guard let url = Bundle.main.appStoreReceiptURL else {
return nil
}
do {
let data = try Data(contentsOf: url)
return data
} catch {
print("Error loading receipt data: (error.localizedDescription)")
return nil
}
}
}
extension BillingManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
options = response.products.map { Subscription(product: $0) }.sorted(by: { (left, right) -> Bool in
left.product.price < right.product.price
})
}
func request(_ request: SKRequest, didFailWithError error: Error) {
if request is SKProductsRequest {
print("Subscription Options Failed Loading: (error.localizedDescription)")
}
}
}
Комментарии:
1. У вас есть приложение в appstore, в
expiresDate
котором хранятся пользовательские настройки по умолчанию??!??!?!!!??!!2. Что произошло? ДА
3. Вы знаете о том, что любой может изменить эти значения?
4. Где добавлен ваш наблюдатель очереди платежей? Можете ли вы показать его код. Можете ли вы запустить приложение на своем собственном устройстве и получить журнал сбоев или сообщение об исключении с консоли?
5. @Paulw11 куда я могу отправить вам код? И теперь у меня есть журнал сбоев, но я не могу понять, где ошибка