Files
purchases-ios/Sources/Purchasing/StoreKitAbstractions/Storefront.swift
T
NachoSoto 2be3d0273b Storefront: added sk1CurrentStorefront for Objective-C (#1614)
Fixes https://community.revenuecat.com/sdks-51/objective-c-how-to-access-rcstorefront-1647?postid=5154#post5154

`RCStoreFront` does have a `currentStorefront` property which supports StoreKit 1 and StoreKit 2, but due to the fact that the SK2 way of obtaining the current storefront is `async`, this property is only `async`, which means that it indeed isn’t available on Objective-C.

This adds a way to be able to access the current storefront from Objective-C.
2022-05-31 10:16:56 -07:00

150 lines
5.1 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// Storefront.swift
//
// Created by Nacho Soto on 4/13/22.
import Foundation
import StoreKit
/// An object containing the location and unique identifier of an Apple App Store storefront.
///
/// - Note: Don't save the storefront information with your user information; storefront information can change
/// at any time. Always get the storefront identifier immediately before you display product information or availability
/// to the user in your app. Storefront information may not be used to develop or enhance a user profile,
/// or track customers for advertising or marketing purposes.
@objc(RCStorefront)
public class Storefront: NSObject, StorefrontType {
private let storefront: StorefrontType
init(_ storefront: StorefrontType) {
self.storefront = storefront
super.init()
}
// Note: this class inherits its docs from `StorefrontType`
// swiftlint:disable missing_docs
@objc public var countryCode: String { self.storefront.countryCode }
@objc public var identifier: String { self.storefront.identifier }
// swiftlint:enable missing_docs
// MARK: -
/// Creates an instance from any `StorefrontType`.
/// If `storefront` is already a wrapped `Storefront` then this returns it instead.
static func from(storefront: StorefrontType) -> Storefront {
return storefront as? Storefront
?? Storefront(storefront)
}
public override func isEqual(_ object: Any?) -> Bool {
guard let other = object as? StorefrontType else { return false }
return self.identifier == other.identifier
}
public override var hash: Int {
return self.identifier.hashValue
}
public override var description: String {
return """
<\(String(describing: Storefront.self)):
identifier=\(self.identifier),
countryCode=\(countryCode)
>
"""
}
}
public extension Storefront {
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
private static var currentStorefrontType: StorefrontType? {
get async {
if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) {
let sk2Storefront = await StoreKit.Storefront.current
return sk2Storefront.map(SK2Storefront.init)
} else {
return Self.sk1CurrentStorefrontType
}
}
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
private static var sk1CurrentStorefrontType: StorefrontType? {
return SKPaymentQueue.default().storefront.map(SK1Storefront.init)
}
/// The current App Store storefront for the device.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
static var currentStorefront: Storefront? {
get async {
return await self.currentStorefrontType.map(Storefront.from(storefront: ))
}
}
/// The current App Store storefront for the device obtained from StoreKit 1 only.
@available(swift, obsoleted: 0.0.1, renamed: "currentStorefront")
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
@objc static var sk1CurrentStorefront: Storefront? {
return self.sk1CurrentStorefrontType.map(Storefront.from(storefront: ))
}
}
// MARK: -
/// A type containing the location and unique identifier of an Apple App Store storefront.
internal protocol StorefrontType {
/// The three-letter code representing the country or region
/// associated with the App Store storefront.
/// - Note: This property uses the ISO 3166-1 Alpha-3 country code representation.
var countryCode: String { get }
/// A value defined by Apple that uniquely identifies an App Store storefront.
var identifier: String { get }
}
// MARK: - Wrapper constructors / getters
extension Storefront {
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
internal convenience init?(sk1Storefront: SKStorefront) {
self.init(SK1Storefront(sk1Storefront))
}
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
internal convenience init?(sk2Storefront: StoreKit.Storefront) {
self.init(SK2Storefront(sk2Storefront))
}
/// Returns the `SKStorefront` if this `Storefront` represents an `SKStorefront`.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, macCatalyst 13.1, *)
@objc public var sk1Storefront: SKStorefront? {
return (self.storefront as? SK1Storefront)?.underlyingSK1Storefront
}
/// Returns the `StoreKit.Storefront` if this `Storefront` represents a `StoreKit.Storefront`.
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
public var sk2Storefront: StoreKit.Storefront? {
return (self.storefront as? SK2Storefront)?.underlyingSK2Storefront
}
}