Skip to content

Commit

Permalink
add more specific errors
Browse files Browse the repository at this point in the history
for handling failing purchases
  • Loading branch information
extrawurst committed Jan 11, 2025
1 parent bf1106f commit 10f6f3a
Show file tree
Hide file tree
Showing 9 changed files with 500 additions and 10 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## [0.5.2] - 2024-01-11

### Added
* add `IosIapPurchaseError` and `IosIapStoreKitError` to `IosIapPurchaseResponse` to provide programmatic error handling

## [0.5.1] - 2024-12-02

### Changed
Expand Down
40 changes: 40 additions & 0 deletions RustXcframework.xcframework/ios-arm64/Headers/bevy_ios_iap.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,30 @@ void* __swift_bridge__$Vec_IosIapTransaction$get_mut(void* vec_ptr, uintptr_t in
uintptr_t __swift_bridge__$Vec_IosIapTransaction$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapTransaction$as_ptr(void* vec_ptr);

typedef struct IosIapStoreKitError IosIapStoreKitError;
void __swift_bridge__$IosIapStoreKitError$_free(void* self);

void* __swift_bridge__$Vec_IosIapStoreKitError$new(void);
void __swift_bridge__$Vec_IosIapStoreKitError$drop(void* vec_ptr);
void __swift_bridge__$Vec_IosIapStoreKitError$push(void* vec_ptr, void* item_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$pop(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$get(void* vec_ptr, uintptr_t index);
void* __swift_bridge__$Vec_IosIapStoreKitError$get_mut(void* vec_ptr, uintptr_t index);
uintptr_t __swift_bridge__$Vec_IosIapStoreKitError$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$as_ptr(void* vec_ptr);

typedef struct IosIapPurchaseError IosIapPurchaseError;
void __swift_bridge__$IosIapPurchaseError$_free(void* self);

void* __swift_bridge__$Vec_IosIapPurchaseError$new(void);
void __swift_bridge__$Vec_IosIapPurchaseError$drop(void* vec_ptr);
void __swift_bridge__$Vec_IosIapPurchaseError$push(void* vec_ptr, void* item_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$pop(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$get(void* vec_ptr, uintptr_t index);
void* __swift_bridge__$Vec_IosIapPurchaseError$get_mut(void* vec_ptr, uintptr_t index);
uintptr_t __swift_bridge__$Vec_IosIapPurchaseError$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$as_ptr(void* vec_ptr);

typedef struct IosIapPurchaseResponse IosIapPurchaseResponse;
void __swift_bridge__$IosIapPurchaseResponse$_free(void* self);

Expand Down Expand Up @@ -215,6 +239,22 @@ void* __swift_bridge__$IosIapPurchaseResponse$canceled(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$pending(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$unknown(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$error(void* e);
void* __swift_bridge__$IosIapPurchaseResponse$purchase_error(void* error, void* localized_description);
void* __swift_bridge__$IosIapPurchaseResponse$storekit_error(void* error, void* localized_description);
void* __swift_bridge__$IosIapPurchaseError$invalid_quantity(void);
void* __swift_bridge__$IosIapPurchaseError$product_unavailable(void);
void* __swift_bridge__$IosIapPurchaseError$purchase_not_allowed(void);
void* __swift_bridge__$IosIapPurchaseError$ineligible_for_offer(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_identifier(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_price(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_signature(void);
void* __swift_bridge__$IosIapPurchaseError$missing_offer_parameters(void);
void* __swift_bridge__$IosIapStoreKitError$unknown(void);
void* __swift_bridge__$IosIapStoreKitError$user_cancelled(void);
void* __swift_bridge__$IosIapStoreKitError$network_error(void* e);
void* __swift_bridge__$IosIapStoreKitError$system_error(void* e);
void* __swift_bridge__$IosIapStoreKitError$not_available_in_storefront(void);
void* __swift_bridge__$IosIapStoreKitError$not_entitled(void);
void* __swift_bridge__$IosIapEnvironment$sandbox(void);
void* __swift_bridge__$IosIapEnvironment$production(void);
void* __swift_bridge__$IosIapEnvironment$xcode(void);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,30 @@ void* __swift_bridge__$Vec_IosIapTransaction$get_mut(void* vec_ptr, uintptr_t in
uintptr_t __swift_bridge__$Vec_IosIapTransaction$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapTransaction$as_ptr(void* vec_ptr);

typedef struct IosIapStoreKitError IosIapStoreKitError;
void __swift_bridge__$IosIapStoreKitError$_free(void* self);

void* __swift_bridge__$Vec_IosIapStoreKitError$new(void);
void __swift_bridge__$Vec_IosIapStoreKitError$drop(void* vec_ptr);
void __swift_bridge__$Vec_IosIapStoreKitError$push(void* vec_ptr, void* item_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$pop(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$get(void* vec_ptr, uintptr_t index);
void* __swift_bridge__$Vec_IosIapStoreKitError$get_mut(void* vec_ptr, uintptr_t index);
uintptr_t __swift_bridge__$Vec_IosIapStoreKitError$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapStoreKitError$as_ptr(void* vec_ptr);

typedef struct IosIapPurchaseError IosIapPurchaseError;
void __swift_bridge__$IosIapPurchaseError$_free(void* self);

void* __swift_bridge__$Vec_IosIapPurchaseError$new(void);
void __swift_bridge__$Vec_IosIapPurchaseError$drop(void* vec_ptr);
void __swift_bridge__$Vec_IosIapPurchaseError$push(void* vec_ptr, void* item_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$pop(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$get(void* vec_ptr, uintptr_t index);
void* __swift_bridge__$Vec_IosIapPurchaseError$get_mut(void* vec_ptr, uintptr_t index);
uintptr_t __swift_bridge__$Vec_IosIapPurchaseError$len(void* vec_ptr);
void* __swift_bridge__$Vec_IosIapPurchaseError$as_ptr(void* vec_ptr);

typedef struct IosIapPurchaseResponse IosIapPurchaseResponse;
void __swift_bridge__$IosIapPurchaseResponse$_free(void* self);

Expand Down Expand Up @@ -215,6 +239,22 @@ void* __swift_bridge__$IosIapPurchaseResponse$canceled(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$pending(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$unknown(void* id);
void* __swift_bridge__$IosIapPurchaseResponse$error(void* e);
void* __swift_bridge__$IosIapPurchaseResponse$purchase_error(void* error, void* localized_description);
void* __swift_bridge__$IosIapPurchaseResponse$storekit_error(void* error, void* localized_description);
void* __swift_bridge__$IosIapPurchaseError$invalid_quantity(void);
void* __swift_bridge__$IosIapPurchaseError$product_unavailable(void);
void* __swift_bridge__$IosIapPurchaseError$purchase_not_allowed(void);
void* __swift_bridge__$IosIapPurchaseError$ineligible_for_offer(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_identifier(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_price(void);
void* __swift_bridge__$IosIapPurchaseError$invalid_offer_signature(void);
void* __swift_bridge__$IosIapPurchaseError$missing_offer_parameters(void);
void* __swift_bridge__$IosIapStoreKitError$unknown(void);
void* __swift_bridge__$IosIapStoreKitError$user_cancelled(void);
void* __swift_bridge__$IosIapStoreKitError$network_error(void* e);
void* __swift_bridge__$IosIapStoreKitError$system_error(void* e);
void* __swift_bridge__$IosIapStoreKitError$not_available_in_storefront(void);
void* __swift_bridge__$IosIapStoreKitError$not_entitled(void);
void* __swift_bridge__$IosIapEnvironment$sandbox(void);
void* __swift_bridge__$IosIapEnvironment$production(void);
void* __swift_bridge__$IosIapEnvironment$xcode(void);
Expand Down
28 changes: 28 additions & 0 deletions Sources/bevy_ios_iap/BevyIosIAP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public func ios_iap_purchase(request:Int64, id: RustString) {
}

purchase_processed(request, result)
} catch let error as Product.PurchaseError {
purchase_processed(request, IosIapPurchaseResponse.purchase_error(convert_purchase_error(error),error.localizedDescription))
} catch let error as StoreKitError {
purchase_processed(request, IosIapPurchaseResponse.storekit_error(convert_storekit_error(error),error.localizedDescription))
} catch {
purchase_processed(request, IosIapPurchaseResponse.error(error.localizedDescription))
}
Expand Down Expand Up @@ -189,6 +193,30 @@ func convert_product(_ product: (Product)) async throws -> IosIapProduct {
return rust_product
}

public func convert_purchase_error(_ error: (Product.PurchaseError)) -> IosIapPurchaseError {
return switch error {
case .invalidQuantity: IosIapPurchaseError.invalid_quantity()
case .productUnavailable: IosIapPurchaseError.product_unavailable()
case .purchaseNotAllowed: IosIapPurchaseError.purchase_not_allowed()
case .ineligibleForOffer: IosIapPurchaseError.ineligible_for_offer()
case .invalidOfferIdentifier: IosIapPurchaseError.invalid_offer_identifier()
case .invalidOfferPrice: IosIapPurchaseError.invalid_offer_price()
case .invalidOfferSignature: IosIapPurchaseError.invalid_offer_signature()
case .missingOfferParameters: IosIapPurchaseError.missing_offer_parameters()
}
}

public func convert_storekit_error(_ error: (StoreKitError)) -> IosIapStoreKitError {
return switch error {
case .unknown: IosIapStoreKitError.unknown()
case .userCancelled: IosIapStoreKitError.user_cancelled()
case .networkError(let e): IosIapStoreKitError.network_error(e.localizedDescription)
case .systemError(let e): IosIapStoreKitError.system_error(e.localizedDescription)
case .notAvailableInStorefront: IosIapStoreKitError.not_available_in_storefront()
case .notEntitled: IosIapStoreKitError.not_entitled()
}
}

public func convert_transaction(_ transaction: (Transaction)) throws -> IosIapTransaction {
let type = if transaction.productType == Product.ProductType.consumable {
IosIapProductType.new_consumable(false)
Expand Down
217 changes: 217 additions & 0 deletions Sources/bevy_ios_iap/bevy_ios_iap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,215 @@ extension IosIapTransaction: Vectorizable {
}


public class IosIapStoreKitError: IosIapStoreKitErrorRefMut {
var isOwned: Bool = true

public override init(ptr: UnsafeMutableRawPointer) {
super.init(ptr: ptr)
}

deinit {
if isOwned {
__swift_bridge__$IosIapStoreKitError$_free(ptr)
}
}
}
extension IosIapStoreKitError {
class public func network_error<GenericIntoRustString: IntoRustString>(_ e: GenericIntoRustString) -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$network_error({ let rustString = e.intoRustString(); rustString.isOwned = false; return rustString.ptr }()))
}

class public func system_error<GenericIntoRustString: IntoRustString>(_ e: GenericIntoRustString) -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$system_error({ let rustString = e.intoRustString(); rustString.isOwned = false; return rustString.ptr }()))
}
}
public class IosIapStoreKitErrorRefMut: IosIapStoreKitErrorRef {
public override init(ptr: UnsafeMutableRawPointer) {
super.init(ptr: ptr)
}
}
public class IosIapStoreKitErrorRef {
var ptr: UnsafeMutableRawPointer

public init(ptr: UnsafeMutableRawPointer) {
self.ptr = ptr
}
}
extension IosIapStoreKitErrorRef {
class public func unknown() -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$unknown())
}

class public func user_cancelled() -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$user_cancelled())
}

class public func not_available_in_storefront() -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$not_available_in_storefront())
}

class public func not_entitled() -> IosIapStoreKitError {
IosIapStoreKitError(ptr: __swift_bridge__$IosIapStoreKitError$not_entitled())
}
}
extension IosIapStoreKitError: Vectorizable {
public static func vecOfSelfNew() -> UnsafeMutableRawPointer {
__swift_bridge__$Vec_IosIapStoreKitError$new()
}

public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) {
__swift_bridge__$Vec_IosIapStoreKitError$drop(vecPtr)
}

public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: IosIapStoreKitError) {
__swift_bridge__$Vec_IosIapStoreKitError$push(vecPtr, {value.isOwned = false; return value.ptr;}())
}

public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional<Self> {
let pointer = __swift_bridge__$Vec_IosIapStoreKitError$pop(vecPtr)
if pointer == nil {
return nil
} else {
return (IosIapStoreKitError(ptr: pointer!) as! Self)
}
}

public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<IosIapStoreKitErrorRef> {
let pointer = __swift_bridge__$Vec_IosIapStoreKitError$get(vecPtr, index)
if pointer == nil {
return nil
} else {
return IosIapStoreKitErrorRef(ptr: pointer!)
}
}

public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<IosIapStoreKitErrorRefMut> {
let pointer = __swift_bridge__$Vec_IosIapStoreKitError$get_mut(vecPtr, index)
if pointer == nil {
return nil
} else {
return IosIapStoreKitErrorRefMut(ptr: pointer!)
}
}

public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer<IosIapStoreKitErrorRef> {
UnsafePointer<IosIapStoreKitErrorRef>(OpaquePointer(__swift_bridge__$Vec_IosIapStoreKitError$as_ptr(vecPtr)))
}

public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt {
__swift_bridge__$Vec_IosIapStoreKitError$len(vecPtr)
}
}


public class IosIapPurchaseError: IosIapPurchaseErrorRefMut {
var isOwned: Bool = true

public override init(ptr: UnsafeMutableRawPointer) {
super.init(ptr: ptr)
}

deinit {
if isOwned {
__swift_bridge__$IosIapPurchaseError$_free(ptr)
}
}
}
public class IosIapPurchaseErrorRefMut: IosIapPurchaseErrorRef {
public override init(ptr: UnsafeMutableRawPointer) {
super.init(ptr: ptr)
}
}
public class IosIapPurchaseErrorRef {
var ptr: UnsafeMutableRawPointer

public init(ptr: UnsafeMutableRawPointer) {
self.ptr = ptr
}
}
extension IosIapPurchaseErrorRef {
class public func invalid_quantity() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$invalid_quantity())
}

class public func product_unavailable() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$product_unavailable())
}

class public func purchase_not_allowed() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$purchase_not_allowed())
}

class public func ineligible_for_offer() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$ineligible_for_offer())
}

class public func invalid_offer_identifier() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$invalid_offer_identifier())
}

class public func invalid_offer_price() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$invalid_offer_price())
}

class public func invalid_offer_signature() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$invalid_offer_signature())
}

class public func missing_offer_parameters() -> IosIapPurchaseError {
IosIapPurchaseError(ptr: __swift_bridge__$IosIapPurchaseError$missing_offer_parameters())
}
}
extension IosIapPurchaseError: Vectorizable {
public static func vecOfSelfNew() -> UnsafeMutableRawPointer {
__swift_bridge__$Vec_IosIapPurchaseError$new()
}

public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) {
__swift_bridge__$Vec_IosIapPurchaseError$drop(vecPtr)
}

public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: IosIapPurchaseError) {
__swift_bridge__$Vec_IosIapPurchaseError$push(vecPtr, {value.isOwned = false; return value.ptr;}())
}

public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional<Self> {
let pointer = __swift_bridge__$Vec_IosIapPurchaseError$pop(vecPtr)
if pointer == nil {
return nil
} else {
return (IosIapPurchaseError(ptr: pointer!) as! Self)
}
}

public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<IosIapPurchaseErrorRef> {
let pointer = __swift_bridge__$Vec_IosIapPurchaseError$get(vecPtr, index)
if pointer == nil {
return nil
} else {
return IosIapPurchaseErrorRef(ptr: pointer!)
}
}

public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<IosIapPurchaseErrorRefMut> {
let pointer = __swift_bridge__$Vec_IosIapPurchaseError$get_mut(vecPtr, index)
if pointer == nil {
return nil
} else {
return IosIapPurchaseErrorRefMut(ptr: pointer!)
}
}

public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer<IosIapPurchaseErrorRef> {
UnsafePointer<IosIapPurchaseErrorRef>(OpaquePointer(__swift_bridge__$Vec_IosIapPurchaseError$as_ptr(vecPtr)))
}

public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt {
__swift_bridge__$Vec_IosIapPurchaseError$len(vecPtr)
}
}


public class IosIapPurchaseResponse: IosIapPurchaseResponseRefMut {
var isOwned: Bool = true

Expand Down Expand Up @@ -1293,6 +1502,14 @@ extension IosIapPurchaseResponse {
class public func error<GenericIntoRustString: IntoRustString>(_ e: GenericIntoRustString) -> IosIapPurchaseResponse {
IosIapPurchaseResponse(ptr: __swift_bridge__$IosIapPurchaseResponse$error({ let rustString = e.intoRustString(); rustString.isOwned = false; return rustString.ptr }()))
}

class public func purchase_error<GenericIntoRustString: IntoRustString>(_ error: IosIapPurchaseError, _ localized_description: GenericIntoRustString) -> IosIapPurchaseResponse {
IosIapPurchaseResponse(ptr: __swift_bridge__$IosIapPurchaseResponse$purchase_error({error.isOwned = false; return error.ptr;}(), { let rustString = localized_description.intoRustString(); rustString.isOwned = false; return rustString.ptr }()))
}

class public func storekit_error<GenericIntoRustString: IntoRustString>(_ error: IosIapStoreKitError, _ localized_description: GenericIntoRustString) -> IosIapPurchaseResponse {
IosIapPurchaseResponse(ptr: __swift_bridge__$IosIapPurchaseResponse$storekit_error({error.isOwned = false; return error.ptr;}(), { let rustString = localized_description.intoRustString(); rustString.isOwned = false; return rustString.ptr }()))
}
}
public class IosIapPurchaseResponseRefMut: IosIapPurchaseResponseRef {
public override init(ptr: UnsafeMutableRawPointer) {
Expand Down
Loading

0 comments on commit 10f6f3a

Please sign in to comment.