├── .github ├── FUNDING.yml └── workflows │ ├── cd.yml │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── Package.swift ├── README.md ├── RustXcframework.xcframework ├── .gitignore ├── Info.plist ├── ios-arm64 │ └── Headers │ │ ├── SwiftBridgeCore.h │ │ ├── bevy_ios_iap.h │ │ └── module.modulemap └── ios-arm64_x86_64-simulator │ └── Headers │ ├── SwiftBridgeCore.h │ ├── bevy_ios_iap.h │ └── module.modulemap ├── SWIFT_BRIDGE.md ├── Sources └── bevy_ios_iap │ ├── BevyIosIAP.swift │ ├── Observer.swift │ ├── SwiftBridgeCore.swift │ └── bevy_ios_iap.swift ├── Tests └── bevy_ios_iapTests │ └── bevy_ios_iapTests.swift ├── assets ├── demo.gif ├── framework.png └── xcode-spm.png ├── bevy_ios_iap ├── .gitignore ├── .vscode │ └── settings.json ├── Cargo.toml ├── build-rust-release.sh ├── build-rust.sh ├── build.rs ├── justfile └── src │ ├── lib.rs │ ├── methods.rs │ ├── native.rs │ ├── plugin.rs │ ├── request.rs │ ├── response.rs │ └── transaction.rs ├── bevy_ios_iap_egui ├── CHANGELOG.md ├── Cargo.toml ├── README.md ├── justfile └── src │ └── lib.rs └── justfile /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rustunit -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD-rust 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'rs-*' 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | build: 13 | permissions: 14 | contents: write 15 | runs-on: macos-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: dtolnay/rust-toolchain@stable 20 | 21 | - name: Add iOS targets 22 | run: rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios 23 | 24 | - uses: extractions/setup-just@v1 25 | 26 | - name: Rust Cache 27 | uses: Swatinem/rust-cache@v2 28 | with: 29 | workspaces: "./bevy_ios_iap" 30 | 31 | - name: make xcframework archive 32 | run: just zip 33 | 34 | - name: Release 35 | uses: softprops/action-gh-release@v2 36 | if: startsWith(github.ref, 'refs/tags/') 37 | with: 38 | prerelease: ${{ contains(github.ref, 'rc') }} 39 | files: | 40 | ./RustXcframework.xcframework.zip 41 | ./RustXcframework.xcframework.sha256.txt -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI-rust 2 | 3 | on: 4 | push: 5 | 6 | env: 7 | CARGO_TERM_COLOR: always 8 | 9 | jobs: 10 | build: 11 | #TODO: run and test on wasm, win and linux 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: dtolnay/rust-toolchain@stable 17 | 18 | - name: Add iOS targets 19 | run: rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios 20 | 21 | - name: Rust Cache 22 | uses: Swatinem/rust-cache@v2 23 | with: 24 | workspaces: "./bevy_ios_iap" 25 | 26 | # TODO: enable once https://github.com/rust-lang/rust-bindgen/issues/3181 is released 27 | # - name: Check iOS Sim 28 | # run: | 29 | # cd bevy_ios_iap 30 | # cargo c --target=aarch64-apple-ios-sim 31 | # cargo b --target=aarch64-apple-ios-sim 32 | # cargo clippy --target=aarch64-apple-ios-sim 33 | 34 | - name: Check iOS 35 | run: | 36 | cd bevy_ios_iap 37 | cargo c --target=aarch64-apple-ios 38 | cargo b --target=aarch64-apple-ios 39 | cargo clippy --target=aarch64-apple-ios 40 | 41 | - name: Check MacOs 42 | run: | 43 | cd bevy_ios_iap 44 | cargo c 45 | cargo b 46 | cargo clippy 47 | cargo t 48 | 49 | build_egui: 50 | runs-on: macos-latest 51 | 52 | steps: 53 | - uses: actions/checkout@v4 54 | - uses: dtolnay/rust-toolchain@stable 55 | 56 | - name: Add iOS targets 57 | run: rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios 58 | 59 | - name: Rust Cache 60 | uses: Swatinem/rust-cache@v2 61 | with: 62 | workspaces: "./bevy_ios_iap_egui" 63 | 64 | # TODO: enable once https://github.com/rust-lang/rust-bindgen/issues/3181 is released 65 | # - name: Check iOS Sim 66 | # run: | 67 | # cd bevy_ios_iap_egui 68 | # cargo c --target=aarch64-apple-ios-sim 69 | # cargo b --target=aarch64-apple-ios-sim 70 | # cargo clippy --target=aarch64-apple-ios-sim 71 | 72 | - name: Check iOS 73 | run: | 74 | cd bevy_ios_iap_egui 75 | cargo c --target=aarch64-apple-ios 76 | cargo b --target=aarch64-apple-ios 77 | cargo clippy --target=aarch64-apple-ios 78 | 79 | - name: Check MacOs 80 | run: | 81 | cd bevy_ios_iap_egui 82 | cargo c 83 | cargo b 84 | cargo clippy 85 | cargo t 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | bevy_ios_iap_egui/target 10 | bevy_ios_iap_egui/Cargo.lock 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## Unreleased 9 | 10 | ## [0.7.0] - 2025-04-26 11 | 12 | ### Fixed 13 | * upgrade to bevy `0.16` 14 | * temporarily disabled ios-sim support until rust-bindgen [releases](https://github.com/rust-lang/rust-bindgen/issues/3181) 15 | 16 | ## [0.6.0] - 2025-03-30 17 | 18 | ### Changed 19 | * make `Transaction` `reason` and `storefront` available only ios `17.0` or up 20 | * introduce `Ios17Specific` Option-like that forces users to handle the fact that these values are only available on iOS 17 or up 21 | * make package iOS `16.0` compatible 22 | * remove `currency_code` as it was deprecated in iOS `16.0` 23 | 24 | ## [0.5.2] - 2025-01-11 25 | 26 | ### Added 27 | * add `IosIapPurchaseError` and `IosIapStoreKitError` to `IosIapPurchaseResponse` to provide programmatic error handling 28 | 29 | ## [0.5.1] - 2024-12-02 30 | 31 | ### Changed 32 | * make `BevyIosIap` requests more typesafe, so you cannot assign a observer that does not match the response type 33 | 34 | ## [0.5.0] - 2024-12-01 35 | 36 | ### Fixed 37 | * upgrade to bevy `0.15` 38 | 39 | ## [0.4.2] - 2024-12-01 40 | 41 | ### Fixed 42 | * fixed broken observer api because we listened to the wrong event type 43 | 44 | ## [0.4.0] - 2024-11-27 45 | 46 | ### Changed 47 | * support subscriptions 48 | * new `BevyIosIap` SystemParam providing observer based API 49 | * new fields in IosIapTransaction: `original_id`, `original_purchase_date`, `json_representation`, `currency`, `currency_code`, `revocation_reason`, `app_account_token`, `web_order_line_item_id`, `subscription_group_id` 50 | * all calls now do proper error handling 51 | * all calls take a request id and return it with the response used for `BevyIosIap` 52 | * `IosIapEvents::Transaction` is not `IosIapEvents::TransactionUpdate` 53 | * renamed `IosIapTransactionFinished` -> `IosIapTransactionFinishResponse` 54 | * renamed `IosIapPurchaseResult` -> `IosIapPurchaseResponse` 55 | * renamed `IosIapEvents` in `IosIapResponse` and moved `TransactionUpdate` into a new `IosIapEvents` to signify the difference between a pro-active event sent or a response to a previous request 56 | 57 | ## [0.3.0] - 2024-07-12 58 | 59 | ### Changed 60 | * update to bevy `0.14` 61 | 62 | ## [0.2.1] - 2024-05-12 63 | 64 | ### Added 65 | * proper rustdoc and readme with example 66 | 67 | ## [0.2.0] - 2024-05-09 68 | 69 | ### Changed 70 | * new method `current_entitlements` that will response via `IosIapEvents::CurrentEntitlements` (see [apple docs](https://developer.apple.com/documentation/storekit/transaction/3851204-currententitlements)) 71 | * `IosIapPurchaseResult::Success` now contains the `IosIapTransaction` of the purchase 72 | * `IosIapPurchaseResult::Pending` and `IosIapPurchaseResult::Cancel` return the Product ID used for `purchase` 73 | 74 | ### Fixes 75 | * `IosIapTransaction.app_bundle_id` was also returing the product ID 76 | 77 | ## [0.1.2] - 2024-05-06 78 | 79 | *note:* the crate release matches the commit tagged with the `ru-` prefix because we release the swift package after the crate due to its dependency on each other 80 | 81 | ### Added 82 | * `IosIapPurchaseResult` can be `Unknown` if an invalid product ID is used for a purchase ([#3](https://github.com/rustunit/bevy_ios_iap/issues/3)) 83 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.10 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "bevy_ios_iap", 8 | platforms: [.iOS("16.0")], 9 | products: [ 10 | // Products define the executables and libraries a package produces, making them visible to other packages. 11 | .library( 12 | name: "bevy_ios_iap", 13 | targets: ["bevy_ios_iap"]) 14 | ], 15 | targets: [ 16 | // Targets are the basic building blocks of a package, defining a module or a test suite. 17 | // Targets can depend on other targets in this package and products from dependencies. 18 | .binaryTarget( 19 | name: "RustXcframework", 20 | //for local development: 21 | //path: "RustXcframework.xcframework"), 22 | url: 23 | "https://github.com/rustunit/bevy_ios_iap/releases/download/rs-0.7.0/RustXcframework.xcframework.zip", 24 | checksum: "ea7396a6950199a7a25d5d8f35d220c1e3b9052e9bb9c207785c1bd8addb85e9"), 25 | .target( 26 | name: "bevy_ios_iap", 27 | dependencies: ["RustXcframework"]), 28 | .testTarget( 29 | name: "bevy_ios_iapTests", 30 | dependencies: ["bevy_ios_iap"]), 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bevy_ios_iap 2 | 3 | [![crates.io][sh_crates]][lk_crates] 4 | [![docs.rs][sh_docs]][lk_docs] 5 | [![discord][sh_discord]][lk_discord] 6 | 7 | [sh_crates]: https://img.shields.io/crates/v/bevy_ios_iap.svg 8 | [lk_crates]: https://crates.io/crates/bevy_ios_iap 9 | [sh_docs]: https://img.shields.io/docsrs/bevy_ios_iap 10 | [lk_docs]: https://docs.rs/bevy_ios_iap/latest/bevy_ios_iap/ 11 | [sh_discord]: https://img.shields.io/discord/1176858176897953872?label=discord&color=5561E6 12 | [lk_discord]: https://discord.gg/rQNeEnMhus 13 | 14 | Provides access to iOS native StoreKit2 Swift API from inside Bevy Apps. 15 | It uses [Swift-Bridge](https://github.com/chinedufn/swift-bridge) to auto-generate the glue code and transport datatypes. 16 | 17 | ![demo](./assets/demo.gif) 18 | 19 | > Demo from our game using this crate: [zoolitaire.com](https://zoolitaire.com) 20 | 21 | ## Features 22 | * fetch products 23 | * purchase products 24 | * listen to changes in transaction states 25 | * fetch list of all transactions (to restore old purchases of non-consumables) 26 | * supports subscriptions 27 | * convenient observer based API 28 | * egui based debug ui crate see [bevy_ios_iap_egui folder](./bevy_ios_iap_egui/README.md) 29 | 30 | ## Notes 31 | * does not return locally un-signed/un-verified transactions 32 | 33 | ## Todo 34 | * allow access to signature for remote verification 35 | * support offers 36 | * support family sharing 37 | 38 | ## Instructions 39 | 40 | 1. Add to XCode: Add SPM (Swift Package Manager) dependency 41 | 2. Add Rust dependency 42 | 3. Setup Plugin 43 | 44 | ### 1. Add to XCode 45 | 46 | * Add `StoreKit` framework: 47 | ![gamekit](./assets/framework.png) 48 | 49 | * Go to `File` -> `Add Package Dependencies` and paste `https://github.com/rustunit/bevy_ios_iap.git` into the search bar on the top right: 50 | ![xcode](./assets/xcode-spm.png) 51 | 52 | * Don't forget to configure your purchases like for any other iOS app, this guide will not focus on that, as it is the same no matter what engine you use. this guide focuses on setting things up in a bevy project. 53 | 54 | **Note:** 55 | The rust crate used must be **exactly** the same version as the Swift Package (for binary compatibility reasons). 56 | I suggest using a specific version (like `0.2.0` in the screenshot) to make sure to always use binary matching versions! 57 | 58 | ### 2. Add Rust dependency 59 | 60 | ``` 61 | cargo add bevy_ios_iap 62 | ``` 63 | 64 | or 65 | 66 | ```toml 67 | # always pin to the same exact version you also of the Swift package 68 | bevy_ios_iap = { version = "=0.2.1" } 69 | ``` 70 | 71 | ### 3. Setup Plugin 72 | 73 | Initialize Bevy Plugin: 74 | 75 | ```rust 76 | // request initialisation right on startup 77 | app.add_plugins(IosIapPlugin::new(true)); 78 | ``` 79 | 80 | ```rust 81 | fn bevy_system(mut iap: BevyIosIap) { 82 | // If you set the plugin to manual init, this will register the 83 | // TranscactionObserver to listen to updates to any Transactions and trigger 84 | // `IosIapEvents::Transaction` accordingly. 85 | // Note: this will require the user to be logged in into their apple-id and popup a login dialog if not 86 | bevy_ios_iap::init(); 87 | 88 | // request product details, product IDs have to be explicitly provided 89 | iap.products(vec!["com.rustunit.zoolitaire.levelunlock".into()]) 90 | .on_response(|trigger: Trigger| match &trigger.event().0 { 91 | IosIapProductsResponse::Done(products) => { 92 | info!("products loaded: {}", products.len()); 93 | 94 | for p in products { 95 | info!("product: {:?}", p); 96 | } 97 | } 98 | IosIapProductsResponse::Error(e) => error!("error fetching products: {e}"), 99 | }); 100 | 101 | // trigger a product purchase for a specific product ID 102 | iap.purchase("com.rustunit.zoolitaire.levelunlock".into()) 103 | .on_response(|trigger: Trigger|{ 104 | match &trigger.event().0 { 105 | IosIapPurchaseResponse::Success(t) => { 106 | info!("just purchased: '{}' {}", t.product_id, t.id); 107 | 108 | iap.finish_transaction(t.id).on_response(on_finish_transaction); 109 | } 110 | _ => {} 111 | } 112 | }); 113 | 114 | // request to restore active subscriptions and non-consumables 115 | iap.current_entitlements() 116 | .on_response(|trigger: Trigger|{ 117 | info!("current entitlements: {}", trigger.event()); 118 | }); 119 | } 120 | ``` 121 | 122 | Process Response Events from iOS back to us in Rust: 123 | 124 | ```rust 125 | fn process_iap_events( 126 | mut events: EventReader, 127 | ) { 128 | for e in events.read() { 129 | match e { 130 | // this is triggered when a transaction verification state changes during the runtime of the app 131 | IosIapEvents::TransactionUpdate(_) => todo!(), 132 | } 133 | } 134 | } 135 | ``` 136 | 137 | ## Local development 138 | 139 | 1. Build locally via `just build` 140 | 2. Change the `Package.swift` to use the locally built `xcframework` 141 | 3. Switch XCode package dependency to use local repo via path 142 | 4. Patch `Cargo.toml` to use local repository 143 | 144 | ## Our Other Crates 145 | 146 | - [bevy_debug_log](https://github.com/rustunit/bevy_debug_log) 147 | - [bevy_device_lang](https://github.com/rustunit/bevy_device_lang) 148 | - [bevy_web_popups](https://github.com/rustunit/bevy_web_popups) 149 | - [bevy_libgdx_atlas](https://github.com/rustunit/bevy_libgdx_atlas) 150 | - [bevy_ios_review](https://github.com/rustunit/bevy_ios_review) 151 | - [bevy_ios_gamecenter](https://github.com/rustunit/bevy_ios_gamecenter) 152 | - [bevy_ios_alerts](https://github.com/rustunit/bevy_ios_alerts) 153 | - [bevy_ios_notifications](https://github.com/rustunit/bevy_ios_notifications) 154 | - [bevy_ios_impact](https://github.com/rustunit/bevy_ios_impact) 155 | - [bevy_ios_safearea](https://github.com/rustunit/bevy_ios_safearea) 156 | 157 | ## Bevy version support 158 | 159 | |bevy|crate| 160 | |---|---| 161 | |0.16|0.6,main| 162 | |0.15|0.5| 163 | |0.14|0.3,0.4| 164 | |0.13|0.2| 165 | 166 | # License 167 | 168 | All code in this repository is dual-licensed under either: 169 | 170 | - MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT) 171 | - Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 172 | 173 | at your option. This means you can select the license you prefer. 174 | 175 | ## Your contributions 176 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. 177 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/.gitignore: -------------------------------------------------------------------------------- 1 | libbevy_ios_iap.a -------------------------------------------------------------------------------- /RustXcframework.xcframework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AvailableLibraries 6 | 7 | 8 | BinaryPath 9 | libbevy_ios_iap.a 10 | HeadersPath 11 | Headers 12 | LibraryIdentifier 13 | ios-arm64_x86_64-simulator 14 | LibraryPath 15 | libbevy_ios_iap.a 16 | SupportedArchitectures 17 | 18 | arm64 19 | x86_64 20 | 21 | SupportedPlatform 22 | ios 23 | SupportedPlatformVariant 24 | simulator 25 | 26 | 27 | BinaryPath 28 | libbevy_ios_iap.a 29 | HeadersPath 30 | Headers 31 | LibraryIdentifier 32 | ios-arm64 33 | LibraryPath 34 | libbevy_ios_iap.a 35 | SupportedArchitectures 36 | 37 | arm64 38 | 39 | SupportedPlatform 40 | ios 41 | 42 | 43 | CFBundlePackageType 44 | XFWK 45 | XCFrameworkFormatVersion 46 | 1.0 47 | 48 | 49 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64/Headers/SwiftBridgeCore.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef struct RustStr { uint8_t* const start; uintptr_t len; } RustStr; 4 | typedef struct __private__FfiSlice { void* const start; uintptr_t len; } __private__FfiSlice; 5 | void* __swift_bridge__null_pointer(void); 6 | 7 | 8 | typedef struct __private__OptionU8 { uint8_t val; bool is_some; } __private__OptionU8; 9 | typedef struct __private__OptionI8 { int8_t val; bool is_some; } __private__OptionI8; 10 | typedef struct __private__OptionU16 { uint16_t val; bool is_some; } __private__OptionU16; 11 | typedef struct __private__OptionI16 { int16_t val; bool is_some; } __private__OptionI16; 12 | typedef struct __private__OptionU32 { uint32_t val; bool is_some; } __private__OptionU32; 13 | typedef struct __private__OptionI32 { int32_t val; bool is_some; } __private__OptionI32; 14 | typedef struct __private__OptionU64 { uint64_t val; bool is_some; } __private__OptionU64; 15 | typedef struct __private__OptionI64 { int64_t val; bool is_some; } __private__OptionI64; 16 | typedef struct __private__OptionUsize { uintptr_t val; bool is_some; } __private__OptionUsize; 17 | typedef struct __private__OptionIsize { intptr_t val; bool is_some; } __private__OptionIsize; 18 | typedef struct __private__OptionF32 { float val; bool is_some; } __private__OptionF32; 19 | typedef struct __private__OptionF64 { double val; bool is_some; } __private__OptionF64; 20 | typedef struct __private__OptionBool { bool val; bool is_some; } __private__OptionBool; 21 | 22 | void* __swift_bridge__$Vec_u8$new(); 23 | void __swift_bridge__$Vec_u8$_free(void* const vec); 24 | uintptr_t __swift_bridge__$Vec_u8$len(void* const vec); 25 | void __swift_bridge__$Vec_u8$push(void* const vec, uint8_t val); 26 | __private__OptionU8 __swift_bridge__$Vec_u8$pop(void* const vec); 27 | __private__OptionU8 __swift_bridge__$Vec_u8$get(void* const vec, uintptr_t index); 28 | __private__OptionU8 __swift_bridge__$Vec_u8$get_mut(void* const vec, uintptr_t index); 29 | uint8_t const * __swift_bridge__$Vec_u8$as_ptr(void* const vec); 30 | 31 | void* __swift_bridge__$Vec_u16$new(); 32 | void __swift_bridge__$Vec_u16$_free(void* const vec); 33 | uintptr_t __swift_bridge__$Vec_u16$len(void* const vec); 34 | void __swift_bridge__$Vec_u16$push(void* const vec, uint16_t val); 35 | __private__OptionU16 __swift_bridge__$Vec_u16$pop(void* const vec); 36 | __private__OptionU16 __swift_bridge__$Vec_u16$get(void* const vec, uintptr_t index); 37 | __private__OptionU16 __swift_bridge__$Vec_u16$get_mut(void* const vec, uintptr_t index); 38 | uint16_t const * __swift_bridge__$Vec_u16$as_ptr(void* const vec); 39 | 40 | void* __swift_bridge__$Vec_u32$new(); 41 | void __swift_bridge__$Vec_u32$_free(void* const vec); 42 | uintptr_t __swift_bridge__$Vec_u32$len(void* const vec); 43 | void __swift_bridge__$Vec_u32$push(void* const vec, uint32_t val); 44 | __private__OptionU32 __swift_bridge__$Vec_u32$pop(void* const vec); 45 | __private__OptionU32 __swift_bridge__$Vec_u32$get(void* const vec, uintptr_t index); 46 | __private__OptionU32 __swift_bridge__$Vec_u32$get_mut(void* const vec, uintptr_t index); 47 | uint32_t const * __swift_bridge__$Vec_u32$as_ptr(void* const vec); 48 | 49 | void* __swift_bridge__$Vec_u64$new(); 50 | void __swift_bridge__$Vec_u64$_free(void* const vec); 51 | uintptr_t __swift_bridge__$Vec_u64$len(void* const vec); 52 | void __swift_bridge__$Vec_u64$push(void* const vec, uint64_t val); 53 | __private__OptionU64 __swift_bridge__$Vec_u64$pop(void* const vec); 54 | __private__OptionU64 __swift_bridge__$Vec_u64$get(void* const vec, uintptr_t index); 55 | __private__OptionU64 __swift_bridge__$Vec_u64$get_mut(void* const vec, uintptr_t index); 56 | uint64_t const * __swift_bridge__$Vec_u64$as_ptr(void* const vec); 57 | 58 | void* __swift_bridge__$Vec_usize$new(); 59 | void __swift_bridge__$Vec_usize$_free(void* const vec); 60 | uintptr_t __swift_bridge__$Vec_usize$len(void* const vec); 61 | void __swift_bridge__$Vec_usize$push(void* const vec, uintptr_t val); 62 | __private__OptionUsize __swift_bridge__$Vec_usize$pop(void* const vec); 63 | __private__OptionUsize __swift_bridge__$Vec_usize$get(void* const vec, uintptr_t index); 64 | __private__OptionUsize __swift_bridge__$Vec_usize$get_mut(void* const vec, uintptr_t index); 65 | uintptr_t const * __swift_bridge__$Vec_usize$as_ptr(void* const vec); 66 | 67 | void* __swift_bridge__$Vec_i8$new(); 68 | void __swift_bridge__$Vec_i8$_free(void* const vec); 69 | uintptr_t __swift_bridge__$Vec_i8$len(void* const vec); 70 | void __swift_bridge__$Vec_i8$push(void* const vec, int8_t val); 71 | __private__OptionI8 __swift_bridge__$Vec_i8$pop(void* const vec); 72 | __private__OptionI8 __swift_bridge__$Vec_i8$get(void* const vec, uintptr_t index); 73 | __private__OptionI8 __swift_bridge__$Vec_i8$get_mut(void* const vec, uintptr_t index); 74 | int8_t const * __swift_bridge__$Vec_i8$as_ptr(void* const vec); 75 | 76 | void* __swift_bridge__$Vec_i16$new(); 77 | void __swift_bridge__$Vec_i16$_free(void* const vec); 78 | uintptr_t __swift_bridge__$Vec_i16$len(void* const vec); 79 | void __swift_bridge__$Vec_i16$push(void* const vec, int16_t val); 80 | __private__OptionI16 __swift_bridge__$Vec_i16$pop(void* const vec); 81 | __private__OptionI16 __swift_bridge__$Vec_i16$get(void* const vec, uintptr_t index); 82 | __private__OptionI16 __swift_bridge__$Vec_i16$get_mut(void* const vec, uintptr_t index); 83 | int16_t const * __swift_bridge__$Vec_i16$as_ptr(void* const vec); 84 | 85 | void* __swift_bridge__$Vec_i32$new(); 86 | void __swift_bridge__$Vec_i32$_free(void* const vec); 87 | uintptr_t __swift_bridge__$Vec_i32$len(void* const vec); 88 | void __swift_bridge__$Vec_i32$push(void* const vec, int32_t val); 89 | __private__OptionI32 __swift_bridge__$Vec_i32$pop(void* const vec); 90 | __private__OptionI32 __swift_bridge__$Vec_i32$get(void* const vec, uintptr_t index); 91 | __private__OptionI32 __swift_bridge__$Vec_i32$get_mut(void* const vec, uintptr_t index); 92 | int32_t const * __swift_bridge__$Vec_i32$as_ptr(void* const vec); 93 | 94 | void* __swift_bridge__$Vec_i64$new(); 95 | void __swift_bridge__$Vec_i64$_free(void* const vec); 96 | uintptr_t __swift_bridge__$Vec_i64$len(void* const vec); 97 | void __swift_bridge__$Vec_i64$push(void* const vec, int64_t val); 98 | __private__OptionI64 __swift_bridge__$Vec_i64$pop(void* const vec); 99 | __private__OptionI64 __swift_bridge__$Vec_i64$get(void* const vec, uintptr_t index); 100 | __private__OptionI64 __swift_bridge__$Vec_i64$get_mut(void* const vec, uintptr_t index); 101 | int64_t const * __swift_bridge__$Vec_i64$as_ptr(void* const vec); 102 | 103 | void* __swift_bridge__$Vec_isize$new(); 104 | void __swift_bridge__$Vec_isize$_free(void* const vec); 105 | uintptr_t __swift_bridge__$Vec_isize$len(void* const vec); 106 | void __swift_bridge__$Vec_isize$push(void* const vec, intptr_t val); 107 | __private__OptionIsize __swift_bridge__$Vec_isize$pop(void* const vec); 108 | __private__OptionIsize __swift_bridge__$Vec_isize$get(void* const vec, uintptr_t index); 109 | __private__OptionIsize __swift_bridge__$Vec_isize$get_mut(void* const vec, uintptr_t index); 110 | intptr_t const * __swift_bridge__$Vec_isize$as_ptr(void* const vec); 111 | 112 | void* __swift_bridge__$Vec_bool$new(); 113 | void __swift_bridge__$Vec_bool$_free(void* const vec); 114 | uintptr_t __swift_bridge__$Vec_bool$len(void* const vec); 115 | void __swift_bridge__$Vec_bool$push(void* const vec, bool val); 116 | __private__OptionBool __swift_bridge__$Vec_bool$pop(void* const vec); 117 | __private__OptionBool __swift_bridge__$Vec_bool$get(void* const vec, uintptr_t index); 118 | __private__OptionBool __swift_bridge__$Vec_bool$get_mut(void* const vec, uintptr_t index); 119 | bool const * __swift_bridge__$Vec_bool$as_ptr(void* const vec); 120 | 121 | void* __swift_bridge__$Vec_f32$new(); 122 | void __swift_bridge__$Vec_f32$_free(void* const vec); 123 | uintptr_t __swift_bridge__$Vec_f32$len(void* const vec); 124 | void __swift_bridge__$Vec_f32$push(void* const vec, float val); 125 | __private__OptionF32 __swift_bridge__$Vec_f32$pop(void* const vec); 126 | __private__OptionF32 __swift_bridge__$Vec_f32$get(void* const vec, uintptr_t index); 127 | __private__OptionF32 __swift_bridge__$Vec_f32$get_mut(void* const vec, uintptr_t index); 128 | float const * __swift_bridge__$Vec_f32$as_ptr(void* const vec); 129 | 130 | void* __swift_bridge__$Vec_f64$new(); 131 | void __swift_bridge__$Vec_f64$_free(void* const vec); 132 | uintptr_t __swift_bridge__$Vec_f64$len(void* const vec); 133 | void __swift_bridge__$Vec_f64$push(void* const vec, double val); 134 | __private__OptionF64 __swift_bridge__$Vec_f64$pop(void* const vec); 135 | __private__OptionF64 __swift_bridge__$Vec_f64$get(void* const vec, uintptr_t index); 136 | __private__OptionF64 __swift_bridge__$Vec_f64$get_mut(void* const vec, uintptr_t index); 137 | double const * __swift_bridge__$Vec_f64$as_ptr(void* const vec); 138 | 139 | #include 140 | typedef struct RustString RustString; 141 | void __swift_bridge__$RustString$_free(void* self); 142 | 143 | void* __swift_bridge__$Vec_RustString$new(void); 144 | void __swift_bridge__$Vec_RustString$drop(void* vec_ptr); 145 | void __swift_bridge__$Vec_RustString$push(void* vec_ptr, void* item_ptr); 146 | void* __swift_bridge__$Vec_RustString$pop(void* vec_ptr); 147 | void* __swift_bridge__$Vec_RustString$get(void* vec_ptr, uintptr_t index); 148 | void* __swift_bridge__$Vec_RustString$get_mut(void* vec_ptr, uintptr_t index); 149 | uintptr_t __swift_bridge__$Vec_RustString$len(void* vec_ptr); 150 | void* __swift_bridge__$Vec_RustString$as_ptr(void* vec_ptr); 151 | 152 | void* __swift_bridge__$RustString$new(void); 153 | void* __swift_bridge__$RustString$new_with_str(struct RustStr str); 154 | uintptr_t __swift_bridge__$RustString$len(void* self); 155 | struct RustStr __swift_bridge__$RustString$as_str(void* self); 156 | struct RustStr __swift_bridge__$RustString$trim(void* self); 157 | bool __swift_bridge__$RustStr$partial_eq(struct RustStr lhs, struct RustStr rhs); 158 | 159 | 160 | void __swift_bridge__$call_boxed_fn_once_no_args_no_return(void* boxed_fnonce); 161 | void __swift_bridge__$free_boxed_fn_once_no_args_no_return(void* boxed_fnonce); 162 | 163 | 164 | struct __private__ResultPtrAndPtr { bool is_ok; void* ok_or_err; }; 165 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64/Headers/bevy_ios_iap.h: -------------------------------------------------------------------------------- 1 | // File automatically generated by swift-bridge. 2 | #include 3 | #include 4 | typedef struct IosIapTransactionFinishResponse IosIapTransactionFinishResponse; 5 | void __swift_bridge__$IosIapTransactionFinishResponse$_free(void* self); 6 | 7 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$new(void); 8 | void __swift_bridge__$Vec_IosIapTransactionFinishResponse$drop(void* vec_ptr); 9 | void __swift_bridge__$Vec_IosIapTransactionFinishResponse$push(void* vec_ptr, void* item_ptr); 10 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$pop(void* vec_ptr); 11 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$get(void* vec_ptr, uintptr_t index); 12 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$get_mut(void* vec_ptr, uintptr_t index); 13 | uintptr_t __swift_bridge__$Vec_IosIapTransactionFinishResponse$len(void* vec_ptr); 14 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$as_ptr(void* vec_ptr); 15 | 16 | typedef struct IosIapTransactionResponse IosIapTransactionResponse; 17 | void __swift_bridge__$IosIapTransactionResponse$_free(void* self); 18 | 19 | void* __swift_bridge__$Vec_IosIapTransactionResponse$new(void); 20 | void __swift_bridge__$Vec_IosIapTransactionResponse$drop(void* vec_ptr); 21 | void __swift_bridge__$Vec_IosIapTransactionResponse$push(void* vec_ptr, void* item_ptr); 22 | void* __swift_bridge__$Vec_IosIapTransactionResponse$pop(void* vec_ptr); 23 | void* __swift_bridge__$Vec_IosIapTransactionResponse$get(void* vec_ptr, uintptr_t index); 24 | void* __swift_bridge__$Vec_IosIapTransactionResponse$get_mut(void* vec_ptr, uintptr_t index); 25 | uintptr_t __swift_bridge__$Vec_IosIapTransactionResponse$len(void* vec_ptr); 26 | void* __swift_bridge__$Vec_IosIapTransactionResponse$as_ptr(void* vec_ptr); 27 | 28 | typedef struct IosIapProductsResponse IosIapProductsResponse; 29 | void __swift_bridge__$IosIapProductsResponse$_free(void* self); 30 | 31 | void* __swift_bridge__$Vec_IosIapProductsResponse$new(void); 32 | void __swift_bridge__$Vec_IosIapProductsResponse$drop(void* vec_ptr); 33 | void __swift_bridge__$Vec_IosIapProductsResponse$push(void* vec_ptr, void* item_ptr); 34 | void* __swift_bridge__$Vec_IosIapProductsResponse$pop(void* vec_ptr); 35 | void* __swift_bridge__$Vec_IosIapProductsResponse$get(void* vec_ptr, uintptr_t index); 36 | void* __swift_bridge__$Vec_IosIapProductsResponse$get_mut(void* vec_ptr, uintptr_t index); 37 | uintptr_t __swift_bridge__$Vec_IosIapProductsResponse$len(void* vec_ptr); 38 | void* __swift_bridge__$Vec_IosIapProductsResponse$as_ptr(void* vec_ptr); 39 | 40 | typedef struct IosIapRevocationReason IosIapRevocationReason; 41 | void __swift_bridge__$IosIapRevocationReason$_free(void* self); 42 | 43 | void* __swift_bridge__$Vec_IosIapRevocationReason$new(void); 44 | void __swift_bridge__$Vec_IosIapRevocationReason$drop(void* vec_ptr); 45 | void __swift_bridge__$Vec_IosIapRevocationReason$push(void* vec_ptr, void* item_ptr); 46 | void* __swift_bridge__$Vec_IosIapRevocationReason$pop(void* vec_ptr); 47 | void* __swift_bridge__$Vec_IosIapRevocationReason$get(void* vec_ptr, uintptr_t index); 48 | void* __swift_bridge__$Vec_IosIapRevocationReason$get_mut(void* vec_ptr, uintptr_t index); 49 | uintptr_t __swift_bridge__$Vec_IosIapRevocationReason$len(void* vec_ptr); 50 | void* __swift_bridge__$Vec_IosIapRevocationReason$as_ptr(void* vec_ptr); 51 | 52 | typedef struct IosIapCurrency IosIapCurrency; 53 | void __swift_bridge__$IosIapCurrency$_free(void* self); 54 | 55 | void* __swift_bridge__$Vec_IosIapCurrency$new(void); 56 | void __swift_bridge__$Vec_IosIapCurrency$drop(void* vec_ptr); 57 | void __swift_bridge__$Vec_IosIapCurrency$push(void* vec_ptr, void* item_ptr); 58 | void* __swift_bridge__$Vec_IosIapCurrency$pop(void* vec_ptr); 59 | void* __swift_bridge__$Vec_IosIapCurrency$get(void* vec_ptr, uintptr_t index); 60 | void* __swift_bridge__$Vec_IosIapCurrency$get_mut(void* vec_ptr, uintptr_t index); 61 | uintptr_t __swift_bridge__$Vec_IosIapCurrency$len(void* vec_ptr); 62 | void* __swift_bridge__$Vec_IosIapCurrency$as_ptr(void* vec_ptr); 63 | 64 | typedef struct IosIapSubscriptionRenewalState IosIapSubscriptionRenewalState; 65 | void __swift_bridge__$IosIapSubscriptionRenewalState$_free(void* self); 66 | 67 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$new(void); 68 | void __swift_bridge__$Vec_IosIapSubscriptionRenewalState$drop(void* vec_ptr); 69 | void __swift_bridge__$Vec_IosIapSubscriptionRenewalState$push(void* vec_ptr, void* item_ptr); 70 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$pop(void* vec_ptr); 71 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$get(void* vec_ptr, uintptr_t index); 72 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$get_mut(void* vec_ptr, uintptr_t index); 73 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionRenewalState$len(void* vec_ptr); 74 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$as_ptr(void* vec_ptr); 75 | 76 | typedef struct IosIapSubscriptionStatus IosIapSubscriptionStatus; 77 | void __swift_bridge__$IosIapSubscriptionStatus$_free(void* self); 78 | 79 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$new(void); 80 | void __swift_bridge__$Vec_IosIapSubscriptionStatus$drop(void* vec_ptr); 81 | void __swift_bridge__$Vec_IosIapSubscriptionStatus$push(void* vec_ptr, void* item_ptr); 82 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$pop(void* vec_ptr); 83 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$get(void* vec_ptr, uintptr_t index); 84 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$get_mut(void* vec_ptr, uintptr_t index); 85 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionStatus$len(void* vec_ptr); 86 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$as_ptr(void* vec_ptr); 87 | 88 | typedef struct IosIapSubscriptionPeriodUnit IosIapSubscriptionPeriodUnit; 89 | void __swift_bridge__$IosIapSubscriptionPeriodUnit$_free(void* self); 90 | 91 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$new(void); 92 | void __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$drop(void* vec_ptr); 93 | void __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$push(void* vec_ptr, void* item_ptr); 94 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$pop(void* vec_ptr); 95 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$get(void* vec_ptr, uintptr_t index); 96 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$get_mut(void* vec_ptr, uintptr_t index); 97 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$len(void* vec_ptr); 98 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$as_ptr(void* vec_ptr); 99 | 100 | typedef struct IosIapSubscriptionPeriod IosIapSubscriptionPeriod; 101 | void __swift_bridge__$IosIapSubscriptionPeriod$_free(void* self); 102 | 103 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$new(void); 104 | void __swift_bridge__$Vec_IosIapSubscriptionPeriod$drop(void* vec_ptr); 105 | void __swift_bridge__$Vec_IosIapSubscriptionPeriod$push(void* vec_ptr, void* item_ptr); 106 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$pop(void* vec_ptr); 107 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$get(void* vec_ptr, uintptr_t index); 108 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$get_mut(void* vec_ptr, uintptr_t index); 109 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionPeriod$len(void* vec_ptr); 110 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$as_ptr(void* vec_ptr); 111 | 112 | typedef struct IosIapSubscriptionInfo IosIapSubscriptionInfo; 113 | void __swift_bridge__$IosIapSubscriptionInfo$_free(void* self); 114 | 115 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$new(void); 116 | void __swift_bridge__$Vec_IosIapSubscriptionInfo$drop(void* vec_ptr); 117 | void __swift_bridge__$Vec_IosIapSubscriptionInfo$push(void* vec_ptr, void* item_ptr); 118 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$pop(void* vec_ptr); 119 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$get(void* vec_ptr, uintptr_t index); 120 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$get_mut(void* vec_ptr, uintptr_t index); 121 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionInfo$len(void* vec_ptr); 122 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$as_ptr(void* vec_ptr); 123 | 124 | typedef struct IosIapStorefront IosIapStorefront; 125 | void __swift_bridge__$IosIapStorefront$_free(void* self); 126 | 127 | void* __swift_bridge__$Vec_IosIapStorefront$new(void); 128 | void __swift_bridge__$Vec_IosIapStorefront$drop(void* vec_ptr); 129 | void __swift_bridge__$Vec_IosIapStorefront$push(void* vec_ptr, void* item_ptr); 130 | void* __swift_bridge__$Vec_IosIapStorefront$pop(void* vec_ptr); 131 | void* __swift_bridge__$Vec_IosIapStorefront$get(void* vec_ptr, uintptr_t index); 132 | void* __swift_bridge__$Vec_IosIapStorefront$get_mut(void* vec_ptr, uintptr_t index); 133 | uintptr_t __swift_bridge__$Vec_IosIapStorefront$len(void* vec_ptr); 134 | void* __swift_bridge__$Vec_IosIapStorefront$as_ptr(void* vec_ptr); 135 | 136 | typedef struct IosIapEnvironment IosIapEnvironment; 137 | void __swift_bridge__$IosIapEnvironment$_free(void* self); 138 | 139 | void* __swift_bridge__$Vec_IosIapEnvironment$new(void); 140 | void __swift_bridge__$Vec_IosIapEnvironment$drop(void* vec_ptr); 141 | void __swift_bridge__$Vec_IosIapEnvironment$push(void* vec_ptr, void* item_ptr); 142 | void* __swift_bridge__$Vec_IosIapEnvironment$pop(void* vec_ptr); 143 | void* __swift_bridge__$Vec_IosIapEnvironment$get(void* vec_ptr, uintptr_t index); 144 | void* __swift_bridge__$Vec_IosIapEnvironment$get_mut(void* vec_ptr, uintptr_t index); 145 | uintptr_t __swift_bridge__$Vec_IosIapEnvironment$len(void* vec_ptr); 146 | void* __swift_bridge__$Vec_IosIapEnvironment$as_ptr(void* vec_ptr); 147 | 148 | typedef struct IosIapTransactionReason IosIapTransactionReason; 149 | void __swift_bridge__$IosIapTransactionReason$_free(void* self); 150 | 151 | void* __swift_bridge__$Vec_IosIapTransactionReason$new(void); 152 | void __swift_bridge__$Vec_IosIapTransactionReason$drop(void* vec_ptr); 153 | void __swift_bridge__$Vec_IosIapTransactionReason$push(void* vec_ptr, void* item_ptr); 154 | void* __swift_bridge__$Vec_IosIapTransactionReason$pop(void* vec_ptr); 155 | void* __swift_bridge__$Vec_IosIapTransactionReason$get(void* vec_ptr, uintptr_t index); 156 | void* __swift_bridge__$Vec_IosIapTransactionReason$get_mut(void* vec_ptr, uintptr_t index); 157 | uintptr_t __swift_bridge__$Vec_IosIapTransactionReason$len(void* vec_ptr); 158 | void* __swift_bridge__$Vec_IosIapTransactionReason$as_ptr(void* vec_ptr); 159 | 160 | typedef struct IosIapTransaction IosIapTransaction; 161 | void __swift_bridge__$IosIapTransaction$_free(void* self); 162 | 163 | void* __swift_bridge__$Vec_IosIapTransaction$new(void); 164 | void __swift_bridge__$Vec_IosIapTransaction$drop(void* vec_ptr); 165 | void __swift_bridge__$Vec_IosIapTransaction$push(void* vec_ptr, void* item_ptr); 166 | void* __swift_bridge__$Vec_IosIapTransaction$pop(void* vec_ptr); 167 | void* __swift_bridge__$Vec_IosIapTransaction$get(void* vec_ptr, uintptr_t index); 168 | void* __swift_bridge__$Vec_IosIapTransaction$get_mut(void* vec_ptr, uintptr_t index); 169 | uintptr_t __swift_bridge__$Vec_IosIapTransaction$len(void* vec_ptr); 170 | void* __swift_bridge__$Vec_IosIapTransaction$as_ptr(void* vec_ptr); 171 | 172 | typedef struct IosIapStoreKitError IosIapStoreKitError; 173 | void __swift_bridge__$IosIapStoreKitError$_free(void* self); 174 | 175 | void* __swift_bridge__$Vec_IosIapStoreKitError$new(void); 176 | void __swift_bridge__$Vec_IosIapStoreKitError$drop(void* vec_ptr); 177 | void __swift_bridge__$Vec_IosIapStoreKitError$push(void* vec_ptr, void* item_ptr); 178 | void* __swift_bridge__$Vec_IosIapStoreKitError$pop(void* vec_ptr); 179 | void* __swift_bridge__$Vec_IosIapStoreKitError$get(void* vec_ptr, uintptr_t index); 180 | void* __swift_bridge__$Vec_IosIapStoreKitError$get_mut(void* vec_ptr, uintptr_t index); 181 | uintptr_t __swift_bridge__$Vec_IosIapStoreKitError$len(void* vec_ptr); 182 | void* __swift_bridge__$Vec_IosIapStoreKitError$as_ptr(void* vec_ptr); 183 | 184 | typedef struct IosIapPurchaseError IosIapPurchaseError; 185 | void __swift_bridge__$IosIapPurchaseError$_free(void* self); 186 | 187 | void* __swift_bridge__$Vec_IosIapPurchaseError$new(void); 188 | void __swift_bridge__$Vec_IosIapPurchaseError$drop(void* vec_ptr); 189 | void __swift_bridge__$Vec_IosIapPurchaseError$push(void* vec_ptr, void* item_ptr); 190 | void* __swift_bridge__$Vec_IosIapPurchaseError$pop(void* vec_ptr); 191 | void* __swift_bridge__$Vec_IosIapPurchaseError$get(void* vec_ptr, uintptr_t index); 192 | void* __swift_bridge__$Vec_IosIapPurchaseError$get_mut(void* vec_ptr, uintptr_t index); 193 | uintptr_t __swift_bridge__$Vec_IosIapPurchaseError$len(void* vec_ptr); 194 | void* __swift_bridge__$Vec_IosIapPurchaseError$as_ptr(void* vec_ptr); 195 | 196 | typedef struct IosIapPurchaseResponse IosIapPurchaseResponse; 197 | void __swift_bridge__$IosIapPurchaseResponse$_free(void* self); 198 | 199 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$new(void); 200 | void __swift_bridge__$Vec_IosIapPurchaseResponse$drop(void* vec_ptr); 201 | void __swift_bridge__$Vec_IosIapPurchaseResponse$push(void* vec_ptr, void* item_ptr); 202 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$pop(void* vec_ptr); 203 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$get(void* vec_ptr, uintptr_t index); 204 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$get_mut(void* vec_ptr, uintptr_t index); 205 | uintptr_t __swift_bridge__$Vec_IosIapPurchaseResponse$len(void* vec_ptr); 206 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$as_ptr(void* vec_ptr); 207 | 208 | typedef struct IosIapProductType IosIapProductType; 209 | void __swift_bridge__$IosIapProductType$_free(void* self); 210 | 211 | void* __swift_bridge__$Vec_IosIapProductType$new(void); 212 | void __swift_bridge__$Vec_IosIapProductType$drop(void* vec_ptr); 213 | void __swift_bridge__$Vec_IosIapProductType$push(void* vec_ptr, void* item_ptr); 214 | void* __swift_bridge__$Vec_IosIapProductType$pop(void* vec_ptr); 215 | void* __swift_bridge__$Vec_IosIapProductType$get(void* vec_ptr, uintptr_t index); 216 | void* __swift_bridge__$Vec_IosIapProductType$get_mut(void* vec_ptr, uintptr_t index); 217 | uintptr_t __swift_bridge__$Vec_IosIapProductType$len(void* vec_ptr); 218 | void* __swift_bridge__$Vec_IosIapProductType$as_ptr(void* vec_ptr); 219 | 220 | typedef struct IosIapProduct IosIapProduct; 221 | void __swift_bridge__$IosIapProduct$_free(void* self); 222 | 223 | void* __swift_bridge__$Vec_IosIapProduct$new(void); 224 | void __swift_bridge__$Vec_IosIapProduct$drop(void* vec_ptr); 225 | void __swift_bridge__$Vec_IosIapProduct$push(void* vec_ptr, void* item_ptr); 226 | void* __swift_bridge__$Vec_IosIapProduct$pop(void* vec_ptr); 227 | void* __swift_bridge__$Vec_IosIapProduct$get(void* vec_ptr, uintptr_t index); 228 | void* __swift_bridge__$Vec_IosIapProduct$get_mut(void* vec_ptr, uintptr_t index); 229 | uintptr_t __swift_bridge__$Vec_IosIapProduct$len(void* vec_ptr); 230 | void* __swift_bridge__$Vec_IosIapProduct$as_ptr(void* vec_ptr); 231 | 232 | void* __swift_bridge__$IosIapProduct$new(void* id, void* display_price, void* display_name, void* description, double price, void* product_type); 233 | void __swift_bridge__$IosIapProduct$subscription(void* t, void* info); 234 | void* __swift_bridge__$IosIapProductType$new_consumable(bool non); 235 | void* __swift_bridge__$IosIapProductType$new_non_renewable(void); 236 | void* __swift_bridge__$IosIapProductType$new_auto_renewable(void); 237 | void* __swift_bridge__$IosIapPurchaseResponse$success(void* t); 238 | void* __swift_bridge__$IosIapPurchaseResponse$canceled(void* id); 239 | void* __swift_bridge__$IosIapPurchaseResponse$pending(void* id); 240 | void* __swift_bridge__$IosIapPurchaseResponse$unknown(void* id); 241 | void* __swift_bridge__$IosIapPurchaseResponse$error(void* e); 242 | void* __swift_bridge__$IosIapPurchaseResponse$purchase_error(void* error, void* localized_description); 243 | void* __swift_bridge__$IosIapPurchaseResponse$storekit_error(void* error, void* localized_description); 244 | void* __swift_bridge__$IosIapPurchaseError$invalid_quantity(void); 245 | void* __swift_bridge__$IosIapPurchaseError$product_unavailable(void); 246 | void* __swift_bridge__$IosIapPurchaseError$purchase_not_allowed(void); 247 | void* __swift_bridge__$IosIapPurchaseError$ineligible_for_offer(void); 248 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_identifier(void); 249 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_price(void); 250 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_signature(void); 251 | void* __swift_bridge__$IosIapPurchaseError$missing_offer_parameters(void); 252 | void* __swift_bridge__$IosIapStoreKitError$unknown(void); 253 | void* __swift_bridge__$IosIapStoreKitError$user_cancelled(void); 254 | void* __swift_bridge__$IosIapStoreKitError$network_error(void* e); 255 | void* __swift_bridge__$IosIapStoreKitError$system_error(void* e); 256 | void* __swift_bridge__$IosIapStoreKitError$not_available_in_storefront(void); 257 | void* __swift_bridge__$IosIapStoreKitError$not_entitled(void); 258 | void* __swift_bridge__$IosIapEnvironment$sandbox(void); 259 | void* __swift_bridge__$IosIapEnvironment$production(void); 260 | void* __swift_bridge__$IosIapEnvironment$xcode(void); 261 | void* __swift_bridge__$IosIapStorefront$storefront(void* id, void* country_code); 262 | void* __swift_bridge__$IosIapTransaction$new_transaction(uint64_t id, void* product_id, void* app_bundle_id, uint64_t purchase_date, uint64_t original_purchase_date, int32_t purchased_quantity, void* storefront_country_code, uint64_t signed_date, bool is_upgraded, uint64_t original_id, void* json_representation, void* product_type, void* environment); 263 | void __swift_bridge__$IosIapTransaction$add_storefront(void* t, void* store); 264 | void __swift_bridge__$IosIapTransaction$add_reason(void* t, void* reason); 265 | void __swift_bridge__$IosIapTransaction$add_revocation(void* t, uint64_t date); 266 | void __swift_bridge__$IosIapTransaction$add_expiration(void* t, uint64_t date); 267 | void __swift_bridge__$IosIapTransaction$add_currency(void* t, void* currency); 268 | void __swift_bridge__$IosIapTransaction$revocation_reason(void* t, void* reason); 269 | void __swift_bridge__$IosIapTransaction$web_order_line_item_id(void* t, void* id); 270 | void __swift_bridge__$IosIapTransaction$subscription_group_id(void* t, void* id); 271 | void __swift_bridge__$IosIapTransaction$app_account_token(void* t, void* uuid); 272 | void* __swift_bridge__$IosIapTransactionReason$renewal(void); 273 | void* __swift_bridge__$IosIapTransactionReason$purchase(void); 274 | void* __swift_bridge__$IosIapTransactionFinishResponse$finished(void* t); 275 | void* __swift_bridge__$IosIapTransactionFinishResponse$error(void* e); 276 | void* __swift_bridge__$IosIapTransactionFinishResponse$unknown(uint64_t id); 277 | void* __swift_bridge__$IosIapSubscriptionInfo$new(void* group_id, void* period, bool is_eligible_for_intro_offer, void* state); 278 | void* __swift_bridge__$IosIapSubscriptionPeriod$new(void* unit, int32_t value); 279 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$day(void); 280 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$week(void); 281 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$month(void); 282 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$year(void); 283 | void* __swift_bridge__$IosIapSubscriptionRenewalState$subscribed(void); 284 | void* __swift_bridge__$IosIapSubscriptionRenewalState$expired(void); 285 | void* __swift_bridge__$IosIapSubscriptionRenewalState$in_billing_retry_period(void); 286 | void* __swift_bridge__$IosIapSubscriptionRenewalState$in_grace_period(void); 287 | void* __swift_bridge__$IosIapSubscriptionRenewalState$revoked(void); 288 | void* __swift_bridge__$IosIapSubscriptionStatus$new(void* state, void* transaction); 289 | void* __swift_bridge__$IosIapCurrency$new(void* identifier, bool is_iso_currency); 290 | void* __swift_bridge__$IosIapRevocationReason$developer_issue(void); 291 | void* __swift_bridge__$IosIapRevocationReason$other(void); 292 | void* __swift_bridge__$IosIapProductsResponse$done(void* items); 293 | void* __swift_bridge__$IosIapProductsResponse$error(void* error); 294 | void* __swift_bridge__$IosIapTransactionResponse$done(void* items); 295 | void* __swift_bridge__$IosIapTransactionResponse$error(void* error); 296 | void __swift_bridge__$products_received(int64_t request, void* response); 297 | void __swift_bridge__$all_transactions(int64_t request, void* response); 298 | void __swift_bridge__$current_entitlements(int64_t request, void* response); 299 | void __swift_bridge__$purchase_processed(int64_t request, void* result); 300 | void __swift_bridge__$transaction_update(void* t); 301 | void __swift_bridge__$transaction_finished(int64_t request, void* t); 302 | 303 | 304 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64/Headers/module.modulemap: -------------------------------------------------------------------------------- 1 | module RustXcframework { 2 | header "SwiftBridgeCore.h" 3 | header "bevy_ios_iap.h" 4 | export * 5 | } 6 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64_x86_64-simulator/Headers/SwiftBridgeCore.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef struct RustStr { uint8_t* const start; uintptr_t len; } RustStr; 4 | typedef struct __private__FfiSlice { void* const start; uintptr_t len; } __private__FfiSlice; 5 | void* __swift_bridge__null_pointer(void); 6 | 7 | 8 | typedef struct __private__OptionU8 { uint8_t val; bool is_some; } __private__OptionU8; 9 | typedef struct __private__OptionI8 { int8_t val; bool is_some; } __private__OptionI8; 10 | typedef struct __private__OptionU16 { uint16_t val; bool is_some; } __private__OptionU16; 11 | typedef struct __private__OptionI16 { int16_t val; bool is_some; } __private__OptionI16; 12 | typedef struct __private__OptionU32 { uint32_t val; bool is_some; } __private__OptionU32; 13 | typedef struct __private__OptionI32 { int32_t val; bool is_some; } __private__OptionI32; 14 | typedef struct __private__OptionU64 { uint64_t val; bool is_some; } __private__OptionU64; 15 | typedef struct __private__OptionI64 { int64_t val; bool is_some; } __private__OptionI64; 16 | typedef struct __private__OptionUsize { uintptr_t val; bool is_some; } __private__OptionUsize; 17 | typedef struct __private__OptionIsize { intptr_t val; bool is_some; } __private__OptionIsize; 18 | typedef struct __private__OptionF32 { float val; bool is_some; } __private__OptionF32; 19 | typedef struct __private__OptionF64 { double val; bool is_some; } __private__OptionF64; 20 | typedef struct __private__OptionBool { bool val; bool is_some; } __private__OptionBool; 21 | 22 | void* __swift_bridge__$Vec_u8$new(); 23 | void __swift_bridge__$Vec_u8$_free(void* const vec); 24 | uintptr_t __swift_bridge__$Vec_u8$len(void* const vec); 25 | void __swift_bridge__$Vec_u8$push(void* const vec, uint8_t val); 26 | __private__OptionU8 __swift_bridge__$Vec_u8$pop(void* const vec); 27 | __private__OptionU8 __swift_bridge__$Vec_u8$get(void* const vec, uintptr_t index); 28 | __private__OptionU8 __swift_bridge__$Vec_u8$get_mut(void* const vec, uintptr_t index); 29 | uint8_t const * __swift_bridge__$Vec_u8$as_ptr(void* const vec); 30 | 31 | void* __swift_bridge__$Vec_u16$new(); 32 | void __swift_bridge__$Vec_u16$_free(void* const vec); 33 | uintptr_t __swift_bridge__$Vec_u16$len(void* const vec); 34 | void __swift_bridge__$Vec_u16$push(void* const vec, uint16_t val); 35 | __private__OptionU16 __swift_bridge__$Vec_u16$pop(void* const vec); 36 | __private__OptionU16 __swift_bridge__$Vec_u16$get(void* const vec, uintptr_t index); 37 | __private__OptionU16 __swift_bridge__$Vec_u16$get_mut(void* const vec, uintptr_t index); 38 | uint16_t const * __swift_bridge__$Vec_u16$as_ptr(void* const vec); 39 | 40 | void* __swift_bridge__$Vec_u32$new(); 41 | void __swift_bridge__$Vec_u32$_free(void* const vec); 42 | uintptr_t __swift_bridge__$Vec_u32$len(void* const vec); 43 | void __swift_bridge__$Vec_u32$push(void* const vec, uint32_t val); 44 | __private__OptionU32 __swift_bridge__$Vec_u32$pop(void* const vec); 45 | __private__OptionU32 __swift_bridge__$Vec_u32$get(void* const vec, uintptr_t index); 46 | __private__OptionU32 __swift_bridge__$Vec_u32$get_mut(void* const vec, uintptr_t index); 47 | uint32_t const * __swift_bridge__$Vec_u32$as_ptr(void* const vec); 48 | 49 | void* __swift_bridge__$Vec_u64$new(); 50 | void __swift_bridge__$Vec_u64$_free(void* const vec); 51 | uintptr_t __swift_bridge__$Vec_u64$len(void* const vec); 52 | void __swift_bridge__$Vec_u64$push(void* const vec, uint64_t val); 53 | __private__OptionU64 __swift_bridge__$Vec_u64$pop(void* const vec); 54 | __private__OptionU64 __swift_bridge__$Vec_u64$get(void* const vec, uintptr_t index); 55 | __private__OptionU64 __swift_bridge__$Vec_u64$get_mut(void* const vec, uintptr_t index); 56 | uint64_t const * __swift_bridge__$Vec_u64$as_ptr(void* const vec); 57 | 58 | void* __swift_bridge__$Vec_usize$new(); 59 | void __swift_bridge__$Vec_usize$_free(void* const vec); 60 | uintptr_t __swift_bridge__$Vec_usize$len(void* const vec); 61 | void __swift_bridge__$Vec_usize$push(void* const vec, uintptr_t val); 62 | __private__OptionUsize __swift_bridge__$Vec_usize$pop(void* const vec); 63 | __private__OptionUsize __swift_bridge__$Vec_usize$get(void* const vec, uintptr_t index); 64 | __private__OptionUsize __swift_bridge__$Vec_usize$get_mut(void* const vec, uintptr_t index); 65 | uintptr_t const * __swift_bridge__$Vec_usize$as_ptr(void* const vec); 66 | 67 | void* __swift_bridge__$Vec_i8$new(); 68 | void __swift_bridge__$Vec_i8$_free(void* const vec); 69 | uintptr_t __swift_bridge__$Vec_i8$len(void* const vec); 70 | void __swift_bridge__$Vec_i8$push(void* const vec, int8_t val); 71 | __private__OptionI8 __swift_bridge__$Vec_i8$pop(void* const vec); 72 | __private__OptionI8 __swift_bridge__$Vec_i8$get(void* const vec, uintptr_t index); 73 | __private__OptionI8 __swift_bridge__$Vec_i8$get_mut(void* const vec, uintptr_t index); 74 | int8_t const * __swift_bridge__$Vec_i8$as_ptr(void* const vec); 75 | 76 | void* __swift_bridge__$Vec_i16$new(); 77 | void __swift_bridge__$Vec_i16$_free(void* const vec); 78 | uintptr_t __swift_bridge__$Vec_i16$len(void* const vec); 79 | void __swift_bridge__$Vec_i16$push(void* const vec, int16_t val); 80 | __private__OptionI16 __swift_bridge__$Vec_i16$pop(void* const vec); 81 | __private__OptionI16 __swift_bridge__$Vec_i16$get(void* const vec, uintptr_t index); 82 | __private__OptionI16 __swift_bridge__$Vec_i16$get_mut(void* const vec, uintptr_t index); 83 | int16_t const * __swift_bridge__$Vec_i16$as_ptr(void* const vec); 84 | 85 | void* __swift_bridge__$Vec_i32$new(); 86 | void __swift_bridge__$Vec_i32$_free(void* const vec); 87 | uintptr_t __swift_bridge__$Vec_i32$len(void* const vec); 88 | void __swift_bridge__$Vec_i32$push(void* const vec, int32_t val); 89 | __private__OptionI32 __swift_bridge__$Vec_i32$pop(void* const vec); 90 | __private__OptionI32 __swift_bridge__$Vec_i32$get(void* const vec, uintptr_t index); 91 | __private__OptionI32 __swift_bridge__$Vec_i32$get_mut(void* const vec, uintptr_t index); 92 | int32_t const * __swift_bridge__$Vec_i32$as_ptr(void* const vec); 93 | 94 | void* __swift_bridge__$Vec_i64$new(); 95 | void __swift_bridge__$Vec_i64$_free(void* const vec); 96 | uintptr_t __swift_bridge__$Vec_i64$len(void* const vec); 97 | void __swift_bridge__$Vec_i64$push(void* const vec, int64_t val); 98 | __private__OptionI64 __swift_bridge__$Vec_i64$pop(void* const vec); 99 | __private__OptionI64 __swift_bridge__$Vec_i64$get(void* const vec, uintptr_t index); 100 | __private__OptionI64 __swift_bridge__$Vec_i64$get_mut(void* const vec, uintptr_t index); 101 | int64_t const * __swift_bridge__$Vec_i64$as_ptr(void* const vec); 102 | 103 | void* __swift_bridge__$Vec_isize$new(); 104 | void __swift_bridge__$Vec_isize$_free(void* const vec); 105 | uintptr_t __swift_bridge__$Vec_isize$len(void* const vec); 106 | void __swift_bridge__$Vec_isize$push(void* const vec, intptr_t val); 107 | __private__OptionIsize __swift_bridge__$Vec_isize$pop(void* const vec); 108 | __private__OptionIsize __swift_bridge__$Vec_isize$get(void* const vec, uintptr_t index); 109 | __private__OptionIsize __swift_bridge__$Vec_isize$get_mut(void* const vec, uintptr_t index); 110 | intptr_t const * __swift_bridge__$Vec_isize$as_ptr(void* const vec); 111 | 112 | void* __swift_bridge__$Vec_bool$new(); 113 | void __swift_bridge__$Vec_bool$_free(void* const vec); 114 | uintptr_t __swift_bridge__$Vec_bool$len(void* const vec); 115 | void __swift_bridge__$Vec_bool$push(void* const vec, bool val); 116 | __private__OptionBool __swift_bridge__$Vec_bool$pop(void* const vec); 117 | __private__OptionBool __swift_bridge__$Vec_bool$get(void* const vec, uintptr_t index); 118 | __private__OptionBool __swift_bridge__$Vec_bool$get_mut(void* const vec, uintptr_t index); 119 | bool const * __swift_bridge__$Vec_bool$as_ptr(void* const vec); 120 | 121 | void* __swift_bridge__$Vec_f32$new(); 122 | void __swift_bridge__$Vec_f32$_free(void* const vec); 123 | uintptr_t __swift_bridge__$Vec_f32$len(void* const vec); 124 | void __swift_bridge__$Vec_f32$push(void* const vec, float val); 125 | __private__OptionF32 __swift_bridge__$Vec_f32$pop(void* const vec); 126 | __private__OptionF32 __swift_bridge__$Vec_f32$get(void* const vec, uintptr_t index); 127 | __private__OptionF32 __swift_bridge__$Vec_f32$get_mut(void* const vec, uintptr_t index); 128 | float const * __swift_bridge__$Vec_f32$as_ptr(void* const vec); 129 | 130 | void* __swift_bridge__$Vec_f64$new(); 131 | void __swift_bridge__$Vec_f64$_free(void* const vec); 132 | uintptr_t __swift_bridge__$Vec_f64$len(void* const vec); 133 | void __swift_bridge__$Vec_f64$push(void* const vec, double val); 134 | __private__OptionF64 __swift_bridge__$Vec_f64$pop(void* const vec); 135 | __private__OptionF64 __swift_bridge__$Vec_f64$get(void* const vec, uintptr_t index); 136 | __private__OptionF64 __swift_bridge__$Vec_f64$get_mut(void* const vec, uintptr_t index); 137 | double const * __swift_bridge__$Vec_f64$as_ptr(void* const vec); 138 | 139 | #include 140 | typedef struct RustString RustString; 141 | void __swift_bridge__$RustString$_free(void* self); 142 | 143 | void* __swift_bridge__$Vec_RustString$new(void); 144 | void __swift_bridge__$Vec_RustString$drop(void* vec_ptr); 145 | void __swift_bridge__$Vec_RustString$push(void* vec_ptr, void* item_ptr); 146 | void* __swift_bridge__$Vec_RustString$pop(void* vec_ptr); 147 | void* __swift_bridge__$Vec_RustString$get(void* vec_ptr, uintptr_t index); 148 | void* __swift_bridge__$Vec_RustString$get_mut(void* vec_ptr, uintptr_t index); 149 | uintptr_t __swift_bridge__$Vec_RustString$len(void* vec_ptr); 150 | void* __swift_bridge__$Vec_RustString$as_ptr(void* vec_ptr); 151 | 152 | void* __swift_bridge__$RustString$new(void); 153 | void* __swift_bridge__$RustString$new_with_str(struct RustStr str); 154 | uintptr_t __swift_bridge__$RustString$len(void* self); 155 | struct RustStr __swift_bridge__$RustString$as_str(void* self); 156 | struct RustStr __swift_bridge__$RustString$trim(void* self); 157 | bool __swift_bridge__$RustStr$partial_eq(struct RustStr lhs, struct RustStr rhs); 158 | 159 | 160 | void __swift_bridge__$call_boxed_fn_once_no_args_no_return(void* boxed_fnonce); 161 | void __swift_bridge__$free_boxed_fn_once_no_args_no_return(void* boxed_fnonce); 162 | 163 | 164 | struct __private__ResultPtrAndPtr { bool is_ok; void* ok_or_err; }; 165 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64_x86_64-simulator/Headers/bevy_ios_iap.h: -------------------------------------------------------------------------------- 1 | // File automatically generated by swift-bridge. 2 | #include 3 | #include 4 | typedef struct IosIapTransactionFinishResponse IosIapTransactionFinishResponse; 5 | void __swift_bridge__$IosIapTransactionFinishResponse$_free(void* self); 6 | 7 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$new(void); 8 | void __swift_bridge__$Vec_IosIapTransactionFinishResponse$drop(void* vec_ptr); 9 | void __swift_bridge__$Vec_IosIapTransactionFinishResponse$push(void* vec_ptr, void* item_ptr); 10 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$pop(void* vec_ptr); 11 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$get(void* vec_ptr, uintptr_t index); 12 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$get_mut(void* vec_ptr, uintptr_t index); 13 | uintptr_t __swift_bridge__$Vec_IosIapTransactionFinishResponse$len(void* vec_ptr); 14 | void* __swift_bridge__$Vec_IosIapTransactionFinishResponse$as_ptr(void* vec_ptr); 15 | 16 | typedef struct IosIapTransactionResponse IosIapTransactionResponse; 17 | void __swift_bridge__$IosIapTransactionResponse$_free(void* self); 18 | 19 | void* __swift_bridge__$Vec_IosIapTransactionResponse$new(void); 20 | void __swift_bridge__$Vec_IosIapTransactionResponse$drop(void* vec_ptr); 21 | void __swift_bridge__$Vec_IosIapTransactionResponse$push(void* vec_ptr, void* item_ptr); 22 | void* __swift_bridge__$Vec_IosIapTransactionResponse$pop(void* vec_ptr); 23 | void* __swift_bridge__$Vec_IosIapTransactionResponse$get(void* vec_ptr, uintptr_t index); 24 | void* __swift_bridge__$Vec_IosIapTransactionResponse$get_mut(void* vec_ptr, uintptr_t index); 25 | uintptr_t __swift_bridge__$Vec_IosIapTransactionResponse$len(void* vec_ptr); 26 | void* __swift_bridge__$Vec_IosIapTransactionResponse$as_ptr(void* vec_ptr); 27 | 28 | typedef struct IosIapProductsResponse IosIapProductsResponse; 29 | void __swift_bridge__$IosIapProductsResponse$_free(void* self); 30 | 31 | void* __swift_bridge__$Vec_IosIapProductsResponse$new(void); 32 | void __swift_bridge__$Vec_IosIapProductsResponse$drop(void* vec_ptr); 33 | void __swift_bridge__$Vec_IosIapProductsResponse$push(void* vec_ptr, void* item_ptr); 34 | void* __swift_bridge__$Vec_IosIapProductsResponse$pop(void* vec_ptr); 35 | void* __swift_bridge__$Vec_IosIapProductsResponse$get(void* vec_ptr, uintptr_t index); 36 | void* __swift_bridge__$Vec_IosIapProductsResponse$get_mut(void* vec_ptr, uintptr_t index); 37 | uintptr_t __swift_bridge__$Vec_IosIapProductsResponse$len(void* vec_ptr); 38 | void* __swift_bridge__$Vec_IosIapProductsResponse$as_ptr(void* vec_ptr); 39 | 40 | typedef struct IosIapRevocationReason IosIapRevocationReason; 41 | void __swift_bridge__$IosIapRevocationReason$_free(void* self); 42 | 43 | void* __swift_bridge__$Vec_IosIapRevocationReason$new(void); 44 | void __swift_bridge__$Vec_IosIapRevocationReason$drop(void* vec_ptr); 45 | void __swift_bridge__$Vec_IosIapRevocationReason$push(void* vec_ptr, void* item_ptr); 46 | void* __swift_bridge__$Vec_IosIapRevocationReason$pop(void* vec_ptr); 47 | void* __swift_bridge__$Vec_IosIapRevocationReason$get(void* vec_ptr, uintptr_t index); 48 | void* __swift_bridge__$Vec_IosIapRevocationReason$get_mut(void* vec_ptr, uintptr_t index); 49 | uintptr_t __swift_bridge__$Vec_IosIapRevocationReason$len(void* vec_ptr); 50 | void* __swift_bridge__$Vec_IosIapRevocationReason$as_ptr(void* vec_ptr); 51 | 52 | typedef struct IosIapCurrency IosIapCurrency; 53 | void __swift_bridge__$IosIapCurrency$_free(void* self); 54 | 55 | void* __swift_bridge__$Vec_IosIapCurrency$new(void); 56 | void __swift_bridge__$Vec_IosIapCurrency$drop(void* vec_ptr); 57 | void __swift_bridge__$Vec_IosIapCurrency$push(void* vec_ptr, void* item_ptr); 58 | void* __swift_bridge__$Vec_IosIapCurrency$pop(void* vec_ptr); 59 | void* __swift_bridge__$Vec_IosIapCurrency$get(void* vec_ptr, uintptr_t index); 60 | void* __swift_bridge__$Vec_IosIapCurrency$get_mut(void* vec_ptr, uintptr_t index); 61 | uintptr_t __swift_bridge__$Vec_IosIapCurrency$len(void* vec_ptr); 62 | void* __swift_bridge__$Vec_IosIapCurrency$as_ptr(void* vec_ptr); 63 | 64 | typedef struct IosIapSubscriptionRenewalState IosIapSubscriptionRenewalState; 65 | void __swift_bridge__$IosIapSubscriptionRenewalState$_free(void* self); 66 | 67 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$new(void); 68 | void __swift_bridge__$Vec_IosIapSubscriptionRenewalState$drop(void* vec_ptr); 69 | void __swift_bridge__$Vec_IosIapSubscriptionRenewalState$push(void* vec_ptr, void* item_ptr); 70 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$pop(void* vec_ptr); 71 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$get(void* vec_ptr, uintptr_t index); 72 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$get_mut(void* vec_ptr, uintptr_t index); 73 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionRenewalState$len(void* vec_ptr); 74 | void* __swift_bridge__$Vec_IosIapSubscriptionRenewalState$as_ptr(void* vec_ptr); 75 | 76 | typedef struct IosIapSubscriptionStatus IosIapSubscriptionStatus; 77 | void __swift_bridge__$IosIapSubscriptionStatus$_free(void* self); 78 | 79 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$new(void); 80 | void __swift_bridge__$Vec_IosIapSubscriptionStatus$drop(void* vec_ptr); 81 | void __swift_bridge__$Vec_IosIapSubscriptionStatus$push(void* vec_ptr, void* item_ptr); 82 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$pop(void* vec_ptr); 83 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$get(void* vec_ptr, uintptr_t index); 84 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$get_mut(void* vec_ptr, uintptr_t index); 85 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionStatus$len(void* vec_ptr); 86 | void* __swift_bridge__$Vec_IosIapSubscriptionStatus$as_ptr(void* vec_ptr); 87 | 88 | typedef struct IosIapSubscriptionPeriodUnit IosIapSubscriptionPeriodUnit; 89 | void __swift_bridge__$IosIapSubscriptionPeriodUnit$_free(void* self); 90 | 91 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$new(void); 92 | void __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$drop(void* vec_ptr); 93 | void __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$push(void* vec_ptr, void* item_ptr); 94 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$pop(void* vec_ptr); 95 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$get(void* vec_ptr, uintptr_t index); 96 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$get_mut(void* vec_ptr, uintptr_t index); 97 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$len(void* vec_ptr); 98 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriodUnit$as_ptr(void* vec_ptr); 99 | 100 | typedef struct IosIapSubscriptionPeriod IosIapSubscriptionPeriod; 101 | void __swift_bridge__$IosIapSubscriptionPeriod$_free(void* self); 102 | 103 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$new(void); 104 | void __swift_bridge__$Vec_IosIapSubscriptionPeriod$drop(void* vec_ptr); 105 | void __swift_bridge__$Vec_IosIapSubscriptionPeriod$push(void* vec_ptr, void* item_ptr); 106 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$pop(void* vec_ptr); 107 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$get(void* vec_ptr, uintptr_t index); 108 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$get_mut(void* vec_ptr, uintptr_t index); 109 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionPeriod$len(void* vec_ptr); 110 | void* __swift_bridge__$Vec_IosIapSubscriptionPeriod$as_ptr(void* vec_ptr); 111 | 112 | typedef struct IosIapSubscriptionInfo IosIapSubscriptionInfo; 113 | void __swift_bridge__$IosIapSubscriptionInfo$_free(void* self); 114 | 115 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$new(void); 116 | void __swift_bridge__$Vec_IosIapSubscriptionInfo$drop(void* vec_ptr); 117 | void __swift_bridge__$Vec_IosIapSubscriptionInfo$push(void* vec_ptr, void* item_ptr); 118 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$pop(void* vec_ptr); 119 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$get(void* vec_ptr, uintptr_t index); 120 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$get_mut(void* vec_ptr, uintptr_t index); 121 | uintptr_t __swift_bridge__$Vec_IosIapSubscriptionInfo$len(void* vec_ptr); 122 | void* __swift_bridge__$Vec_IosIapSubscriptionInfo$as_ptr(void* vec_ptr); 123 | 124 | typedef struct IosIapStorefront IosIapStorefront; 125 | void __swift_bridge__$IosIapStorefront$_free(void* self); 126 | 127 | void* __swift_bridge__$Vec_IosIapStorefront$new(void); 128 | void __swift_bridge__$Vec_IosIapStorefront$drop(void* vec_ptr); 129 | void __swift_bridge__$Vec_IosIapStorefront$push(void* vec_ptr, void* item_ptr); 130 | void* __swift_bridge__$Vec_IosIapStorefront$pop(void* vec_ptr); 131 | void* __swift_bridge__$Vec_IosIapStorefront$get(void* vec_ptr, uintptr_t index); 132 | void* __swift_bridge__$Vec_IosIapStorefront$get_mut(void* vec_ptr, uintptr_t index); 133 | uintptr_t __swift_bridge__$Vec_IosIapStorefront$len(void* vec_ptr); 134 | void* __swift_bridge__$Vec_IosIapStorefront$as_ptr(void* vec_ptr); 135 | 136 | typedef struct IosIapEnvironment IosIapEnvironment; 137 | void __swift_bridge__$IosIapEnvironment$_free(void* self); 138 | 139 | void* __swift_bridge__$Vec_IosIapEnvironment$new(void); 140 | void __swift_bridge__$Vec_IosIapEnvironment$drop(void* vec_ptr); 141 | void __swift_bridge__$Vec_IosIapEnvironment$push(void* vec_ptr, void* item_ptr); 142 | void* __swift_bridge__$Vec_IosIapEnvironment$pop(void* vec_ptr); 143 | void* __swift_bridge__$Vec_IosIapEnvironment$get(void* vec_ptr, uintptr_t index); 144 | void* __swift_bridge__$Vec_IosIapEnvironment$get_mut(void* vec_ptr, uintptr_t index); 145 | uintptr_t __swift_bridge__$Vec_IosIapEnvironment$len(void* vec_ptr); 146 | void* __swift_bridge__$Vec_IosIapEnvironment$as_ptr(void* vec_ptr); 147 | 148 | typedef struct IosIapTransactionReason IosIapTransactionReason; 149 | void __swift_bridge__$IosIapTransactionReason$_free(void* self); 150 | 151 | void* __swift_bridge__$Vec_IosIapTransactionReason$new(void); 152 | void __swift_bridge__$Vec_IosIapTransactionReason$drop(void* vec_ptr); 153 | void __swift_bridge__$Vec_IosIapTransactionReason$push(void* vec_ptr, void* item_ptr); 154 | void* __swift_bridge__$Vec_IosIapTransactionReason$pop(void* vec_ptr); 155 | void* __swift_bridge__$Vec_IosIapTransactionReason$get(void* vec_ptr, uintptr_t index); 156 | void* __swift_bridge__$Vec_IosIapTransactionReason$get_mut(void* vec_ptr, uintptr_t index); 157 | uintptr_t __swift_bridge__$Vec_IosIapTransactionReason$len(void* vec_ptr); 158 | void* __swift_bridge__$Vec_IosIapTransactionReason$as_ptr(void* vec_ptr); 159 | 160 | typedef struct IosIapTransaction IosIapTransaction; 161 | void __swift_bridge__$IosIapTransaction$_free(void* self); 162 | 163 | void* __swift_bridge__$Vec_IosIapTransaction$new(void); 164 | void __swift_bridge__$Vec_IosIapTransaction$drop(void* vec_ptr); 165 | void __swift_bridge__$Vec_IosIapTransaction$push(void* vec_ptr, void* item_ptr); 166 | void* __swift_bridge__$Vec_IosIapTransaction$pop(void* vec_ptr); 167 | void* __swift_bridge__$Vec_IosIapTransaction$get(void* vec_ptr, uintptr_t index); 168 | void* __swift_bridge__$Vec_IosIapTransaction$get_mut(void* vec_ptr, uintptr_t index); 169 | uintptr_t __swift_bridge__$Vec_IosIapTransaction$len(void* vec_ptr); 170 | void* __swift_bridge__$Vec_IosIapTransaction$as_ptr(void* vec_ptr); 171 | 172 | typedef struct IosIapStoreKitError IosIapStoreKitError; 173 | void __swift_bridge__$IosIapStoreKitError$_free(void* self); 174 | 175 | void* __swift_bridge__$Vec_IosIapStoreKitError$new(void); 176 | void __swift_bridge__$Vec_IosIapStoreKitError$drop(void* vec_ptr); 177 | void __swift_bridge__$Vec_IosIapStoreKitError$push(void* vec_ptr, void* item_ptr); 178 | void* __swift_bridge__$Vec_IosIapStoreKitError$pop(void* vec_ptr); 179 | void* __swift_bridge__$Vec_IosIapStoreKitError$get(void* vec_ptr, uintptr_t index); 180 | void* __swift_bridge__$Vec_IosIapStoreKitError$get_mut(void* vec_ptr, uintptr_t index); 181 | uintptr_t __swift_bridge__$Vec_IosIapStoreKitError$len(void* vec_ptr); 182 | void* __swift_bridge__$Vec_IosIapStoreKitError$as_ptr(void* vec_ptr); 183 | 184 | typedef struct IosIapPurchaseError IosIapPurchaseError; 185 | void __swift_bridge__$IosIapPurchaseError$_free(void* self); 186 | 187 | void* __swift_bridge__$Vec_IosIapPurchaseError$new(void); 188 | void __swift_bridge__$Vec_IosIapPurchaseError$drop(void* vec_ptr); 189 | void __swift_bridge__$Vec_IosIapPurchaseError$push(void* vec_ptr, void* item_ptr); 190 | void* __swift_bridge__$Vec_IosIapPurchaseError$pop(void* vec_ptr); 191 | void* __swift_bridge__$Vec_IosIapPurchaseError$get(void* vec_ptr, uintptr_t index); 192 | void* __swift_bridge__$Vec_IosIapPurchaseError$get_mut(void* vec_ptr, uintptr_t index); 193 | uintptr_t __swift_bridge__$Vec_IosIapPurchaseError$len(void* vec_ptr); 194 | void* __swift_bridge__$Vec_IosIapPurchaseError$as_ptr(void* vec_ptr); 195 | 196 | typedef struct IosIapPurchaseResponse IosIapPurchaseResponse; 197 | void __swift_bridge__$IosIapPurchaseResponse$_free(void* self); 198 | 199 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$new(void); 200 | void __swift_bridge__$Vec_IosIapPurchaseResponse$drop(void* vec_ptr); 201 | void __swift_bridge__$Vec_IosIapPurchaseResponse$push(void* vec_ptr, void* item_ptr); 202 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$pop(void* vec_ptr); 203 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$get(void* vec_ptr, uintptr_t index); 204 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$get_mut(void* vec_ptr, uintptr_t index); 205 | uintptr_t __swift_bridge__$Vec_IosIapPurchaseResponse$len(void* vec_ptr); 206 | void* __swift_bridge__$Vec_IosIapPurchaseResponse$as_ptr(void* vec_ptr); 207 | 208 | typedef struct IosIapProductType IosIapProductType; 209 | void __swift_bridge__$IosIapProductType$_free(void* self); 210 | 211 | void* __swift_bridge__$Vec_IosIapProductType$new(void); 212 | void __swift_bridge__$Vec_IosIapProductType$drop(void* vec_ptr); 213 | void __swift_bridge__$Vec_IosIapProductType$push(void* vec_ptr, void* item_ptr); 214 | void* __swift_bridge__$Vec_IosIapProductType$pop(void* vec_ptr); 215 | void* __swift_bridge__$Vec_IosIapProductType$get(void* vec_ptr, uintptr_t index); 216 | void* __swift_bridge__$Vec_IosIapProductType$get_mut(void* vec_ptr, uintptr_t index); 217 | uintptr_t __swift_bridge__$Vec_IosIapProductType$len(void* vec_ptr); 218 | void* __swift_bridge__$Vec_IosIapProductType$as_ptr(void* vec_ptr); 219 | 220 | typedef struct IosIapProduct IosIapProduct; 221 | void __swift_bridge__$IosIapProduct$_free(void* self); 222 | 223 | void* __swift_bridge__$Vec_IosIapProduct$new(void); 224 | void __swift_bridge__$Vec_IosIapProduct$drop(void* vec_ptr); 225 | void __swift_bridge__$Vec_IosIapProduct$push(void* vec_ptr, void* item_ptr); 226 | void* __swift_bridge__$Vec_IosIapProduct$pop(void* vec_ptr); 227 | void* __swift_bridge__$Vec_IosIapProduct$get(void* vec_ptr, uintptr_t index); 228 | void* __swift_bridge__$Vec_IosIapProduct$get_mut(void* vec_ptr, uintptr_t index); 229 | uintptr_t __swift_bridge__$Vec_IosIapProduct$len(void* vec_ptr); 230 | void* __swift_bridge__$Vec_IosIapProduct$as_ptr(void* vec_ptr); 231 | 232 | void* __swift_bridge__$IosIapProduct$new(void* id, void* display_price, void* display_name, void* description, double price, void* product_type); 233 | void __swift_bridge__$IosIapProduct$subscription(void* t, void* info); 234 | void* __swift_bridge__$IosIapProductType$new_consumable(bool non); 235 | void* __swift_bridge__$IosIapProductType$new_non_renewable(void); 236 | void* __swift_bridge__$IosIapProductType$new_auto_renewable(void); 237 | void* __swift_bridge__$IosIapPurchaseResponse$success(void* t); 238 | void* __swift_bridge__$IosIapPurchaseResponse$canceled(void* id); 239 | void* __swift_bridge__$IosIapPurchaseResponse$pending(void* id); 240 | void* __swift_bridge__$IosIapPurchaseResponse$unknown(void* id); 241 | void* __swift_bridge__$IosIapPurchaseResponse$error(void* e); 242 | void* __swift_bridge__$IosIapPurchaseResponse$purchase_error(void* error, void* localized_description); 243 | void* __swift_bridge__$IosIapPurchaseResponse$storekit_error(void* error, void* localized_description); 244 | void* __swift_bridge__$IosIapPurchaseError$invalid_quantity(void); 245 | void* __swift_bridge__$IosIapPurchaseError$product_unavailable(void); 246 | void* __swift_bridge__$IosIapPurchaseError$purchase_not_allowed(void); 247 | void* __swift_bridge__$IosIapPurchaseError$ineligible_for_offer(void); 248 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_identifier(void); 249 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_price(void); 250 | void* __swift_bridge__$IosIapPurchaseError$invalid_offer_signature(void); 251 | void* __swift_bridge__$IosIapPurchaseError$missing_offer_parameters(void); 252 | void* __swift_bridge__$IosIapStoreKitError$unknown(void); 253 | void* __swift_bridge__$IosIapStoreKitError$user_cancelled(void); 254 | void* __swift_bridge__$IosIapStoreKitError$network_error(void* e); 255 | void* __swift_bridge__$IosIapStoreKitError$system_error(void* e); 256 | void* __swift_bridge__$IosIapStoreKitError$not_available_in_storefront(void); 257 | void* __swift_bridge__$IosIapStoreKitError$not_entitled(void); 258 | void* __swift_bridge__$IosIapEnvironment$sandbox(void); 259 | void* __swift_bridge__$IosIapEnvironment$production(void); 260 | void* __swift_bridge__$IosIapEnvironment$xcode(void); 261 | void* __swift_bridge__$IosIapStorefront$storefront(void* id, void* country_code); 262 | void* __swift_bridge__$IosIapTransaction$new_transaction(uint64_t id, void* product_id, void* app_bundle_id, uint64_t purchase_date, uint64_t original_purchase_date, int32_t purchased_quantity, void* storefront_country_code, uint64_t signed_date, bool is_upgraded, uint64_t original_id, void* json_representation, void* product_type, void* environment); 263 | void __swift_bridge__$IosIapTransaction$add_storefront(void* t, void* store); 264 | void __swift_bridge__$IosIapTransaction$add_reason(void* t, void* reason); 265 | void __swift_bridge__$IosIapTransaction$add_revocation(void* t, uint64_t date); 266 | void __swift_bridge__$IosIapTransaction$add_expiration(void* t, uint64_t date); 267 | void __swift_bridge__$IosIapTransaction$add_currency(void* t, void* currency); 268 | void __swift_bridge__$IosIapTransaction$revocation_reason(void* t, void* reason); 269 | void __swift_bridge__$IosIapTransaction$web_order_line_item_id(void* t, void* id); 270 | void __swift_bridge__$IosIapTransaction$subscription_group_id(void* t, void* id); 271 | void __swift_bridge__$IosIapTransaction$app_account_token(void* t, void* uuid); 272 | void* __swift_bridge__$IosIapTransactionReason$renewal(void); 273 | void* __swift_bridge__$IosIapTransactionReason$purchase(void); 274 | void* __swift_bridge__$IosIapTransactionFinishResponse$finished(void* t); 275 | void* __swift_bridge__$IosIapTransactionFinishResponse$error(void* e); 276 | void* __swift_bridge__$IosIapTransactionFinishResponse$unknown(uint64_t id); 277 | void* __swift_bridge__$IosIapSubscriptionInfo$new(void* group_id, void* period, bool is_eligible_for_intro_offer, void* state); 278 | void* __swift_bridge__$IosIapSubscriptionPeriod$new(void* unit, int32_t value); 279 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$day(void); 280 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$week(void); 281 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$month(void); 282 | void* __swift_bridge__$IosIapSubscriptionPeriodUnit$year(void); 283 | void* __swift_bridge__$IosIapSubscriptionRenewalState$subscribed(void); 284 | void* __swift_bridge__$IosIapSubscriptionRenewalState$expired(void); 285 | void* __swift_bridge__$IosIapSubscriptionRenewalState$in_billing_retry_period(void); 286 | void* __swift_bridge__$IosIapSubscriptionRenewalState$in_grace_period(void); 287 | void* __swift_bridge__$IosIapSubscriptionRenewalState$revoked(void); 288 | void* __swift_bridge__$IosIapSubscriptionStatus$new(void* state, void* transaction); 289 | void* __swift_bridge__$IosIapCurrency$new(void* identifier, bool is_iso_currency); 290 | void* __swift_bridge__$IosIapRevocationReason$developer_issue(void); 291 | void* __swift_bridge__$IosIapRevocationReason$other(void); 292 | void* __swift_bridge__$IosIapProductsResponse$done(void* items); 293 | void* __swift_bridge__$IosIapProductsResponse$error(void* error); 294 | void* __swift_bridge__$IosIapTransactionResponse$done(void* items); 295 | void* __swift_bridge__$IosIapTransactionResponse$error(void* error); 296 | void __swift_bridge__$products_received(int64_t request, void* response); 297 | void __swift_bridge__$all_transactions(int64_t request, void* response); 298 | void __swift_bridge__$current_entitlements(int64_t request, void* response); 299 | void __swift_bridge__$purchase_processed(int64_t request, void* result); 300 | void __swift_bridge__$transaction_update(void* t); 301 | void __swift_bridge__$transaction_finished(int64_t request, void* t); 302 | 303 | 304 | -------------------------------------------------------------------------------- /RustXcframework.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap: -------------------------------------------------------------------------------- 1 | module RustXcframework { 2 | header "SwiftBridgeCore.h" 3 | header "bevy_ios_iap.h" 4 | export * 5 | } 6 | -------------------------------------------------------------------------------- /SWIFT_BRIDGE.md: -------------------------------------------------------------------------------- 1 | # Swift-Bridge wishlist 2 | 3 | * how to return data from swift that rust can read? (`fn foo() -> Bar`) 4 | * make @_cdecl funcs `public` (https://github.com/chinedufn/swift-bridge/issues/166) 5 | * allow changing stuff to allow multiple libs using this approach (`SwiftBridgeCore.swift`, Name of `RustXcframework`, `Headers` subfolder etc.) see https://github.com/jessegrosjean/swift-cargo-problem 6 | * support derives(Clone,Debug) on shared enums 7 | * support calling async swift from rust 8 | * allow shared structs in `Vec`'s (Vectorizable) 9 | * properly add missing `import RustXcframework` when using Swift Package approach 10 | * add `swift_bridge_build.update_package` to only copy the files over instead of generating everything (and do the above) 11 | * how to get swift `Data` out? cannot figure out how to convert that into RustVec or anything compatible -------------------------------------------------------------------------------- /Sources/bevy_ios_iap/BevyIosIAP.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Stephan on 26.04.24. 6 | // 7 | 8 | import StoreKit 9 | import RustXcframework 10 | 11 | public func ios_iap_products(request:Int64, products:RustVec) 12 | { 13 | Task { 14 | do { 15 | var productIds:[String] = [] 16 | for p in products { 17 | productIds.append(p.as_str().toString()) 18 | } 19 | 20 | let products = try await Product.products(for: productIds) 21 | 22 | let rust_products = RustVec() 23 | 24 | for product in products { 25 | rust_products.push(value: try await convert_product(product)) 26 | } 27 | 28 | products_received(request, IosIapProductsResponse.done(rust_products)) 29 | } catch { 30 | products_received(request, IosIapProductsResponse.error(error.localizedDescription)) 31 | } 32 | } 33 | } 34 | 35 | public func ios_iap_purchase(request:Int64, id: RustString) { 36 | Task { 37 | do { 38 | let productIds = [id.toString()] 39 | let products = try await Product.products(for: productIds) 40 | 41 | if products.isEmpty { 42 | return purchase_processed(request, IosIapPurchaseResponse.unknown(id.toString())) 43 | } 44 | 45 | let purchase = try await products.first!.purchase() 46 | 47 | let result = switch purchase { 48 | case .success(let transactionResult): 49 | IosIapPurchaseResponse.success(try convert_transaction(transactionResult.unsafePayloadValue)) 50 | case .userCancelled: 51 | IosIapPurchaseResponse.canceled(id.toString()) 52 | case .pending: 53 | IosIapPurchaseResponse.pending(id.toString()) 54 | } 55 | 56 | purchase_processed(request, result) 57 | } catch let error as Product.PurchaseError { 58 | purchase_processed(request, IosIapPurchaseResponse.purchase_error(convert_purchase_error(error),error.localizedDescription)) 59 | } catch let error as StoreKitError { 60 | purchase_processed(request, IosIapPurchaseResponse.storekit_error(convert_storekit_error(error),error.localizedDescription)) 61 | } catch { 62 | purchase_processed(request, IosIapPurchaseResponse.error(error.localizedDescription)) 63 | } 64 | } 65 | } 66 | 67 | public func ios_iap_init() 68 | { 69 | TransactionObserver.init() 70 | } 71 | 72 | public func ios_iap_transaction_finish(request: Int64, transaction_id: UInt64) { 73 | Task { 74 | do { 75 | for await t in Transaction.unfinished { 76 | // ignore un-signed/verified transactions 77 | guard case .verified(let transaction) = t else { 78 | continue 79 | } 80 | 81 | if transaction.id == transaction_id { 82 | await transaction.finish() 83 | transaction_finished(request, IosIapTransactionFinishResponse.finished(try convert_transaction(transaction))) 84 | return; 85 | } 86 | } 87 | 88 | transaction_finished(request, IosIapTransactionFinishResponse.unknown(transaction_id)) 89 | } catch { 90 | transaction_finished(request, IosIapTransactionFinishResponse.error(error.localizedDescription)) 91 | } 92 | } 93 | } 94 | 95 | public func ios_iap_transactions_all(request: Int64) { 96 | Task { 97 | do { 98 | var transactions = RustVec.init() 99 | 100 | for await t in Transaction.all { 101 | //only return signed/verified transactions 102 | guard case .verified(let transaction) = t else { 103 | continue 104 | } 105 | 106 | transactions.push(value:try convert_transaction(transaction)) 107 | } 108 | 109 | all_transactions(request, IosIapTransactionResponse.done(transactions)) 110 | } catch { 111 | all_transactions(request, IosIapTransactionResponse.error(error.localizedDescription)) 112 | } 113 | } 114 | } 115 | 116 | public func ios_iap_transactions_current_entitlements(request: Int64) { 117 | Task { 118 | do{ 119 | var transactions = RustVec.init() 120 | 121 | for await t in Transaction.currentEntitlements { 122 | //only return signed/verified transactions 123 | guard case .verified(let transaction) = t else { 124 | continue 125 | } 126 | 127 | transactions.push(value:try convert_transaction(transaction)) 128 | } 129 | 130 | current_entitlements(request,IosIapTransactionResponse.done(transactions)) 131 | } catch { 132 | current_entitlements(request,IosIapTransactionResponse.error(error.localizedDescription)) 133 | } 134 | } 135 | } 136 | 137 | func convert_product(_ product: (Product)) async throws -> IosIapProduct { 138 | let type = if product.type == Product.ProductType.consumable { 139 | IosIapProductType.new_consumable(false) 140 | } else if product.type == Product.ProductType.nonConsumable { 141 | IosIapProductType.new_consumable(true) 142 | } else if product.type == Product.ProductType.nonRenewable { 143 | IosIapProductType.new_non_renewable() 144 | } else { 145 | IosIapProductType.new_auto_renewable() 146 | } 147 | 148 | var rust_product = IosIapProduct.new(product.id, product.displayPrice, product.displayName, product.description, Double(truncating: product.price as NSNumber), type) 149 | 150 | if let sub = product.subscription { 151 | let unit = switch sub.subscriptionPeriod.unit { 152 | case .day: 153 | IosIapSubscriptionPeriodUnit.day() 154 | case .week: 155 | IosIapSubscriptionPeriodUnit.week() 156 | case .month: 157 | IosIapSubscriptionPeriodUnit.month() 158 | case .year: 159 | IosIapSubscriptionPeriodUnit.year() 160 | } 161 | 162 | let period = IosIapSubscriptionPeriod.new(unit, Int32(sub.subscriptionPeriod.value)) 163 | 164 | let status = try await sub.status 165 | 166 | let rust_status = RustVec() 167 | for s in status { 168 | let renewalState = switch s.state { 169 | case .subscribed: 170 | IosIapSubscriptionRenewalState.subscribed() 171 | case .expired: 172 | IosIapSubscriptionRenewalState.expired() 173 | case .inGracePeriod: 174 | IosIapSubscriptionRenewalState.in_grace_period() 175 | case .inBillingRetryPeriod: 176 | IosIapSubscriptionRenewalState.in_billing_retry_period() 177 | case .revoked: 178 | IosIapSubscriptionRenewalState.revoked() 179 | default: 180 | throw NSError(domain: "invalid renewal state", code: 1, userInfo: nil) 181 | } 182 | guard case .verified(let transaction) = s.transaction else { 183 | continue 184 | } 185 | rust_status.push(value: IosIapSubscriptionStatus.new(renewalState,try convert_transaction(transaction))) 186 | } 187 | 188 | let subscription = IosIapSubscriptionInfo.new(sub.subscriptionGroupID, period, try await sub.isEligibleForIntroOffer, rust_status) 189 | 190 | IosIapProduct.subscription(rust_product, subscription) 191 | } 192 | 193 | return rust_product 194 | } 195 | 196 | public func convert_purchase_error(_ error: (Product.PurchaseError)) -> IosIapPurchaseError { 197 | return switch error { 198 | case .invalidQuantity: IosIapPurchaseError.invalid_quantity() 199 | case .productUnavailable: IosIapPurchaseError.product_unavailable() 200 | case .purchaseNotAllowed: IosIapPurchaseError.purchase_not_allowed() 201 | case .ineligibleForOffer: IosIapPurchaseError.ineligible_for_offer() 202 | case .invalidOfferIdentifier: IosIapPurchaseError.invalid_offer_identifier() 203 | case .invalidOfferPrice: IosIapPurchaseError.invalid_offer_price() 204 | case .invalidOfferSignature: IosIapPurchaseError.invalid_offer_signature() 205 | case .missingOfferParameters: IosIapPurchaseError.missing_offer_parameters() 206 | } 207 | } 208 | 209 | public func convert_storekit_error(_ error: (StoreKitError)) -> IosIapStoreKitError { 210 | return switch error { 211 | case .unknown: IosIapStoreKitError.unknown() 212 | case .userCancelled: IosIapStoreKitError.user_cancelled() 213 | case .networkError(let e): IosIapStoreKitError.network_error(e.localizedDescription) 214 | case .systemError(let e): IosIapStoreKitError.system_error(e.localizedDescription) 215 | case .notAvailableInStorefront: IosIapStoreKitError.not_available_in_storefront() 216 | case .notEntitled: IosIapStoreKitError.not_entitled() 217 | 218 | @unknown default: 219 | IosIapStoreKitError.unknown() 220 | } 221 | } 222 | 223 | public func convert_transaction(_ transaction: (Transaction)) throws -> IosIapTransaction { 224 | let type = if transaction.productType == Product.ProductType.consumable { 225 | IosIapProductType.new_consumable(false) 226 | } else if transaction.productType == Product.ProductType.nonConsumable { 227 | IosIapProductType.new_consumable(true) 228 | } else if transaction.productType == Product.ProductType.nonRenewable { 229 | IosIapProductType.new_non_renewable() 230 | } else { 231 | IosIapProductType.new_auto_renewable() 232 | } 233 | 234 | let jsonRepresentation = String(decoding: transaction.jsonRepresentation, as: UTF8.self) 235 | 236 | let env = if transaction.environment == AppStore.Environment.xcode { 237 | IosIapEnvironment.xcode() 238 | } else if transaction.environment == AppStore.Environment.sandbox { 239 | IosIapEnvironment.sandbox() 240 | } else { 241 | IosIapEnvironment.production() 242 | } 243 | 244 | var t = IosIapTransaction.new_transaction( 245 | transaction.id, 246 | transaction.productID, 247 | transaction.appBundleID, 248 | UInt64(transaction.purchaseDate.timeIntervalSince1970), 249 | UInt64(transaction.originalPurchaseDate.timeIntervalSince1970), 250 | Int32(transaction.purchasedQuantity), 251 | transaction.storefrontCountryCode, 252 | UInt64(transaction.signedDate.timeIntervalSince1970), 253 | transaction.isUpgraded, 254 | transaction.originalID, 255 | jsonRepresentation, 256 | type, 257 | env) 258 | 259 | if #available(iOS 17.0, *) { 260 | let store = IosIapStorefront.storefront(transaction.storefront.id, transaction.storefront.countryCode) 261 | 262 | IosIapTransaction.add_storefront(t, store) 263 | 264 | let reason = if transaction.reason == Transaction.Reason.purchase { 265 | IosIapTransactionReason.purchase() 266 | } else { 267 | IosIapTransactionReason.renewal() 268 | } 269 | 270 | IosIapTransaction.add_reason(t, reason) 271 | } 272 | 273 | if let appAccountToken = transaction.appAccountToken { 274 | IosIapTransaction.app_account_token(t, appAccountToken.uuidString) 275 | } 276 | 277 | if let currency = transaction.currency { 278 | IosIapTransaction.add_currency(t, IosIapCurrency.new(currency.identifier, currency.isISOCurrency)) 279 | } 280 | 281 | if let revocationDate = transaction.revocationDate { 282 | IosIapTransaction.add_revocation(t, UInt64(revocationDate.timeIntervalSince1970)) 283 | } 284 | 285 | if let revocationReason = transaction.revocationReason { 286 | let revocationReason = switch revocationReason { 287 | case .developerIssue: 288 | IosIapRevocationReason.developer_issue() 289 | case .other: 290 | IosIapRevocationReason.other() 291 | default: 292 | throw NSError(domain: "invalid revocation reason", code: 2, userInfo: nil) 293 | } 294 | 295 | IosIapTransaction.revocation_reason(t, revocationReason) 296 | } 297 | 298 | if let expirationDate = transaction.expirationDate { 299 | IosIapTransaction.add_expiration(t, UInt64(expirationDate.timeIntervalSince1970)) 300 | } 301 | 302 | if let subscriptionGroupID = transaction.subscriptionGroupID { 303 | IosIapTransaction.subscription_group_id(t, subscriptionGroupID) 304 | } 305 | 306 | if let webOrderLineItemID = transaction.webOrderLineItemID { 307 | IosIapTransaction.web_order_line_item_id(t, webOrderLineItemID) 308 | } 309 | 310 | return t 311 | } 312 | -------------------------------------------------------------------------------- /Sources/bevy_ios_iap/Observer.swift: -------------------------------------------------------------------------------- 1 | import StoreKit 2 | 3 | final class TransactionObserver { 4 | 5 | var updates: Task? = nil 6 | 7 | init() { 8 | updates = newTransactionListenerTask() 9 | } 10 | 11 | 12 | deinit { 13 | // Cancel the update handling task when you deinitialize the class. 14 | updates?.cancel() 15 | } 16 | 17 | private func newTransactionListenerTask() -> Task { 18 | Task(priority: .background) { 19 | for await verificationResult in Transaction.updates { 20 | self.handle(updatedTransaction: verificationResult) 21 | } 22 | } 23 | } 24 | 25 | private func handle(updatedTransaction verificationResult: VerificationResult) { 26 | guard case .verified(let transaction) = verificationResult else { 27 | // Ignore unverified transactions. 28 | print("unverified:\n \(verificationResult)") 29 | return 30 | } 31 | 32 | do { 33 | let t = try convert_transaction(transaction) 34 | transaction_update(t) 35 | } catch { 36 | print("error converting transaction: \(error.localizedDescription)") 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/bevy_ios_iap/SwiftBridgeCore.swift: -------------------------------------------------------------------------------- 1 | import RustXcframework 2 | import Foundation 3 | 4 | extension RustString { 5 | public func toString() -> String { 6 | let str = self.as_str() 7 | let string = str.toString() 8 | 9 | return string 10 | } 11 | } 12 | 13 | extension RustStr { 14 | func toBufferPointer() -> UnsafeBufferPointer { 15 | let bytes = UnsafeBufferPointer(start: self.start, count: Int(self.len)) 16 | return bytes 17 | } 18 | 19 | public func toString() -> String { 20 | let bytes = self.toBufferPointer() 21 | return String(bytes: bytes, encoding: .utf8)! 22 | } 23 | } 24 | extension RustStr: Identifiable { 25 | public var id: String { 26 | self.toString() 27 | } 28 | } 29 | extension RustStr: Equatable { 30 | public static func == (lhs: RustStr, rhs: RustStr) -> Bool { 31 | return __swift_bridge__$RustStr$partial_eq(lhs, rhs); 32 | } 33 | } 34 | 35 | public protocol IntoRustString { 36 | func intoRustString() -> RustString; 37 | } 38 | 39 | extension String: IntoRustString { 40 | public func intoRustString() -> RustString { 41 | // TODO: When passing an owned Swift std String to Rust we've being wasteful here in that 42 | // we're creating a RustString (which involves Boxing a Rust std::string::String) 43 | // only to unbox it back into a String once it gets to the Rust side. 44 | // 45 | // A better approach would be to pass a RustStr to the Rust side and then have Rust 46 | // call `.to_string()` on the RustStr. 47 | RustString(self) 48 | } 49 | } 50 | 51 | extension RustString: IntoRustString { 52 | public func intoRustString() -> RustString { 53 | self 54 | } 55 | } 56 | 57 | /// If the String is Some: 58 | /// Safely get a scoped pointer to the String and then call the callback with a RustStr 59 | /// that uses that pointer. 60 | /// 61 | /// If the String is None: 62 | /// Call the callback with a RustStr that has a null pointer. 63 | /// The Rust side will know to treat this as `None`. 64 | func optionalStringIntoRustString(_ string: Optional) -> RustString? { 65 | if let val = string { 66 | return val.intoRustString() 67 | } else { 68 | return nil 69 | } 70 | } 71 | 72 | /// Used to safely get a pointer to a sequence of utf8 bytes, represented as a `RustStr`. 73 | /// 74 | /// For example, the Swift `String` implementation of the `ToRustStr` protocol does the following: 75 | /// 1. Use Swift's `String.utf8.withUnsafeBufferPointer` to get a pointer to the strings underlying 76 | /// utf8 bytes. 77 | /// 2. Construct a `RustStr` that points to these utf8 bytes. This is safe because `withUnsafeBufferPointer` 78 | /// guarantees that the buffer pointer will be valid for the duration of the `withUnsafeBufferPointer` 79 | /// callback. 80 | /// 3. Pass the `RustStr` to the closure that was passed into `RustStr.toRustStr`. 81 | public protocol ToRustStr { 82 | func toRustStr (_ withUnsafeRustStr: (RustStr) -> T) -> T; 83 | } 84 | 85 | extension String: ToRustStr { 86 | /// Safely get a scoped pointer to the String and then call the callback with a RustStr 87 | /// that uses that pointer. 88 | public func toRustStr (_ withUnsafeRustStr: (RustStr) -> T) -> T { 89 | return self.utf8CString.withUnsafeBufferPointer({ bufferPtr in 90 | let rustStr = RustStr( 91 | start: UnsafeMutableRawPointer(mutating: bufferPtr.baseAddress!).assumingMemoryBound(to: UInt8.self), 92 | // Subtract 1 because of the null termination character at the end 93 | len: UInt(bufferPtr.count - 1) 94 | ) 95 | return withUnsafeRustStr(rustStr) 96 | }) 97 | } 98 | } 99 | 100 | extension RustStr: ToRustStr { 101 | public func toRustStr (_ withUnsafeRustStr: (RustStr) -> T) -> T { 102 | return withUnsafeRustStr(self) 103 | } 104 | } 105 | 106 | func optionalRustStrToRustStr(_ str: Optional, _ withUnsafeRustStr: (RustStr) -> T) -> T { 107 | if let val = str { 108 | return val.toRustStr(withUnsafeRustStr) 109 | } else { 110 | return withUnsafeRustStr(RustStr(start: nil, len: 0)) 111 | } 112 | } 113 | public class RustVec { 114 | var ptr: UnsafeMutableRawPointer 115 | var isOwned: Bool = true 116 | 117 | public init(ptr: UnsafeMutableRawPointer) { 118 | self.ptr = ptr 119 | } 120 | 121 | public init() { 122 | ptr = T.vecOfSelfNew() 123 | isOwned = true 124 | } 125 | 126 | public func push (value: T) { 127 | T.vecOfSelfPush(vecPtr: ptr, value: value) 128 | } 129 | 130 | public func pop () -> Optional { 131 | T.vecOfSelfPop(vecPtr: ptr) 132 | } 133 | 134 | public func get(index: UInt) -> Optional { 135 | T.vecOfSelfGet(vecPtr: ptr, index: index) 136 | } 137 | 138 | public func as_ptr() -> UnsafePointer { 139 | UnsafePointer(OpaquePointer(T.vecOfSelfAsPtr(vecPtr: ptr))) 140 | } 141 | 142 | /// Rust returns a UInt, but we cast to an Int because many Swift APIs such as 143 | /// `ForEach(0..rustVec.len())` expect Int. 144 | public func len() -> Int { 145 | Int(T.vecOfSelfLen(vecPtr: ptr)) 146 | } 147 | 148 | deinit { 149 | if isOwned { 150 | T.vecOfSelfFree(vecPtr: ptr) 151 | } 152 | } 153 | } 154 | 155 | extension RustVec: Sequence { 156 | public func makeIterator() -> RustVecIterator { 157 | return RustVecIterator(self) 158 | } 159 | } 160 | 161 | public struct RustVecIterator: IteratorProtocol { 162 | var rustVec: RustVec 163 | var index: UInt = 0 164 | 165 | init (_ rustVec: RustVec) { 166 | self.rustVec = rustVec 167 | } 168 | 169 | public mutating func next() -> T.SelfRef? { 170 | let val = rustVec.get(index: index) 171 | index += 1 172 | return val 173 | } 174 | } 175 | 176 | extension RustVec: Collection { 177 | public typealias Index = Int 178 | 179 | public func index(after i: Int) -> Int { 180 | i + 1 181 | } 182 | 183 | public subscript(position: Int) -> T.SelfRef { 184 | self.get(index: UInt(position))! 185 | } 186 | 187 | public var startIndex: Int { 188 | 0 189 | } 190 | 191 | public var endIndex: Int { 192 | self.len() 193 | } 194 | } 195 | 196 | extension RustVec: RandomAccessCollection {} 197 | 198 | extension UnsafeBufferPointer { 199 | func toFfiSlice () -> __private__FfiSlice { 200 | __private__FfiSlice(start: UnsafeMutablePointer(mutating: self.baseAddress), len: UInt(self.count)) 201 | } 202 | } 203 | 204 | public protocol Vectorizable { 205 | associatedtype SelfRef 206 | associatedtype SelfRefMut 207 | 208 | static func vecOfSelfNew() -> UnsafeMutableRawPointer; 209 | 210 | static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) 211 | 212 | static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) 213 | 214 | static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional 215 | 216 | static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional 217 | 218 | static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional 219 | 220 | static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer 221 | 222 | static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt 223 | } 224 | 225 | extension UInt8: Vectorizable { 226 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 227 | __swift_bridge__$Vec_u8$new() 228 | } 229 | 230 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 231 | __swift_bridge__$Vec_u8$_free(vecPtr) 232 | } 233 | 234 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 235 | __swift_bridge__$Vec_u8$push(vecPtr, value) 236 | } 237 | 238 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 239 | let val = __swift_bridge__$Vec_u8$pop(vecPtr) 240 | if val.is_some { 241 | return val.val 242 | } else { 243 | return nil 244 | } 245 | } 246 | 247 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 248 | let val = __swift_bridge__$Vec_u8$get(vecPtr, index) 249 | if val.is_some { 250 | return val.val 251 | } else { 252 | return nil 253 | } 254 | } 255 | 256 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 257 | let val = __swift_bridge__$Vec_u8$get_mut(vecPtr, index) 258 | if val.is_some { 259 | return val.val 260 | } else { 261 | return nil 262 | } 263 | } 264 | 265 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 266 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_u8$as_ptr(vecPtr))) 267 | } 268 | 269 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 270 | __swift_bridge__$Vec_u8$len(vecPtr) 271 | } 272 | } 273 | 274 | extension UInt16: Vectorizable { 275 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 276 | __swift_bridge__$Vec_u16$new() 277 | } 278 | 279 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 280 | __swift_bridge__$Vec_u16$_free(vecPtr) 281 | } 282 | 283 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 284 | __swift_bridge__$Vec_u16$push(vecPtr, value) 285 | } 286 | 287 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 288 | let val = __swift_bridge__$Vec_u16$pop(vecPtr) 289 | if val.is_some { 290 | return val.val 291 | } else { 292 | return nil 293 | } 294 | } 295 | 296 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 297 | let val = __swift_bridge__$Vec_u16$get(vecPtr, index) 298 | if val.is_some { 299 | return val.val 300 | } else { 301 | return nil 302 | } 303 | } 304 | 305 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 306 | let val = __swift_bridge__$Vec_u16$get_mut(vecPtr, index) 307 | if val.is_some { 308 | return val.val 309 | } else { 310 | return nil 311 | } 312 | } 313 | 314 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 315 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_u16$as_ptr(vecPtr))) 316 | } 317 | 318 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 319 | __swift_bridge__$Vec_u16$len(vecPtr) 320 | } 321 | } 322 | 323 | extension UInt32: Vectorizable { 324 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 325 | __swift_bridge__$Vec_u32$new() 326 | } 327 | 328 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 329 | __swift_bridge__$Vec_u32$_free(vecPtr) 330 | } 331 | 332 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 333 | __swift_bridge__$Vec_u32$push(vecPtr, value) 334 | } 335 | 336 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 337 | let val = __swift_bridge__$Vec_u32$pop(vecPtr) 338 | if val.is_some { 339 | return val.val 340 | } else { 341 | return nil 342 | } 343 | } 344 | 345 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 346 | let val = __swift_bridge__$Vec_u32$get(vecPtr, index) 347 | if val.is_some { 348 | return val.val 349 | } else { 350 | return nil 351 | } 352 | } 353 | 354 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 355 | let val = __swift_bridge__$Vec_u32$get_mut(vecPtr, index) 356 | if val.is_some { 357 | return val.val 358 | } else { 359 | return nil 360 | } 361 | } 362 | 363 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 364 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_u32$as_ptr(vecPtr))) 365 | } 366 | 367 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 368 | __swift_bridge__$Vec_u32$len(vecPtr) 369 | } 370 | } 371 | 372 | extension UInt64: Vectorizable { 373 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 374 | __swift_bridge__$Vec_u64$new() 375 | } 376 | 377 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 378 | __swift_bridge__$Vec_u64$_free(vecPtr) 379 | } 380 | 381 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 382 | __swift_bridge__$Vec_u64$push(vecPtr, value) 383 | } 384 | 385 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 386 | let val = __swift_bridge__$Vec_u64$pop(vecPtr) 387 | if val.is_some { 388 | return val.val 389 | } else { 390 | return nil 391 | } 392 | } 393 | 394 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 395 | let val = __swift_bridge__$Vec_u64$get(vecPtr, index) 396 | if val.is_some { 397 | return val.val 398 | } else { 399 | return nil 400 | } 401 | } 402 | 403 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 404 | let val = __swift_bridge__$Vec_u64$get_mut(vecPtr, index) 405 | if val.is_some { 406 | return val.val 407 | } else { 408 | return nil 409 | } 410 | } 411 | 412 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 413 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_u64$as_ptr(vecPtr))) 414 | } 415 | 416 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 417 | __swift_bridge__$Vec_u64$len(vecPtr) 418 | } 419 | } 420 | 421 | extension UInt: Vectorizable { 422 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 423 | __swift_bridge__$Vec_usize$new() 424 | } 425 | 426 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 427 | __swift_bridge__$Vec_usize$_free(vecPtr) 428 | } 429 | 430 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 431 | __swift_bridge__$Vec_usize$push(vecPtr, value) 432 | } 433 | 434 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 435 | let val = __swift_bridge__$Vec_usize$pop(vecPtr) 436 | if val.is_some { 437 | return val.val 438 | } else { 439 | return nil 440 | } 441 | } 442 | 443 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 444 | let val = __swift_bridge__$Vec_usize$get(vecPtr, index) 445 | if val.is_some { 446 | return val.val 447 | } else { 448 | return nil 449 | } 450 | } 451 | 452 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 453 | let val = __swift_bridge__$Vec_usize$get_mut(vecPtr, index) 454 | if val.is_some { 455 | return val.val 456 | } else { 457 | return nil 458 | } 459 | } 460 | 461 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 462 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_usize$as_ptr(vecPtr))) 463 | } 464 | 465 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 466 | __swift_bridge__$Vec_usize$len(vecPtr) 467 | } 468 | } 469 | 470 | extension Int8: Vectorizable { 471 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 472 | __swift_bridge__$Vec_i8$new() 473 | } 474 | 475 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 476 | __swift_bridge__$Vec_i8$_free(vecPtr) 477 | } 478 | 479 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 480 | __swift_bridge__$Vec_i8$push(vecPtr, value) 481 | } 482 | 483 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 484 | let val = __swift_bridge__$Vec_i8$pop(vecPtr) 485 | if val.is_some { 486 | return val.val 487 | } else { 488 | return nil 489 | } 490 | } 491 | 492 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 493 | let val = __swift_bridge__$Vec_i8$get(vecPtr, index) 494 | if val.is_some { 495 | return val.val 496 | } else { 497 | return nil 498 | } 499 | } 500 | 501 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 502 | let val = __swift_bridge__$Vec_i8$get_mut(vecPtr, index) 503 | if val.is_some { 504 | return val.val 505 | } else { 506 | return nil 507 | } 508 | } 509 | 510 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 511 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_i8$as_ptr(vecPtr))) 512 | } 513 | 514 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 515 | __swift_bridge__$Vec_i8$len(vecPtr) 516 | } 517 | } 518 | 519 | extension Int16: Vectorizable { 520 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 521 | __swift_bridge__$Vec_i16$new() 522 | } 523 | 524 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 525 | __swift_bridge__$Vec_i16$_free(vecPtr) 526 | } 527 | 528 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 529 | __swift_bridge__$Vec_i16$push(vecPtr, value) 530 | } 531 | 532 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 533 | let val = __swift_bridge__$Vec_i16$pop(vecPtr) 534 | if val.is_some { 535 | return val.val 536 | } else { 537 | return nil 538 | } 539 | } 540 | 541 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 542 | let val = __swift_bridge__$Vec_i16$get(vecPtr, index) 543 | if val.is_some { 544 | return val.val 545 | } else { 546 | return nil 547 | } 548 | } 549 | 550 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 551 | let val = __swift_bridge__$Vec_i16$get_mut(vecPtr, index) 552 | if val.is_some { 553 | return val.val 554 | } else { 555 | return nil 556 | } 557 | } 558 | 559 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 560 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_i16$as_ptr(vecPtr))) 561 | } 562 | 563 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 564 | __swift_bridge__$Vec_i16$len(vecPtr) 565 | } 566 | } 567 | 568 | extension Int32: Vectorizable { 569 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 570 | __swift_bridge__$Vec_i32$new() 571 | } 572 | 573 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 574 | __swift_bridge__$Vec_i32$_free(vecPtr) 575 | } 576 | 577 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 578 | __swift_bridge__$Vec_i32$push(vecPtr, value) 579 | } 580 | 581 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 582 | let val = __swift_bridge__$Vec_i32$pop(vecPtr) 583 | if val.is_some { 584 | return val.val 585 | } else { 586 | return nil 587 | } 588 | } 589 | 590 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 591 | let val = __swift_bridge__$Vec_i32$get(vecPtr, index) 592 | if val.is_some { 593 | return val.val 594 | } else { 595 | return nil 596 | } 597 | } 598 | 599 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 600 | let val = __swift_bridge__$Vec_i32$get_mut(vecPtr, index) 601 | if val.is_some { 602 | return val.val 603 | } else { 604 | return nil 605 | } 606 | } 607 | 608 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 609 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_i32$as_ptr(vecPtr))) 610 | } 611 | 612 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 613 | __swift_bridge__$Vec_i32$len(vecPtr) 614 | } 615 | } 616 | 617 | extension Int64: Vectorizable { 618 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 619 | __swift_bridge__$Vec_i64$new() 620 | } 621 | 622 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 623 | __swift_bridge__$Vec_i64$_free(vecPtr) 624 | } 625 | 626 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 627 | __swift_bridge__$Vec_i64$push(vecPtr, value) 628 | } 629 | 630 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 631 | let val = __swift_bridge__$Vec_i64$pop(vecPtr) 632 | if val.is_some { 633 | return val.val 634 | } else { 635 | return nil 636 | } 637 | } 638 | 639 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 640 | let val = __swift_bridge__$Vec_i64$get(vecPtr, index) 641 | if val.is_some { 642 | return val.val 643 | } else { 644 | return nil 645 | } 646 | } 647 | 648 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 649 | let val = __swift_bridge__$Vec_i64$get_mut(vecPtr, index) 650 | if val.is_some { 651 | return val.val 652 | } else { 653 | return nil 654 | } 655 | } 656 | 657 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 658 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_i64$as_ptr(vecPtr))) 659 | } 660 | 661 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 662 | __swift_bridge__$Vec_i64$len(vecPtr) 663 | } 664 | } 665 | 666 | extension Int: Vectorizable { 667 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 668 | __swift_bridge__$Vec_isize$new() 669 | } 670 | 671 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 672 | __swift_bridge__$Vec_isize$_free(vecPtr) 673 | } 674 | 675 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 676 | __swift_bridge__$Vec_isize$push(vecPtr, value) 677 | } 678 | 679 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 680 | let val = __swift_bridge__$Vec_isize$pop(vecPtr) 681 | if val.is_some { 682 | return val.val 683 | } else { 684 | return nil 685 | } 686 | } 687 | 688 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 689 | let val = __swift_bridge__$Vec_isize$get(vecPtr, index) 690 | if val.is_some { 691 | return val.val 692 | } else { 693 | return nil 694 | } 695 | } 696 | 697 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 698 | let val = __swift_bridge__$Vec_isize$get_mut(vecPtr, index) 699 | if val.is_some { 700 | return val.val 701 | } else { 702 | return nil 703 | } 704 | } 705 | 706 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 707 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_isize$as_ptr(vecPtr))) 708 | } 709 | 710 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 711 | __swift_bridge__$Vec_isize$len(vecPtr) 712 | } 713 | } 714 | 715 | extension Bool: Vectorizable { 716 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 717 | __swift_bridge__$Vec_bool$new() 718 | } 719 | 720 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 721 | __swift_bridge__$Vec_bool$_free(vecPtr) 722 | } 723 | 724 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 725 | __swift_bridge__$Vec_bool$push(vecPtr, value) 726 | } 727 | 728 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 729 | let val = __swift_bridge__$Vec_bool$pop(vecPtr) 730 | if val.is_some { 731 | return val.val 732 | } else { 733 | return nil 734 | } 735 | } 736 | 737 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 738 | let val = __swift_bridge__$Vec_bool$get(vecPtr, index) 739 | if val.is_some { 740 | return val.val 741 | } else { 742 | return nil 743 | } 744 | } 745 | 746 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 747 | let val = __swift_bridge__$Vec_bool$get_mut(vecPtr, index) 748 | if val.is_some { 749 | return val.val 750 | } else { 751 | return nil 752 | } 753 | } 754 | 755 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 756 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_bool$as_ptr(vecPtr))) 757 | } 758 | 759 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 760 | __swift_bridge__$Vec_bool$len(vecPtr) 761 | } 762 | } 763 | 764 | extension Float: Vectorizable { 765 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 766 | __swift_bridge__$Vec_f32$new() 767 | } 768 | 769 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 770 | __swift_bridge__$Vec_f32$_free(vecPtr) 771 | } 772 | 773 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 774 | __swift_bridge__$Vec_f32$push(vecPtr, value) 775 | } 776 | 777 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 778 | let val = __swift_bridge__$Vec_f32$pop(vecPtr) 779 | if val.is_some { 780 | return val.val 781 | } else { 782 | return nil 783 | } 784 | } 785 | 786 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 787 | let val = __swift_bridge__$Vec_f32$get(vecPtr, index) 788 | if val.is_some { 789 | return val.val 790 | } else { 791 | return nil 792 | } 793 | } 794 | 795 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 796 | let val = __swift_bridge__$Vec_f32$get_mut(vecPtr, index) 797 | if val.is_some { 798 | return val.val 799 | } else { 800 | return nil 801 | } 802 | } 803 | 804 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 805 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_f32$as_ptr(vecPtr))) 806 | } 807 | 808 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 809 | __swift_bridge__$Vec_f32$len(vecPtr) 810 | } 811 | } 812 | 813 | extension Double: Vectorizable { 814 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 815 | __swift_bridge__$Vec_f64$new() 816 | } 817 | 818 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 819 | __swift_bridge__$Vec_f64$_free(vecPtr) 820 | } 821 | 822 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { 823 | __swift_bridge__$Vec_f64$push(vecPtr, value) 824 | } 825 | 826 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 827 | let val = __swift_bridge__$Vec_f64$pop(vecPtr) 828 | if val.is_some { 829 | return val.val 830 | } else { 831 | return nil 832 | } 833 | } 834 | 835 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 836 | let val = __swift_bridge__$Vec_f64$get(vecPtr, index) 837 | if val.is_some { 838 | return val.val 839 | } else { 840 | return nil 841 | } 842 | } 843 | 844 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 845 | let val = __swift_bridge__$Vec_f64$get_mut(vecPtr, index) 846 | if val.is_some { 847 | return val.val 848 | } else { 849 | return nil 850 | } 851 | } 852 | 853 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 854 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_f64$as_ptr(vecPtr))) 855 | } 856 | 857 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 858 | __swift_bridge__$Vec_f64$len(vecPtr) 859 | } 860 | } 861 | 862 | protocol SwiftBridgeGenericFreer { 863 | func rust_free(); 864 | } 865 | 866 | protocol SwiftBridgeGenericCopyTypeFfiRepr {} 867 | 868 | public class RustString: RustStringRefMut { 869 | var isOwned: Bool = true 870 | 871 | public override init(ptr: UnsafeMutableRawPointer) { 872 | super.init(ptr: ptr) 873 | } 874 | 875 | deinit { 876 | if isOwned { 877 | __swift_bridge__$RustString$_free(ptr) 878 | } 879 | } 880 | } 881 | extension RustString { 882 | public convenience init() { 883 | self.init(ptr: __swift_bridge__$RustString$new()) 884 | } 885 | 886 | public convenience init(_ str: GenericToRustStr) { 887 | self.init(ptr: str.toRustStr({ strAsRustStr in 888 | __swift_bridge__$RustString$new_with_str(strAsRustStr) 889 | })) 890 | } 891 | } 892 | public class RustStringRefMut: RustStringRef { 893 | public override init(ptr: UnsafeMutableRawPointer) { 894 | super.init(ptr: ptr) 895 | } 896 | } 897 | public class RustStringRef { 898 | var ptr: UnsafeMutableRawPointer 899 | 900 | public init(ptr: UnsafeMutableRawPointer) { 901 | self.ptr = ptr 902 | } 903 | } 904 | extension RustStringRef { 905 | public func len() -> UInt { 906 | __swift_bridge__$RustString$len(ptr) 907 | } 908 | 909 | public func as_str() -> RustStr { 910 | __swift_bridge__$RustString$as_str(ptr) 911 | } 912 | 913 | public func trim() -> RustStr { 914 | __swift_bridge__$RustString$trim(ptr) 915 | } 916 | } 917 | extension RustString: Vectorizable { 918 | public static func vecOfSelfNew() -> UnsafeMutableRawPointer { 919 | __swift_bridge__$Vec_RustString$new() 920 | } 921 | 922 | public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { 923 | __swift_bridge__$Vec_RustString$drop(vecPtr) 924 | } 925 | 926 | public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: RustString) { 927 | __swift_bridge__$Vec_RustString$push(vecPtr, {value.isOwned = false; return value.ptr;}()) 928 | } 929 | 930 | public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional { 931 | let pointer = __swift_bridge__$Vec_RustString$pop(vecPtr) 932 | if pointer == nil { 933 | return nil 934 | } else { 935 | return (RustString(ptr: pointer!) as! Self) 936 | } 937 | } 938 | 939 | public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 940 | let pointer = __swift_bridge__$Vec_RustString$get(vecPtr, index) 941 | if pointer == nil { 942 | return nil 943 | } else { 944 | return RustStringRef(ptr: pointer!) 945 | } 946 | } 947 | 948 | public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional { 949 | let pointer = __swift_bridge__$Vec_RustString$get_mut(vecPtr, index) 950 | if pointer == nil { 951 | return nil 952 | } else { 953 | return RustStringRefMut(ptr: pointer!) 954 | } 955 | } 956 | 957 | public static func vecOfSelfAsPtr(vecPtr: UnsafeMutableRawPointer) -> UnsafePointer { 958 | UnsafePointer(OpaquePointer(__swift_bridge__$Vec_RustString$as_ptr(vecPtr))) 959 | } 960 | 961 | public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { 962 | __swift_bridge__$Vec_RustString$len(vecPtr) 963 | } 964 | } 965 | 966 | public class __private__RustFnOnceCallbackNoArgsNoRet { 967 | var ptr: UnsafeMutableRawPointer 968 | var called = false 969 | 970 | init(ptr: UnsafeMutableRawPointer) { 971 | self.ptr = ptr 972 | } 973 | 974 | deinit { 975 | if !called { 976 | __swift_bridge__$free_boxed_fn_once_no_args_no_return(ptr) 977 | } 978 | } 979 | 980 | func call() { 981 | if called { 982 | fatalError("Cannot call a Rust FnOnce function twice") 983 | } 984 | called = true 985 | return __swift_bridge__$call_boxed_fn_once_no_args_no_return(ptr) 986 | } 987 | } 988 | 989 | 990 | public enum RustResult { 991 | case Ok(T) 992 | case Err(E) 993 | } 994 | 995 | extension RustResult { 996 | func ok() -> T? { 997 | switch self { 998 | case .Ok(let ok): 999 | return ok 1000 | case .Err(_): 1001 | return nil 1002 | } 1003 | } 1004 | 1005 | func err() -> E? { 1006 | switch self { 1007 | case .Ok(_): 1008 | return nil 1009 | case .Err(let err): 1010 | return err 1011 | } 1012 | } 1013 | 1014 | func toResult() -> Result 1015 | where E: Error { 1016 | switch self { 1017 | case .Ok(let ok): 1018 | return .success(ok) 1019 | case .Err(let err): 1020 | return .failure(err) 1021 | } 1022 | } 1023 | } 1024 | 1025 | 1026 | extension __private__OptionU8 { 1027 | func intoSwiftRepr() -> Optional { 1028 | if self.is_some { 1029 | return self.val 1030 | } else { 1031 | return nil 1032 | } 1033 | } 1034 | 1035 | init(_ val: Optional) { 1036 | if let val = val { 1037 | self = Self(val: val, is_some: true) 1038 | } else { 1039 | self = Self(val: 123, is_some: false) 1040 | } 1041 | } 1042 | } 1043 | extension Optional where Wrapped == UInt8 { 1044 | func intoFfiRepr() -> __private__OptionU8 { 1045 | __private__OptionU8(self) 1046 | } 1047 | } 1048 | 1049 | extension __private__OptionI8 { 1050 | func intoSwiftRepr() -> Optional { 1051 | if self.is_some { 1052 | return self.val 1053 | } else { 1054 | return nil 1055 | } 1056 | } 1057 | 1058 | init(_ val: Optional) { 1059 | if let val = val { 1060 | self = Self(val: val, is_some: true) 1061 | } else { 1062 | self = Self(val: 123, is_some: false) 1063 | } 1064 | } 1065 | } 1066 | extension Optional where Wrapped == Int8 { 1067 | func intoFfiRepr() -> __private__OptionI8 { 1068 | __private__OptionI8(self) 1069 | } 1070 | } 1071 | 1072 | extension __private__OptionU16 { 1073 | func intoSwiftRepr() -> Optional { 1074 | if self.is_some { 1075 | return self.val 1076 | } else { 1077 | return nil 1078 | } 1079 | } 1080 | 1081 | init(_ val: Optional) { 1082 | if let val = val { 1083 | self = Self(val: val, is_some: true) 1084 | } else { 1085 | self = Self(val: 123, is_some: false) 1086 | } 1087 | } 1088 | } 1089 | extension Optional where Wrapped == UInt16 { 1090 | func intoFfiRepr() -> __private__OptionU16 { 1091 | __private__OptionU16(self) 1092 | } 1093 | } 1094 | 1095 | extension __private__OptionI16 { 1096 | func intoSwiftRepr() -> Optional { 1097 | if self.is_some { 1098 | return self.val 1099 | } else { 1100 | return nil 1101 | } 1102 | } 1103 | 1104 | init(_ val: Optional) { 1105 | if let val = val { 1106 | self = Self(val: val, is_some: true) 1107 | } else { 1108 | self = Self(val: 123, is_some: false) 1109 | } 1110 | } 1111 | } 1112 | extension Optional where Wrapped == Int16 { 1113 | func intoFfiRepr() -> __private__OptionI16 { 1114 | __private__OptionI16(self) 1115 | } 1116 | } 1117 | 1118 | extension __private__OptionU32 { 1119 | func intoSwiftRepr() -> Optional { 1120 | if self.is_some { 1121 | return self.val 1122 | } else { 1123 | return nil 1124 | } 1125 | } 1126 | 1127 | init(_ val: Optional) { 1128 | if let val = val { 1129 | self = Self(val: val, is_some: true) 1130 | } else { 1131 | self = Self(val: 123, is_some: false) 1132 | } 1133 | } 1134 | } 1135 | extension Optional where Wrapped == UInt32 { 1136 | func intoFfiRepr() -> __private__OptionU32 { 1137 | __private__OptionU32(self) 1138 | } 1139 | } 1140 | 1141 | extension __private__OptionI32 { 1142 | func intoSwiftRepr() -> Optional { 1143 | if self.is_some { 1144 | return self.val 1145 | } else { 1146 | return nil 1147 | } 1148 | } 1149 | 1150 | init(_ val: Optional) { 1151 | if let val = val { 1152 | self = Self(val: val, is_some: true) 1153 | } else { 1154 | self = Self(val: 123, is_some: false) 1155 | } 1156 | } 1157 | } 1158 | extension Optional where Wrapped == Int32 { 1159 | func intoFfiRepr() -> __private__OptionI32 { 1160 | __private__OptionI32(self) 1161 | } 1162 | } 1163 | 1164 | extension __private__OptionU64 { 1165 | func intoSwiftRepr() -> Optional { 1166 | if self.is_some { 1167 | return self.val 1168 | } else { 1169 | return nil 1170 | } 1171 | } 1172 | 1173 | init(_ val: Optional) { 1174 | if let val = val { 1175 | self = Self(val: val, is_some: true) 1176 | } else { 1177 | self = Self(val: 123, is_some: false) 1178 | } 1179 | } 1180 | } 1181 | extension Optional where Wrapped == UInt64 { 1182 | func intoFfiRepr() -> __private__OptionU64 { 1183 | __private__OptionU64(self) 1184 | } 1185 | } 1186 | 1187 | extension __private__OptionI64 { 1188 | func intoSwiftRepr() -> Optional { 1189 | if self.is_some { 1190 | return self.val 1191 | } else { 1192 | return nil 1193 | } 1194 | } 1195 | 1196 | init(_ val: Optional) { 1197 | if let val = val { 1198 | self = Self(val: val, is_some: true) 1199 | } else { 1200 | self = Self(val: 123, is_some: false) 1201 | } 1202 | } 1203 | } 1204 | extension Optional where Wrapped == Int64 { 1205 | func intoFfiRepr() -> __private__OptionI64 { 1206 | __private__OptionI64(self) 1207 | } 1208 | } 1209 | 1210 | extension __private__OptionUsize { 1211 | func intoSwiftRepr() -> Optional { 1212 | if self.is_some { 1213 | return self.val 1214 | } else { 1215 | return nil 1216 | } 1217 | } 1218 | 1219 | init(_ val: Optional) { 1220 | if let val = val { 1221 | self = Self(val: val, is_some: true) 1222 | } else { 1223 | self = Self(val: 123, is_some: false) 1224 | } 1225 | } 1226 | } 1227 | extension Optional where Wrapped == UInt { 1228 | func intoFfiRepr() -> __private__OptionUsize { 1229 | __private__OptionUsize(self) 1230 | } 1231 | } 1232 | 1233 | extension __private__OptionIsize { 1234 | func intoSwiftRepr() -> Optional { 1235 | if self.is_some { 1236 | return self.val 1237 | } else { 1238 | return nil 1239 | } 1240 | } 1241 | 1242 | init(_ val: Optional) { 1243 | if let val = val { 1244 | self = Self(val: val, is_some: true) 1245 | } else { 1246 | self = Self(val: 123, is_some: false) 1247 | } 1248 | } 1249 | } 1250 | extension Optional where Wrapped == Int { 1251 | func intoFfiRepr() -> __private__OptionIsize { 1252 | __private__OptionIsize(self) 1253 | } 1254 | } 1255 | 1256 | extension __private__OptionF32 { 1257 | func intoSwiftRepr() -> Optional { 1258 | if self.is_some { 1259 | return self.val 1260 | } else { 1261 | return nil 1262 | } 1263 | } 1264 | 1265 | init(_ val: Optional) { 1266 | if let val = val { 1267 | self = Self(val: val, is_some: true) 1268 | } else { 1269 | self = Self(val: 123.4, is_some: false) 1270 | } 1271 | } 1272 | } 1273 | extension Optional where Wrapped == Float { 1274 | func intoFfiRepr() -> __private__OptionF32 { 1275 | __private__OptionF32(self) 1276 | } 1277 | } 1278 | 1279 | extension __private__OptionF64 { 1280 | func intoSwiftRepr() -> Optional { 1281 | if self.is_some { 1282 | return self.val 1283 | } else { 1284 | return nil 1285 | } 1286 | } 1287 | 1288 | init(_ val: Optional) { 1289 | if let val = val { 1290 | self = Self(val: val, is_some: true) 1291 | } else { 1292 | self = Self(val: 123.4, is_some: false) 1293 | } 1294 | } 1295 | } 1296 | extension Optional where Wrapped == Double { 1297 | func intoFfiRepr() -> __private__OptionF64 { 1298 | __private__OptionF64(self) 1299 | } 1300 | } 1301 | 1302 | extension __private__OptionBool { 1303 | func intoSwiftRepr() -> Optional { 1304 | if self.is_some { 1305 | return self.val 1306 | } else { 1307 | return nil 1308 | } 1309 | } 1310 | 1311 | init(_ val: Optional) { 1312 | if let val = val { 1313 | self = Self(val: val, is_some: true) 1314 | } else { 1315 | self = Self(val: false, is_some: false) 1316 | } 1317 | } 1318 | } 1319 | extension Optional where Wrapped == Bool { 1320 | func intoFfiRepr() -> __private__OptionBool { 1321 | __private__OptionBool(self) 1322 | } 1323 | } 1324 | -------------------------------------------------------------------------------- /Tests/bevy_ios_iapTests/bevy_ios_iapTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import bevy_ios_iap 3 | 4 | final class bevy_ios_iapTests: XCTestCase { 5 | func testExample() throws { 6 | // XCTest Documentation 7 | // https://developer.apple.com/documentation/xctest 8 | 9 | // Defining Test Cases and Test Methods 10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustunit/bevy_ios_iap/5f2d47cafaeef2c7685bad7bc795bcc7008a295a/assets/demo.gif -------------------------------------------------------------------------------- /assets/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustunit/bevy_ios_iap/5f2d47cafaeef2c7685bad7bc795bcc7008a295a/assets/framework.png -------------------------------------------------------------------------------- /assets/xcode-spm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustunit/bevy_ios_iap/5f2d47cafaeef2c7685bad7bc795bcc7008a295a/assets/xcode-spm.png -------------------------------------------------------------------------------- /bevy_ios_iap/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | generated/ -------------------------------------------------------------------------------- /bevy_ios_iap/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.target": "aarch64-apple-ios-sim" 3 | } -------------------------------------------------------------------------------- /bevy_ios_iap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bevy_ios_iap" 3 | version = "0.7.0" 4 | edition = "2024" 5 | build = "build.rs" 6 | readme = "../README.md" 7 | license = "MIT" 8 | authors = ["extrawurst "] 9 | documentation = "https://docs.rs/bevy_ios_iap" 10 | repository = "https://github.com/rustunit/bevy_ios_iap" 11 | keywords = ["bevy", "gamedev", "mobile", "ios", "swift"] 12 | description = "Bevy Plugin and Swift Package to provide access to iOS native StoreKit2 from inside Bevy Apps" 13 | 14 | [lib] 15 | crate-type = ["staticlib", "rlib"] 16 | 17 | [dependencies] 18 | bevy_app = { version = "0.16", default-features = false } 19 | bevy_ecs = { version = "0.16", default-features = false } 20 | bevy_ecs_macros = { version = "0.16", default-features = false } 21 | bevy_log = { version = "0.16", default-features = false } 22 | bevy_crossbeam_event = "0.8" 23 | swift-bridge = "0.1" 24 | 25 | [build-dependencies] 26 | swift-bridge-build = "0.1" 27 | -------------------------------------------------------------------------------- /bevy_ios_iap/build-rust-release.sh: -------------------------------------------------------------------------------- 1 | # build-rust.sh 2 | 3 | #!/bin/bash 4 | 5 | set -e 6 | 7 | THISDIR=$(dirname $0) 8 | cd $THISDIR 9 | 10 | touch ./src/lib.rs 11 | cargo build --release --target aarch64-apple-ios 12 | cargo build --release --target x86_64-apple-ios 13 | # TODO: enable once https://github.com/rust-lang/rust-bindgen/issues/3181 is released 14 | # cargo build --release --target aarch64-apple-ios-sim 15 | # 16 | mkdir -p ./target/universal-ios/release 17 | 18 | # TODO: add back sim target 19 | lipo -create \ 20 | "./target/aarch64-apple-ios/release/libbevy_ios_iap.a" \ 21 | "./target/x86_64-apple-ios/release/libbevy_ios_iap.a" \ 22 | -output ./target/universal-ios/release/libbevy_ios_iap.a 23 | -------------------------------------------------------------------------------- /bevy_ios_iap/build-rust.sh: -------------------------------------------------------------------------------- 1 | # build-rust.sh 2 | 3 | #!/bin/bash 4 | 5 | set -e 6 | 7 | THISDIR=$(dirname $0) 8 | cd $THISDIR 9 | 10 | touch ./src/lib.rs 11 | cargo build --target aarch64-apple-ios 12 | cargo build --target x86_64-apple-ios 13 | # TODO: enable once https://github.com/rust-lang/rust-bindgen/issues/3181 is released 14 | # cargo build --target aarch64-apple-ios-sim 15 | 16 | mkdir -p ./target/universal-ios/debug 17 | 18 | # TODO: add back sim target 19 | lipo -create \ 20 | "./target/aarch64-apple-ios/debug/libbevy_ios_iap.a" \ 21 | "./target/x86_64-apple-ios/debug/libbevy_ios_iap.a" \ 22 | -output ./target/universal-ios/debug/libbevy_ios_iap.a 23 | -------------------------------------------------------------------------------- /bevy_ios_iap/build.rs: -------------------------------------------------------------------------------- 1 | // build.rs 2 | 3 | use std::path::PathBuf; 4 | 5 | fn main() { 6 | let is_doc_rs = std::env::var("DOCS_RS") 7 | .map(|doc| &doc == "1") 8 | .unwrap_or_default(); 9 | 10 | if !is_doc_rs { 11 | let out_dir = PathBuf::from("./generated"); 12 | 13 | let bridges = vec!["src/lib.rs", "src/native.rs"]; 14 | for path in &bridges { 15 | println!("cargo:rerun-if-changed={}", path); 16 | } 17 | 18 | swift_bridge_build::parse_bridges(bridges) 19 | .write_all_concatenated(out_dir, env!("CARGO_PKG_NAME")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bevy_ios_iap/justfile: -------------------------------------------------------------------------------- 1 | check: 2 | cargo c 3 | cargo c --target=aarch64-apple-ios 4 | cargo clippy 5 | cargo fmt -- --check 6 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod methods; 2 | mod native; 3 | mod plugin; 4 | mod request; 5 | mod response; 6 | mod transaction; 7 | 8 | pub use methods::{ 9 | all_transactions, current_entitlements, finish_transaction, get_products, init, purchase, 10 | }; 11 | pub use plugin::{IosIapEvents, IosIapPlugin, IosIapResponse}; 12 | pub use request::{ 13 | AllTransactions, BevyIosIap, BevyIosIapRequestBuilder, CurrentEntitlements, FinishTransaction, 14 | Products, Purchase, 15 | }; 16 | pub use response::{ 17 | IosIapProductsResponse, IosIapPurchaseError, IosIapPurchaseResponse, IosIapStoreKitError, 18 | IosIapTransactionFinishResponse, IosIapTransactionResponse, 19 | }; 20 | pub use transaction::IosIapTransaction; 21 | 22 | /// A cause of a purchase transaction, indicating whether it’s a customer’s purchase or 23 | /// an auto-renewable subscription renewal that the system initiates. 24 | /// 25 | /// Part of [`IosIapTransaction`]. 26 | /// 27 | /// See 28 | #[derive(Debug, Clone)] 29 | pub enum IosIapTransactionReason { 30 | Renewal, 31 | Purchase, 32 | } 33 | 34 | impl IosIapTransactionReason { 35 | pub fn renewal() -> Self { 36 | Self::Renewal 37 | } 38 | pub fn purchase() -> Self { 39 | Self::Purchase 40 | } 41 | } 42 | 43 | /// The server environment that generates and signs the transaction. 44 | /// 45 | /// Part of [`IosIapTransaction`]. 46 | /// 47 | /// See 48 | #[derive(Debug, Clone)] 49 | pub enum IosIapEnvironment { 50 | Production, 51 | Sandbox, 52 | XCode, 53 | } 54 | 55 | impl IosIapEnvironment { 56 | pub fn production() -> Self { 57 | Self::Production 58 | } 59 | pub fn sandbox() -> Self { 60 | Self::Sandbox 61 | } 62 | pub fn xcode() -> Self { 63 | Self::XCode 64 | } 65 | } 66 | 67 | /// The App Store storefront associated with the transaction. 68 | /// 69 | /// Part of [`IosIapTransaction`]. 70 | /// 71 | /// See 72 | #[derive(Debug, Clone, Default)] 73 | pub struct IosIapStorefront { 74 | pub id: String, 75 | pub country_code: String, 76 | } 77 | 78 | impl IosIapStorefront { 79 | fn storefront(id: String, country_code: String) -> Self { 80 | Self { id, country_code } 81 | } 82 | } 83 | 84 | /// The type of the in-app purchase. 85 | /// 86 | /// Part of [`IosIapTransaction`] and [`IosIapProduct`]. 87 | /// 88 | /// See 89 | #[derive(Debug, Clone)] 90 | pub enum IosIapProductType { 91 | Consumable, 92 | NonConsumable, 93 | NonRenewable, 94 | AutoRenewable, 95 | } 96 | 97 | impl IosIapProductType { 98 | fn new_consumable(non: bool) -> Self { 99 | if non { 100 | Self::NonConsumable 101 | } else { 102 | Self::Consumable 103 | } 104 | } 105 | 106 | fn new_non_renewable() -> Self { 107 | Self::NonRenewable 108 | } 109 | 110 | fn new_auto_renewable() -> Self { 111 | Self::AutoRenewable 112 | } 113 | } 114 | 115 | /// Expected event data in response to [`get_products`] method call. 116 | /// 117 | /// See Event [`IosIapEvents`] 118 | /// 119 | /// See 120 | #[derive(Debug, Clone)] 121 | pub struct IosIapProduct { 122 | pub id: String, 123 | pub display_price: String, 124 | pub display_name: String, 125 | pub description: String, 126 | pub price: f64, 127 | pub product_type: IosIapProductType, 128 | pub subscription: Option, 129 | } 130 | 131 | impl IosIapProduct { 132 | fn new( 133 | id: String, 134 | display_price: String, 135 | display_name: String, 136 | description: String, 137 | price: f64, 138 | product_type: IosIapProductType, 139 | ) -> Self { 140 | Self { 141 | id, 142 | display_price, 143 | display_name, 144 | description, 145 | price, 146 | product_type, 147 | subscription: None, 148 | } 149 | } 150 | 151 | fn subscription(p: &mut Self, info: IosIapSubscriptionInfo) { 152 | p.subscription = Some(info); 153 | } 154 | } 155 | 156 | /// Expected event data in response to [`get_products`] method call. 157 | /// 158 | /// See [`IosIapProduct`] 159 | /// 160 | /// See 161 | #[derive(Debug, Clone)] 162 | pub struct IosIapSubscriptionInfo { 163 | pub group_id: String, 164 | pub period: IosIapSubscriptionPeriod, 165 | pub is_eligible_for_intro_offer: bool, 166 | pub state: Vec, 167 | } 168 | 169 | impl IosIapSubscriptionInfo { 170 | fn new( 171 | group_id: String, 172 | period: IosIapSubscriptionPeriod, 173 | is_eligible_for_intro_offer: bool, 174 | state: Vec, 175 | ) -> Self { 176 | Self { 177 | group_id, 178 | period, 179 | is_eligible_for_intro_offer, 180 | state, 181 | } 182 | } 183 | } 184 | 185 | /// Used in [`IosIapSubscriptionPeriod`] 186 | /// 187 | /// See 188 | #[derive(Debug, Clone)] 189 | pub enum IosIapSubscriptionPeriodUnit { 190 | Day, 191 | Week, 192 | Month, 193 | Year, 194 | } 195 | 196 | impl IosIapSubscriptionPeriodUnit { 197 | pub fn day() -> Self { 198 | Self::Day 199 | } 200 | pub fn week() -> Self { 201 | Self::Week 202 | } 203 | pub fn month() -> Self { 204 | Self::Month 205 | } 206 | pub fn year() -> Self { 207 | Self::Year 208 | } 209 | } 210 | 211 | /// Used in [`IosIapSubscriptionInfo`] 212 | /// 213 | /// See 214 | #[derive(Debug, Clone)] 215 | pub struct IosIapSubscriptionPeriod { 216 | pub unit: IosIapSubscriptionPeriodUnit, 217 | pub value: i32, 218 | } 219 | 220 | impl IosIapSubscriptionPeriod { 221 | pub fn new(unit: IosIapSubscriptionPeriodUnit, value: i32) -> Self { 222 | Self { unit, value } 223 | } 224 | } 225 | 226 | /// Used in [`IosIapSubscriptionStatus`] 227 | /// 228 | /// See 229 | #[derive(Debug, Clone)] 230 | pub enum IosIapSubscriptionRenewalState { 231 | Subscribed, 232 | Expired, 233 | InBillingRetryPeriod, 234 | InGracePeriod, 235 | Revoked, 236 | } 237 | 238 | impl IosIapSubscriptionRenewalState { 239 | pub fn subscribed() -> Self { 240 | Self::Subscribed 241 | } 242 | pub fn expired() -> Self { 243 | Self::Expired 244 | } 245 | pub fn in_billing_retry_period() -> Self { 246 | Self::InBillingRetryPeriod 247 | } 248 | pub fn in_grace_period() -> Self { 249 | Self::InGracePeriod 250 | } 251 | pub fn revoked() -> Self { 252 | Self::Revoked 253 | } 254 | } 255 | 256 | /// Used in [`IosIapSubscriptionInfo`] 257 | /// 258 | /// See 259 | #[derive(Debug, Clone)] 260 | pub struct IosIapSubscriptionStatus { 261 | pub state: IosIapSubscriptionRenewalState, 262 | pub transaction: IosIapTransaction, 263 | } 264 | 265 | impl IosIapSubscriptionStatus { 266 | pub fn new(state: IosIapSubscriptionRenewalState, transaction: IosIapTransaction) -> Self { 267 | Self { state, transaction } 268 | } 269 | } 270 | 271 | /// Used in [`IosIapTransaction`] 272 | /// 273 | /// See 274 | #[derive(Debug, Clone)] 275 | pub struct IosIapCurrency { 276 | pub identifier: String, 277 | pub is_iso_currency: bool, 278 | } 279 | 280 | impl IosIapCurrency { 281 | pub fn new(identifier: String, is_iso_currency: bool) -> Self { 282 | Self { 283 | identifier, 284 | is_iso_currency, 285 | } 286 | } 287 | } 288 | 289 | /// Used in [`IosIapTransaction`] 290 | /// 291 | /// See 292 | #[derive(Debug, Clone)] 293 | pub enum IosIapRevocationReason { 294 | DeveloperIssue, 295 | Other, 296 | } 297 | 298 | impl IosIapRevocationReason { 299 | pub fn developer_issue() -> Self { 300 | Self::DeveloperIssue 301 | } 302 | pub fn other() -> Self { 303 | Self::Other 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/methods.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | #[allow(unused_imports)] 4 | use crate::native; 5 | 6 | /// Registers for any updates on Transactions. 7 | /// Any such update will trigger: [`IosIapEvents::TransactionUpdate`][crate::IosIapEvents::TransactionUpdate] 8 | /// 9 | /// See 10 | pub fn init() { 11 | #[cfg(target_os = "ios")] 12 | native::ios_iap_init(); 13 | } 14 | 15 | /// Fetch Product Details. A list of Product IDs has to be provided. 16 | /// Expected to be confirmed with event: [`IosIapEvents::Products`][crate::IosIapEvents::Products] 17 | /// 18 | /// See 19 | pub fn get_products(request: i64, products: Vec) { 20 | #[cfg(target_os = "ios")] 21 | native::ios_iap_products(request, products); 22 | } 23 | 24 | /// Trigger a purchase flow. The product ID has to be provided 25 | /// Expected to be confirmed with event: [`IosIapEvents::Purchase`][crate::IosIapEvents::Purchase] 26 | /// 27 | /// See 28 | pub fn purchase(request: i64, id: String) { 29 | #[cfg(target_os = "ios")] 30 | native::ios_iap_purchase(request, id); 31 | } 32 | 33 | /// Finishes a Transaction. Identify the Transaction with an ID. 34 | /// Apple expects us to call this only after the user got the Product granted so we can safely consider this purchase finished. 35 | /// Until the transaction is finished iOS will keep triggering it as soon as we register the 36 | /// TransactionObserver via the `init` call. See [`crate::init`]. 37 | /// 38 | /// Expected to be confirmed with event: [`IosIapEvents::TransactionFinished`][crate::IosIapEvents::TransactionFinished] 39 | /// 40 | /// See 41 | pub fn finish_transaction(request: i64, transaction_id: u64) { 42 | #[cfg(target_os = "ios")] 43 | native::ios_iap_transaction_finish(request, transaction_id); 44 | } 45 | 46 | /// Quoted from Apple's docs: "A sequence that emits all the transactions for the user for your app." 47 | /// 48 | /// Unlike [`crate::current_entitlements`] this will also return unfinished Transactions. Otherwise the result is the same. 49 | /// 50 | /// Expected to be confirmed with event: [`IosIapEvents::AllTransactions`][crate::IosIapEvents::AllTransactions] 51 | /// 52 | /// See 53 | pub fn all_transactions(request: i64) { 54 | #[cfg(target_os = "ios")] 55 | native::ios_iap_transactions_all(request); 56 | } 57 | 58 | /// Quoted from Apple docs: "A sequence of the latest transactions that entitle a user to in-app purchases and subscriptions." 59 | /// 60 | /// Usually used for "RestorePurchases" functionality. 61 | /// Most importantly this will only included active subscriptions and non-consumables. 62 | /// Finished Transactions of Consumables will never appear again. 63 | /// 64 | /// Expected to be confirmed with event: [`IosIapEvents::CurrentEntitlements`][crate::IosIapEvents::CurrentEntitlements] 65 | /// 66 | /// See 67 | pub fn current_entitlements(request: i64) { 68 | #[cfg(target_os = "ios")] 69 | native::ios_iap_transactions_current_entitlements(request); 70 | } 71 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/native.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unnecessary_cast)] 2 | 3 | use std::sync::OnceLock; 4 | 5 | use bevy_crossbeam_event::CrossbeamEventSender; 6 | 7 | #[allow(unused_imports)] 8 | pub use ffi::*; 9 | 10 | use crate::{ 11 | IosIapCurrency, IosIapEnvironment, IosIapProduct, IosIapProductType, IosIapProductsResponse, 12 | IosIapPurchaseError, IosIapPurchaseResponse, IosIapRevocationReason, IosIapStoreKitError, 13 | IosIapStorefront, IosIapSubscriptionInfo, IosIapSubscriptionPeriod, 14 | IosIapSubscriptionPeriodUnit, IosIapSubscriptionRenewalState, IosIapSubscriptionStatus, 15 | IosIapTransactionFinishResponse, IosIapTransactionReason, IosIapTransactionResponse, 16 | plugin::{IosIapEvents, IosIapResponse}, 17 | transaction::IosIapTransaction, 18 | }; 19 | 20 | #[swift_bridge::bridge] 21 | mod ffi { 22 | 23 | extern "Rust" { 24 | type IosIapProduct; 25 | type IosIapProductType; 26 | type IosIapPurchaseResponse; 27 | type IosIapPurchaseError; 28 | type IosIapStoreKitError; 29 | type IosIapTransaction; 30 | type IosIapTransactionReason; 31 | type IosIapEnvironment; 32 | type IosIapStorefront; 33 | type IosIapSubscriptionInfo; 34 | type IosIapSubscriptionPeriod; 35 | type IosIapSubscriptionPeriodUnit; 36 | type IosIapSubscriptionStatus; 37 | type IosIapSubscriptionRenewalState; 38 | type IosIapCurrency; 39 | type IosIapRevocationReason; 40 | type IosIapProductsResponse; 41 | type IosIapTransactionResponse; 42 | 43 | #[swift_bridge(associated_to = IosIapProduct)] 44 | fn new( 45 | id: String, 46 | display_price: String, 47 | display_name: String, 48 | description: String, 49 | price: f64, 50 | product_type: IosIapProductType, 51 | ) -> IosIapProduct; 52 | #[swift_bridge(associated_to = IosIapProduct)] 53 | fn subscription(t: &mut IosIapProduct, info: IosIapSubscriptionInfo); 54 | 55 | #[swift_bridge(associated_to = IosIapProductType)] 56 | fn new_consumable(non: bool) -> IosIapProductType; 57 | #[swift_bridge(associated_to = IosIapProductType)] 58 | fn new_non_renewable() -> IosIapProductType; 59 | #[swift_bridge(associated_to = IosIapProductType)] 60 | fn new_auto_renewable() -> IosIapProductType; 61 | 62 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 63 | fn success(t: IosIapTransaction) -> IosIapPurchaseResponse; 64 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 65 | fn canceled(id: String) -> IosIapPurchaseResponse; 66 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 67 | fn pending(id: String) -> IosIapPurchaseResponse; 68 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 69 | fn unknown(id: String) -> IosIapPurchaseResponse; 70 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 71 | fn error(e: String) -> IosIapPurchaseResponse; 72 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 73 | fn purchase_error( 74 | error: IosIapPurchaseError, 75 | localized_description: String, 76 | ) -> IosIapPurchaseResponse; 77 | #[swift_bridge(associated_to = IosIapPurchaseResponse)] 78 | fn storekit_error( 79 | error: IosIapStoreKitError, 80 | localized_description: String, 81 | ) -> IosIapPurchaseResponse; 82 | 83 | #[swift_bridge(associated_to = IosIapPurchaseError)] 84 | fn invalid_quantity() -> IosIapPurchaseError; 85 | #[swift_bridge(associated_to = IosIapPurchaseError)] 86 | fn product_unavailable() -> IosIapPurchaseError; 87 | #[swift_bridge(associated_to = IosIapPurchaseError)] 88 | fn purchase_not_allowed() -> IosIapPurchaseError; 89 | #[swift_bridge(associated_to = IosIapPurchaseError)] 90 | fn ineligible_for_offer() -> IosIapPurchaseError; 91 | #[swift_bridge(associated_to = IosIapPurchaseError)] 92 | fn invalid_offer_identifier() -> IosIapPurchaseError; 93 | #[swift_bridge(associated_to = IosIapPurchaseError)] 94 | fn invalid_offer_price() -> IosIapPurchaseError; 95 | #[swift_bridge(associated_to = IosIapPurchaseError)] 96 | fn invalid_offer_signature() -> IosIapPurchaseError; 97 | #[swift_bridge(associated_to = IosIapPurchaseError)] 98 | fn missing_offer_parameters() -> IosIapPurchaseError; 99 | 100 | #[swift_bridge(associated_to = IosIapStoreKitError)] 101 | fn unknown() -> IosIapStoreKitError; 102 | #[swift_bridge(associated_to = IosIapStoreKitError)] 103 | fn user_cancelled() -> IosIapStoreKitError; 104 | #[swift_bridge(associated_to = IosIapStoreKitError)] 105 | fn network_error(e: String) -> IosIapStoreKitError; 106 | #[swift_bridge(associated_to = IosIapStoreKitError)] 107 | fn system_error(e: String) -> IosIapStoreKitError; 108 | #[swift_bridge(associated_to = IosIapStoreKitError)] 109 | fn not_available_in_storefront() -> IosIapStoreKitError; 110 | #[swift_bridge(associated_to = IosIapStoreKitError)] 111 | fn not_entitled() -> IosIapStoreKitError; 112 | 113 | #[swift_bridge(associated_to = IosIapEnvironment)] 114 | fn sandbox() -> IosIapEnvironment; 115 | #[swift_bridge(associated_to = IosIapEnvironment)] 116 | fn production() -> IosIapEnvironment; 117 | #[swift_bridge(associated_to = IosIapEnvironment)] 118 | fn xcode() -> IosIapEnvironment; 119 | 120 | #[swift_bridge(associated_to = IosIapStorefront)] 121 | fn storefront(id: String, country_code: String) -> IosIapStorefront; 122 | 123 | #[swift_bridge(associated_to = IosIapTransaction)] 124 | fn new_transaction( 125 | id: u64, 126 | product_id: String, 127 | app_bundle_id: String, 128 | purchase_date: u64, 129 | original_purchase_date: u64, 130 | purchased_quantity: i32, 131 | storefront_country_code: String, 132 | signed_date: u64, 133 | is_upgraded: bool, 134 | original_id: u64, 135 | json_representation: String, 136 | product_type: IosIapProductType, 137 | environment: IosIapEnvironment, 138 | ) -> IosIapTransaction; 139 | #[swift_bridge(associated_to = IosIapTransaction)] 140 | fn add_storefront(t: &mut IosIapTransaction, store: IosIapStorefront); 141 | #[swift_bridge(associated_to = IosIapTransaction)] 142 | fn add_reason(t: &mut IosIapTransaction, reason: IosIapTransactionReason); 143 | #[swift_bridge(associated_to = IosIapTransaction)] 144 | fn add_revocation(t: &mut IosIapTransaction, date: u64); 145 | #[swift_bridge(associated_to = IosIapTransaction)] 146 | fn add_expiration(t: &mut IosIapTransaction, date: u64); 147 | #[swift_bridge(associated_to = IosIapTransaction)] 148 | fn add_currency(t: &mut IosIapTransaction, currency: IosIapCurrency); 149 | #[swift_bridge(associated_to = IosIapTransaction)] 150 | fn revocation_reason(t: &mut IosIapTransaction, reason: IosIapRevocationReason); 151 | #[swift_bridge(associated_to = IosIapTransaction)] 152 | fn web_order_line_item_id(t: &mut IosIapTransaction, id: String); 153 | #[swift_bridge(associated_to = IosIapTransaction)] 154 | fn subscription_group_id(t: &mut IosIapTransaction, id: String); 155 | #[swift_bridge(associated_to = IosIapTransaction)] 156 | fn app_account_token(t: &mut IosIapTransaction, uuid: String); 157 | 158 | #[swift_bridge(associated_to = IosIapTransactionReason)] 159 | fn renewal() -> IosIapTransactionReason; 160 | #[swift_bridge(associated_to = IosIapTransactionReason)] 161 | fn purchase() -> IosIapTransactionReason; 162 | 163 | type IosIapTransactionFinishResponse; 164 | #[swift_bridge(associated_to = IosIapTransactionFinishResponse)] 165 | fn finished(t: IosIapTransaction) -> IosIapTransactionFinishResponse; 166 | #[swift_bridge(associated_to = IosIapTransactionFinishResponse)] 167 | fn error(e: String) -> IosIapTransactionFinishResponse; 168 | #[swift_bridge(associated_to = IosIapTransactionFinishResponse)] 169 | fn unknown(id: u64) -> IosIapTransactionFinishResponse; 170 | 171 | #[swift_bridge(associated_to = IosIapSubscriptionInfo)] 172 | fn new( 173 | group_id: String, 174 | period: IosIapSubscriptionPeriod, 175 | is_eligible_for_intro_offer: bool, 176 | state: Vec, 177 | ) -> IosIapSubscriptionInfo; 178 | 179 | #[swift_bridge(associated_to = IosIapSubscriptionPeriod)] 180 | fn new(unit: IosIapSubscriptionPeriodUnit, value: i32) -> IosIapSubscriptionPeriod; 181 | 182 | #[swift_bridge(associated_to = IosIapSubscriptionPeriodUnit)] 183 | fn day() -> IosIapSubscriptionPeriodUnit; 184 | #[swift_bridge(associated_to = IosIapSubscriptionPeriodUnit)] 185 | fn week() -> IosIapSubscriptionPeriodUnit; 186 | #[swift_bridge(associated_to = IosIapSubscriptionPeriodUnit)] 187 | fn month() -> IosIapSubscriptionPeriodUnit; 188 | #[swift_bridge(associated_to = IosIapSubscriptionPeriodUnit)] 189 | fn year() -> IosIapSubscriptionPeriodUnit; 190 | 191 | #[swift_bridge(associated_to = IosIapSubscriptionRenewalState)] 192 | fn subscribed() -> IosIapSubscriptionRenewalState; 193 | #[swift_bridge(associated_to = IosIapSubscriptionRenewalState)] 194 | fn expired() -> IosIapSubscriptionRenewalState; 195 | #[swift_bridge(associated_to = IosIapSubscriptionRenewalState)] 196 | fn in_billing_retry_period() -> IosIapSubscriptionRenewalState; 197 | #[swift_bridge(associated_to = IosIapSubscriptionRenewalState)] 198 | fn in_grace_period() -> IosIapSubscriptionRenewalState; 199 | #[swift_bridge(associated_to = IosIapSubscriptionRenewalState)] 200 | fn revoked() -> IosIapSubscriptionRenewalState; 201 | 202 | #[swift_bridge(associated_to = IosIapSubscriptionStatus)] 203 | fn new( 204 | state: IosIapSubscriptionRenewalState, 205 | transaction: IosIapTransaction, 206 | ) -> IosIapSubscriptionStatus; 207 | 208 | #[swift_bridge(associated_to = IosIapCurrency)] 209 | fn new(identifier: String, is_iso_currency: bool) -> IosIapCurrency; 210 | 211 | #[swift_bridge(associated_to = IosIapRevocationReason)] 212 | fn developer_issue() -> IosIapRevocationReason; 213 | #[swift_bridge(associated_to = IosIapRevocationReason)] 214 | fn other() -> IosIapRevocationReason; 215 | 216 | #[swift_bridge(associated_to = IosIapProductsResponse)] 217 | fn done(items: Vec) -> IosIapProductsResponse; 218 | #[swift_bridge(associated_to = IosIapProductsResponse)] 219 | fn error(error: String) -> IosIapProductsResponse; 220 | 221 | #[swift_bridge(associated_to = IosIapTransactionResponse)] 222 | fn done(items: Vec) -> IosIapTransactionResponse; 223 | #[swift_bridge(associated_to = IosIapTransactionResponse)] 224 | fn error(error: String) -> IosIapTransactionResponse; 225 | 226 | // 227 | 228 | fn products_received(request: i64, response: IosIapProductsResponse); 229 | fn all_transactions(request: i64, response: IosIapTransactionResponse); 230 | fn current_entitlements(request: i64, response: IosIapTransactionResponse); 231 | fn purchase_processed(request: i64, result: IosIapPurchaseResponse); 232 | fn transaction_update(t: IosIapTransaction); 233 | fn transaction_finished(request: i64, t: IosIapTransactionFinishResponse); 234 | } 235 | 236 | extern "Swift" { 237 | pub fn ios_iap_init(); 238 | pub fn ios_iap_products(request: i64, products: Vec); 239 | pub fn ios_iap_purchase(request: i64, id: String); 240 | pub fn ios_iap_transactions_all(request: i64); 241 | pub fn ios_iap_transactions_current_entitlements(request: i64); 242 | pub fn ios_iap_transaction_finish(request: i64, transaction_id: u64); 243 | } 244 | } 245 | 246 | static SENDER_EVENTS: OnceLock>> = OnceLock::new(); 247 | static SENDER_RESPONSE: OnceLock>> = OnceLock::new(); 248 | 249 | #[allow(dead_code)] 250 | pub fn set_sender_events(sender: CrossbeamEventSender) { 251 | while SENDER_EVENTS.set(Some(sender.clone())).is_err() {} 252 | } 253 | 254 | #[allow(dead_code)] 255 | pub fn set_sender_response(sender: CrossbeamEventSender) { 256 | while SENDER_RESPONSE.set(Some(sender.clone())).is_err() {} 257 | } 258 | 259 | fn transaction_update(t: IosIapTransaction) { 260 | SENDER_EVENTS 261 | .get() 262 | .unwrap() 263 | .as_ref() 264 | .unwrap() 265 | .send(IosIapEvents::TransactionUpdate(t)); 266 | } 267 | 268 | fn all_transactions(request: i64, response: IosIapTransactionResponse) { 269 | SENDER_RESPONSE 270 | .get() 271 | .unwrap() 272 | .as_ref() 273 | .unwrap() 274 | .send(IosIapResponse::AllTransactions((request, response))); 275 | } 276 | 277 | fn current_entitlements(request: i64, response: IosIapTransactionResponse) { 278 | SENDER_RESPONSE 279 | .get() 280 | .unwrap() 281 | .as_ref() 282 | .unwrap() 283 | .send(IosIapResponse::CurrentEntitlements((request, response))); 284 | } 285 | 286 | fn transaction_finished(request: i64, response: IosIapTransactionFinishResponse) { 287 | SENDER_RESPONSE 288 | .get() 289 | .unwrap() 290 | .as_ref() 291 | .unwrap() 292 | .send(IosIapResponse::TransactionFinished((request, response))); 293 | } 294 | 295 | fn products_received(request: i64, response: IosIapProductsResponse) { 296 | SENDER_RESPONSE 297 | .get() 298 | .unwrap() 299 | .as_ref() 300 | .unwrap() 301 | .send(IosIapResponse::Products((request, response))); 302 | } 303 | 304 | fn purchase_processed(request: i64, result: IosIapPurchaseResponse) { 305 | // bevy_log::info!("purchase_processed: {:?}", result as u8); 306 | 307 | SENDER_RESPONSE 308 | .get() 309 | .unwrap() 310 | .as_ref() 311 | .unwrap() 312 | .send(IosIapResponse::Purchase((request, result))); 313 | } 314 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/plugin.rs: -------------------------------------------------------------------------------- 1 | use bevy_app::prelude::*; 2 | use bevy_ecs::prelude::*; 3 | 4 | use crate::transaction::IosIapTransaction; 5 | use crate::{ 6 | IosIapProductsResponse, IosIapPurchaseResponse, IosIapTransactionFinishResponse, 7 | IosIapTransactionResponse, 8 | }; 9 | 10 | /// All possible responses for communication from the native iOS (Swift) side to Rust/Bevy as a reaction to a method call / request. 11 | #[derive(Event, Clone, Debug)] 12 | pub enum IosIapResponse { 13 | /// Triggered by calls to [`get_products`][crate::get_products] 14 | Products((i64, IosIapProductsResponse)), 15 | /// Triggered by calls to [`purchase`][crate::purchase] 16 | Purchase((i64, IosIapPurchaseResponse)), 17 | /// Triggered in response to calls to [`finish_transaction`][crate::finish_transaction] 18 | TransactionFinished((i64, IosIapTransactionFinishResponse)), 19 | /// Triggered in response to calls to [`all_transactions`][crate::all_transactions] 20 | AllTransactions((i64, IosIapTransactionResponse)), 21 | /// Triggered in response to calls to [`current_entitlements`][crate::current_entitlements] 22 | CurrentEntitlements((i64, IosIapTransactionResponse)), 23 | } 24 | 25 | /// Events for pro-active communication from native iOS (Swift) side to Rust/Bevy that are not a direct response to a request. 26 | #[non_exhaustive] 27 | #[derive(Event, Clone, Debug)] 28 | pub enum IosIapEvents { 29 | /// Triggered automatically by TransactionObserver registered by [`init`][crate::init] 30 | /// for every update on any Transaction while the app is running. 31 | TransactionUpdate(IosIapTransaction), 32 | } 33 | 34 | /// Bevy plugin to integrate access to iOS StoreKit2 35 | #[allow(dead_code)] 36 | pub struct IosIapPlugin { 37 | auto_init: bool, 38 | } 39 | 40 | impl IosIapPlugin { 41 | /// create plugin and define whether it will call [`init`][`crate::init`] automatically right on startup. 42 | pub fn new(auto_init: bool) -> Self { 43 | Self { auto_init } 44 | } 45 | } 46 | 47 | impl Plugin for IosIapPlugin { 48 | fn build(&self, app: &mut App) { 49 | app.add_plugins(crate::request::plugin); 50 | 51 | #[cfg(not(target_os = "ios"))] 52 | { 53 | app.add_event::(); 54 | app.add_event::(); 55 | } 56 | 57 | #[cfg(target_os = "ios")] 58 | { 59 | use bevy_crossbeam_event::{CrossbeamEventApp, CrossbeamEventSender}; 60 | 61 | app.add_crossbeam_event::(); 62 | 63 | let sender = app 64 | .world() 65 | .get_resource::>() 66 | .unwrap() 67 | .clone(); 68 | 69 | crate::native::set_sender_events(sender); 70 | 71 | app.add_crossbeam_event::(); 72 | 73 | let sender = app 74 | .world() 75 | .get_resource::>() 76 | .unwrap() 77 | .clone(); 78 | 79 | crate::native::set_sender_response(sender); 80 | 81 | if self.auto_init { 82 | crate::native::ios_iap_init(); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/request.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use bevy_app::{App, PreUpdate}; 4 | use bevy_ecs::{ 5 | prelude::*, 6 | system::{EntityCommands, IntoObserverSystem, SystemParam}, 7 | }; 8 | 9 | use crate::{ 10 | IosIapProductsResponse, IosIapPurchaseResponse, IosIapTransactionFinishResponse, 11 | IosIapTransactionResponse, plugin::IosIapResponse, 12 | }; 13 | 14 | #[derive(Event, Debug)] 15 | pub struct CurrentEntitlements(pub IosIapTransactionResponse); 16 | 17 | #[derive(Event, Debug)] 18 | pub struct Products(pub IosIapProductsResponse); 19 | 20 | #[derive(Event, Debug)] 21 | pub struct Purchase(pub IosIapPurchaseResponse); 22 | 23 | #[derive(Event, Debug)] 24 | pub struct FinishTransaction(pub IosIapTransactionFinishResponse); 25 | 26 | #[derive(Event, Debug)] 27 | pub struct AllTransactions(pub IosIapTransactionResponse); 28 | 29 | #[derive(Resource, Default)] 30 | struct BevyIosIapSate { 31 | request_id: i64, 32 | } 33 | 34 | #[derive(Component)] 35 | #[component(storage = "SparseSet")] 36 | struct RequestCurrentEntitlements; 37 | 38 | #[derive(Component)] 39 | #[component(storage = "SparseSet")] 40 | struct RequestProducts; 41 | 42 | #[derive(Component)] 43 | #[component(storage = "SparseSet")] 44 | struct RequestPurchase; 45 | 46 | #[derive(Component)] 47 | #[component(storage = "SparseSet")] 48 | struct RequestFinishTransaction; 49 | 50 | #[derive(Component)] 51 | #[component(storage = "SparseSet")] 52 | struct RequestAllTransactions; 53 | 54 | #[derive(Component)] 55 | struct RequestId(i64); 56 | 57 | #[derive(Component)] 58 | struct RequestEntity; 59 | 60 | #[derive(SystemParam)] 61 | pub struct BevyIosIap<'w, 's> { 62 | commands: Commands<'w, 's>, 63 | res: ResMut<'w, BevyIosIapSate>, 64 | } 65 | 66 | impl BevyIosIap<'_, '_> { 67 | pub fn current_entitlements(&mut self) -> BevyIosIapRequestBuilder<'_, CurrentEntitlements> { 68 | let id = self.res.request_id; 69 | self.res.request_id += 1; 70 | crate::methods::current_entitlements(id); 71 | BevyIosIapRequestBuilder::new(self.commands.spawn(( 72 | RequestCurrentEntitlements, 73 | RequestId(id), 74 | RequestEntity, 75 | ))) 76 | } 77 | 78 | pub fn products(&mut self, products: Vec) -> BevyIosIapRequestBuilder<'_, Products> { 79 | let id = self.res.request_id; 80 | self.res.request_id += 1; 81 | crate::methods::get_products(id, products); 82 | BevyIosIapRequestBuilder::new(self.commands.spawn(( 83 | RequestProducts, 84 | RequestId(id), 85 | RequestEntity, 86 | ))) 87 | } 88 | 89 | pub fn purchase(&mut self, product_id: String) -> BevyIosIapRequestBuilder<'_, Purchase> { 90 | let id = self.res.request_id; 91 | self.res.request_id += 1; 92 | crate::methods::purchase(id, product_id); 93 | BevyIosIapRequestBuilder::new(self.commands.spawn(( 94 | RequestPurchase, 95 | RequestId(id), 96 | RequestEntity, 97 | ))) 98 | } 99 | 100 | pub fn finish_transaction( 101 | &mut self, 102 | transaction_id: u64, 103 | ) -> BevyIosIapRequestBuilder<'_, FinishTransaction> { 104 | let id = self.res.request_id; 105 | self.res.request_id += 1; 106 | crate::methods::finish_transaction(id, transaction_id); 107 | BevyIosIapRequestBuilder::new(self.commands.spawn(( 108 | RequestFinishTransaction, 109 | RequestId(id), 110 | RequestEntity, 111 | ))) 112 | } 113 | 114 | pub fn all_transactions(&mut self) -> BevyIosIapRequestBuilder<'_, AllTransactions> { 115 | let id = self.res.request_id; 116 | self.res.request_id += 1; 117 | crate::methods::all_transactions(id); 118 | BevyIosIapRequestBuilder::new(self.commands.spawn(( 119 | RequestAllTransactions, 120 | RequestId(id), 121 | RequestEntity, 122 | ))) 123 | } 124 | } 125 | 126 | pub struct BevyIosIapRequestBuilder<'a, T>(EntityCommands<'a>, PhantomData); 127 | 128 | impl<'a, T> BevyIosIapRequestBuilder<'a, T> 129 | where 130 | T: 'static + Event, 131 | { 132 | fn new(ec: EntityCommands<'a>) -> Self { 133 | Self(ec, PhantomData) 134 | } 135 | 136 | pub fn on_response>( 137 | &mut self, 138 | on_response: OR, 139 | ) -> &mut Self { 140 | self.0.observe(on_response); 141 | self 142 | } 143 | } 144 | 145 | #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] 146 | pub struct BevyIosIapSet; 147 | 148 | pub fn plugin(app: &mut App) { 149 | app.init_resource::(); 150 | app.add_systems( 151 | PreUpdate, 152 | ( 153 | cleanup_finished_requests, 154 | process_events.run_if(on_event::), 155 | ) 156 | .chain() 157 | .in_set(BevyIosIapSet), 158 | ); 159 | } 160 | 161 | fn cleanup_finished_requests( 162 | mut commands: Commands, 163 | query: Query, Without)>, 164 | ) { 165 | for e in query.iter() { 166 | if let Ok(mut ec) = commands.get_entity(e) { 167 | ec.despawn(); 168 | } 169 | } 170 | } 171 | 172 | #[allow(unused_variables, unused_mut)] 173 | fn process_events( 174 | mut events: EventReader, 175 | mut commands: Commands, 176 | query_current_entitlements: Query<(Entity, &RequestId), With>, 177 | query_products: Query<(Entity, &RequestId), With>, 178 | query_purchases: Query<(Entity, &RequestId), With>, 179 | ) { 180 | for e in events.read() { 181 | match e { 182 | IosIapResponse::CurrentEntitlements((r, response)) => { 183 | for (e, id) in &query_current_entitlements { 184 | if id.0 == *r { 185 | commands.trigger_targets(CurrentEntitlements(response.clone()), e); 186 | if let Ok(mut ec) = commands.get_entity(e) { 187 | ec.remove::(); 188 | } 189 | break; 190 | } 191 | } 192 | } 193 | IosIapResponse::Products((r, response)) => { 194 | for (e, id) in &query_products { 195 | if id.0 == *r { 196 | commands.trigger_targets(Products(response.clone()), e); 197 | if let Ok(mut ec) = commands.get_entity(e) { 198 | ec.remove::(); 199 | } 200 | break; 201 | } 202 | } 203 | } 204 | IosIapResponse::Purchase((r, response)) => { 205 | for (e, id) in &query_purchases { 206 | if id.0 == *r { 207 | commands.trigger_targets(Purchase(response.clone()), e); 208 | if let Ok(mut ec) = commands.get_entity(e) { 209 | ec.remove::(); 210 | } 211 | break; 212 | } 213 | } 214 | } 215 | IosIapResponse::TransactionFinished((r, response)) => { 216 | for (e, id) in &query_purchases { 217 | if id.0 == *r { 218 | commands.trigger_targets(FinishTransaction(response.clone()), e); 219 | if let Ok(mut ec) = commands.get_entity(e) { 220 | ec.remove::(); 221 | } 222 | break; 223 | } 224 | } 225 | } 226 | IosIapResponse::AllTransactions((r, response)) => { 227 | for (e, id) in &query_purchases { 228 | if id.0 == *r { 229 | commands.trigger_targets(AllTransactions(response.clone()), e); 230 | if let Ok(mut ec) = commands.get_entity(e) { 231 | ec.remove::(); 232 | } 233 | break; 234 | } 235 | } 236 | } 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/response.rs: -------------------------------------------------------------------------------- 1 | use crate::{IosIapProduct, IosIapTransaction}; 2 | 3 | /// Expected event data in response to [`get_products`] method call. 4 | /// 5 | /// See Event [`IosIapEvents`] 6 | #[derive(Debug, Clone)] 7 | pub enum IosIapProductsResponse { 8 | Done(Vec), 9 | Error(String), 10 | } 11 | 12 | impl IosIapProductsResponse { 13 | pub(crate) fn done(items: Vec) -> Self { 14 | Self::Done(items) 15 | } 16 | pub(crate) fn error(e: String) -> Self { 17 | Self::Error(e) 18 | } 19 | } 20 | 21 | /// Expected event data in response to [`current_entitlements`] or [`all_transactions`] method call. 22 | /// 23 | /// See Event [`IosIapEvents`] 24 | #[derive(Debug, Clone)] 25 | pub enum IosIapTransactionResponse { 26 | Done(Vec), 27 | Error(String), 28 | } 29 | 30 | impl IosIapTransactionResponse { 31 | pub(crate) fn done(items: Vec) -> Self { 32 | Self::Done(items) 33 | } 34 | pub(crate) fn error(e: String) -> Self { 35 | Self::Error(e) 36 | } 37 | } 38 | 39 | /// Expected event data in response to [`finish_transaction`] method call. 40 | /// 41 | /// See Event [`IosIapEvents`] 42 | #[derive(Debug, Clone)] 43 | #[allow(clippy::large_enum_variant)] 44 | pub enum IosIapTransactionFinishResponse { 45 | /// Unknown Unfinished Transaction, maybe a concurrent process to finish it in the meantime? 46 | UnknownTransaction(u64), 47 | /// Transaction successfully finished 48 | Finished(IosIapTransaction), 49 | /// Some error occured 50 | Error(String), 51 | } 52 | 53 | impl IosIapTransactionFinishResponse { 54 | pub(crate) fn unknown(id: u64) -> Self { 55 | Self::UnknownTransaction(id) 56 | } 57 | 58 | pub(crate) fn finished(t: IosIapTransaction) -> Self { 59 | Self::Finished(t) 60 | } 61 | pub(crate) fn error(e: String) -> Self { 62 | Self::Error(e) 63 | } 64 | } 65 | 66 | /// Expected event data in response to [`purchase`] method call. 67 | /// 68 | /// See Event [`IosIapEvents`] 69 | #[derive(Debug, Clone)] 70 | #[allow(clippy::large_enum_variant)] 71 | pub enum IosIapPurchaseResponse { 72 | /// Purchase successful 73 | Success(IosIapTransaction), 74 | /// User canceled the purchase 75 | Canceled(String), 76 | /// The purchase is pending, and requires action from the customer. If the transaction completes, 77 | /// it's available through the TransactionObserver registered via [`init`] and lead to [`IosIapEvents::Transaction`] calls. 78 | Pending(String), 79 | /// Unknown / invalid product ID was used to trigger purchase 80 | Unknown(String), 81 | /// Generic error 82 | Error(String), 83 | /// Purchase error 84 | PurchaseError { 85 | error: IosIapPurchaseError, 86 | localized_description: String, 87 | }, 88 | /// store kit error 89 | StoreKitError { 90 | error: IosIapStoreKitError, 91 | localized_description: String, 92 | }, 93 | } 94 | 95 | impl IosIapPurchaseResponse { 96 | pub(crate) fn success(t: IosIapTransaction) -> Self { 97 | Self::Success(t) 98 | } 99 | 100 | pub(crate) fn canceled(id: String) -> Self { 101 | Self::Canceled(id) 102 | } 103 | 104 | pub(crate) fn pending(id: String) -> Self { 105 | Self::Pending(id) 106 | } 107 | 108 | pub(crate) fn unknown(id: String) -> Self { 109 | Self::Unknown(id) 110 | } 111 | 112 | pub(crate) fn error(e: String) -> Self { 113 | Self::Error(e) 114 | } 115 | 116 | pub(crate) fn purchase_error( 117 | error: IosIapPurchaseError, 118 | localized_description: String, 119 | ) -> Self { 120 | Self::PurchaseError { 121 | error, 122 | localized_description, 123 | } 124 | } 125 | 126 | pub(crate) fn storekit_error( 127 | error: IosIapStoreKitError, 128 | localized_description: String, 129 | ) -> Self { 130 | Self::StoreKitError { 131 | error, 132 | localized_description, 133 | } 134 | } 135 | } 136 | 137 | /// Used in [`IosIapPurchaseResponse`] 138 | /// 139 | /// See 140 | #[derive(Debug, Clone, Copy)] 141 | pub enum IosIapPurchaseError { 142 | InvalidQuantity, 143 | ProductUnavailable, 144 | PurchaseNotAllowed, 145 | IneligibleForOffer, 146 | InvalidOfferIdentifier, 147 | InvalidOfferPrice, 148 | InvalidOfferSignature, 149 | MissingOfferParameters, 150 | } 151 | 152 | impl IosIapPurchaseError { 153 | pub fn invalid_quantity() -> Self { 154 | Self::InvalidQuantity 155 | } 156 | 157 | pub fn product_unavailable() -> Self { 158 | Self::ProductUnavailable 159 | } 160 | 161 | pub fn purchase_not_allowed() -> Self { 162 | Self::PurchaseNotAllowed 163 | } 164 | 165 | pub fn ineligible_for_offer() -> Self { 166 | Self::IneligibleForOffer 167 | } 168 | 169 | pub fn invalid_offer_identifier() -> Self { 170 | Self::InvalidOfferIdentifier 171 | } 172 | 173 | pub fn invalid_offer_price() -> Self { 174 | Self::InvalidOfferPrice 175 | } 176 | 177 | pub fn invalid_offer_signature() -> Self { 178 | Self::InvalidOfferSignature 179 | } 180 | 181 | pub fn missing_offer_parameters() -> Self { 182 | Self::MissingOfferParameters 183 | } 184 | } 185 | 186 | /// Used in [`IosIapPurchaseResponse`] 187 | /// 188 | /// See 189 | #[derive(Debug, Clone)] 190 | pub enum IosIapStoreKitError { 191 | Unknown, 192 | UserCancelled, 193 | NetworkError(String), 194 | SystemError(String), 195 | NotAvailableInStorefront, 196 | NotEntitled, 197 | } 198 | 199 | impl IosIapStoreKitError { 200 | pub fn unknown() -> Self { 201 | Self::Unknown 202 | } 203 | 204 | pub fn user_cancelled() -> Self { 205 | Self::UserCancelled 206 | } 207 | 208 | pub fn network_error(e: String) -> Self { 209 | Self::NetworkError(e) 210 | } 211 | 212 | pub fn system_error(e: String) -> Self { 213 | Self::SystemError(e) 214 | } 215 | 216 | pub fn not_available_in_storefront() -> Self { 217 | Self::NotAvailableInStorefront 218 | } 219 | 220 | pub fn not_entitled() -> Self { 221 | Self::NotEntitled 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /bevy_ios_iap/src/transaction.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | IosIapCurrency, IosIapEnvironment, IosIapProductType, IosIapRevocationReason, IosIapStorefront, 3 | IosIapTransactionReason, 4 | }; 5 | 6 | /// Marks an iOS 17 version dependant value. If it is set then the device supports minimum iOS 17. 7 | /// Not using `Option` here to be explicit about the cause for a missing value and to handle it with caution. 8 | #[derive(Debug, Clone, Copy)] 9 | pub enum Ios17Specific { 10 | /// The value is available on iOS 17.0 and later. 11 | Available(T), 12 | /// The value is not available on iOS 17.0 and later. 13 | NotAvailable, 14 | } 15 | 16 | /// Representation of a Transaction. 17 | /// Mirrors the Transcation type in Apple's StoreKit2 closely. 18 | /// See official docs for more details on the individual fields. 19 | /// 20 | /// See 21 | #[derive(Debug, Clone)] 22 | pub struct IosIapTransaction { 23 | pub id: u64, 24 | pub original_id: u64, 25 | pub product_id: String, 26 | pub app_bundle_id: String, 27 | pub purchase_date: u64, 28 | pub original_purchase_date: u64, 29 | pub revocation_date: Option, 30 | pub expiration_date: Option, 31 | pub purchased_quantity: i32, 32 | pub storefront_country_code: String, 33 | pub signed_date: u64, 34 | pub is_upgraded: bool, 35 | pub json_representation: String, 36 | pub product_type: IosIapProductType, 37 | pub storefront: Ios17Specific, 38 | pub reason: Ios17Specific, 39 | pub environment: IosIapEnvironment, 40 | pub currency: Option, 41 | pub revocation_reason: Option, 42 | /// representing a UUID 43 | pub app_account_token: Option, 44 | pub web_order_line_item_id: Option, 45 | pub subscription_group_id: Option, 46 | // 47 | // TODO: 48 | //pub deviceVerification 49 | //pub deviceVerificationNonce 50 | 51 | // TODO: support family sharing 52 | //pub ownershipType 53 | 54 | // TODO: offer support 55 | //pub offer 56 | //pub offerType 57 | //pub offerID 58 | } 59 | 60 | impl IosIapTransaction { 61 | #[allow(clippy::too_many_arguments)] 62 | pub fn new_transaction( 63 | id: u64, 64 | product_id: String, 65 | app_bundle_id: String, 66 | purchase_date: u64, 67 | original_purchase_date: u64, 68 | purchased_quantity: i32, 69 | storefront_country_code: String, 70 | signed_date: u64, 71 | is_upgraded: bool, 72 | original_id: u64, 73 | json_representation: String, 74 | product_type: IosIapProductType, 75 | environment: IosIapEnvironment, 76 | ) -> Self { 77 | Self { 78 | id, 79 | product_id, 80 | app_bundle_id, 81 | purchase_date, 82 | original_purchase_date, 83 | purchased_quantity, 84 | storefront_country_code, 85 | signed_date, 86 | app_account_token: None, 87 | json_representation, 88 | product_type, 89 | revocation_date: None, 90 | expiration_date: None, 91 | is_upgraded, 92 | environment, 93 | currency: None, 94 | original_id, 95 | revocation_reason: None, 96 | subscription_group_id: None, 97 | web_order_line_item_id: None, 98 | storefront: Ios17Specific::NotAvailable, 99 | reason: Ios17Specific::NotAvailable, 100 | } 101 | } 102 | 103 | pub fn add_storefront(t: &mut Self, store: IosIapStorefront) { 104 | t.storefront = Ios17Specific::Available(store); 105 | } 106 | 107 | pub fn add_reason(t: &mut Self, reason: IosIapTransactionReason) { 108 | t.reason = Ios17Specific::Available(reason); 109 | } 110 | 111 | pub fn add_revocation(t: &mut Self, date: u64) { 112 | t.revocation_date = Some(date); 113 | } 114 | 115 | pub fn add_expiration(t: &mut Self, date: u64) { 116 | t.expiration_date = Some(date); 117 | } 118 | 119 | pub fn add_currency(t: &mut Self, currency: IosIapCurrency) { 120 | t.currency = Some(currency); 121 | } 122 | 123 | pub fn revocation_reason(t: &mut Self, reason: IosIapRevocationReason) { 124 | t.revocation_reason = Some(reason); 125 | } 126 | 127 | pub fn web_order_line_item_id(t: &mut Self, id: String) { 128 | t.web_order_line_item_id = Some(id); 129 | } 130 | 131 | pub fn subscription_group_id(t: &mut Self, id: String) { 132 | t.subscription_group_id = Some(id); 133 | } 134 | 135 | pub fn app_account_token(t: &mut Self, uuid: String) { 136 | t.app_account_token = Some(uuid); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /bevy_ios_iap_egui/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## Unreleased 9 | 10 | ## [0.1.1] - 2024-01-10 11 | 12 | ### Changed 13 | * bevy_egui 0.32 upgrade 14 | -------------------------------------------------------------------------------- /bevy_ios_iap_egui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bevy_ios_iap_egui" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bevy_ios_iap = "0.7" 8 | bevy = { version = "0.16", default-features = false } 9 | bevy_egui = { version = "0.34", default-features = false } 10 | egui_extras = { version = "0.31" } 11 | -------------------------------------------------------------------------------- /bevy_ios_iap_egui/README.md: -------------------------------------------------------------------------------- 1 | # bevy_ios_iap_egui 2 | 3 | This helper crate is for interacting with the ios iap api from within your bevy app. It is using [egui](https://github.com/emilk/egui) for the ui. 4 | 5 | ![demo](../assets/demo.gif) 6 | 7 | > Demo from our game using this crate: [zoolitaire.com](https://zoolitaire.com) 8 | 9 | # Usage 10 | 11 | for now the crate is not published on crates, so it has to be used as a git dependency: 12 | 13 | ```toml 14 | bevy_ios_iap_egui = { git = "https://github.com/rustunit/bevy_ios_iap.git" } 15 | ``` 16 | 17 | add this to your code: 18 | 19 | ```rust 20 | // initialize the plugin with the product ids your app uses. 21 | app.add_plugins(IosIapEguiPlugin { 22 | products_ids: vec!["com.yourapp.product1".into()], 23 | }); 24 | 25 | // in your system you can toggle the ui with the following command: 26 | commands.trigger(IosIapEguiOpen::Toggle); 27 | ``` -------------------------------------------------------------------------------- /bevy_ios_iap_egui/justfile: -------------------------------------------------------------------------------- 1 | check: 2 | cargo c 3 | cargo c --target=aarch64-apple-ios 4 | cargo clippy 5 | cargo fmt -- --check 6 | -------------------------------------------------------------------------------- /bevy_ios_iap_egui/src/lib.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_egui::{egui, EguiContexts, EguiPlugin}; 3 | use bevy_ios_iap::{ 4 | IosIapEvents, IosIapProduct, IosIapProductsResponse, IosIapResponse, IosIapTransaction, 5 | IosIapTransactionResponse, 6 | }; 7 | use egui_extras::{Column, TableBuilder}; 8 | 9 | #[derive(Event)] 10 | pub enum IosIapEguiOpen { 11 | Toggle, 12 | Open, 13 | Close, 14 | } 15 | 16 | #[derive(Resource, Default)] 17 | struct DebugUiResource { 18 | open: bool, 19 | } 20 | 21 | #[derive(Resource, Default)] 22 | struct DebugIosIap { 23 | products_ids: Vec, 24 | iap_events: Vec, 25 | iap_products: Vec, 26 | iap_transactions: Vec, 27 | } 28 | 29 | pub struct IosIapEguiPlugin { 30 | pub products_ids: Vec, 31 | } 32 | 33 | impl Plugin for IosIapEguiPlugin { 34 | fn build(&self, app: &mut App) { 35 | if !app.is_plugin_added::() { 36 | app.add_plugins(EguiPlugin { 37 | enable_multipass_for_primary_context: false, 38 | }); 39 | } 40 | 41 | app.init_resource::(); 42 | app.init_resource::(); 43 | 44 | app.insert_resource(DebugIosIap { 45 | products_ids: self.products_ids.clone(), 46 | ..default() 47 | }); 48 | 49 | app.add_systems(Update, update); 50 | app.add_systems( 51 | Update, 52 | process_iap_responses.run_if(on_event::), 53 | ); 54 | app.add_systems(Update, process_iap_events.run_if(on_event::)); 55 | 56 | app.add_observer(on_toggle); 57 | } 58 | } 59 | 60 | fn on_toggle(trigger: Trigger, mut res: ResMut) { 61 | match trigger.event() { 62 | IosIapEguiOpen::Toggle => res.open = !res.open, 63 | IosIapEguiOpen::Open => res.open = true, 64 | IosIapEguiOpen::Close => res.open = false, 65 | } 66 | } 67 | 68 | fn process_iap_responses(mut events: EventReader, mut res: ResMut) { 69 | for e in events.read() { 70 | match e { 71 | IosIapResponse::Products((_r, IosIapProductsResponse::Done(products))) => { 72 | res.iap_events.push(format!("Products: {}", products.len())); 73 | res.iap_products.clone_from(products); 74 | } 75 | IosIapResponse::AllTransactions((_r, IosIapTransactionResponse::Done(t))) => { 76 | res.iap_events 77 | .push(format!("All Transactions: {}", t.len())); 78 | res.iap_transactions.clone_from(t); 79 | } 80 | IosIapResponse::CurrentEntitlements((r, IosIapTransactionResponse::Done(t))) => { 81 | res.iap_events 82 | .push(format!("Current Entitlements: {} [{r}]", t.len())); 83 | res.iap_transactions.clone_from(t); 84 | } 85 | IosIapResponse::TransactionFinished((_r, t)) => match t { 86 | bevy_ios_iap::IosIapTransactionFinishResponse::Finished(t) => { 87 | res.iap_events.push(format!( 88 | "TransactionFinished: {} '{:?}'", 89 | t.id, t.product_id 90 | )); 91 | } 92 | _ => { 93 | res.iap_events.push(format!("TransactionFinished: {:?}", t)); 94 | } 95 | }, 96 | IosIapResponse::Purchase((_r, t)) => match t { 97 | bevy_ios_iap::IosIapPurchaseResponse::Success(t) => { 98 | res.iap_events 99 | .push(format!("Purchase({},'{:?}')", t.id, t.product_id)); 100 | } 101 | _ => { 102 | res.iap_events.push(format!("{:?}", t)); 103 | } 104 | }, 105 | _ => res.iap_events.push(format!("{:?}", e)), 106 | } 107 | } 108 | } 109 | 110 | fn process_iap_events(mut events: EventReader, mut res: ResMut) { 111 | for e in events.read() { 112 | match e { 113 | IosIapEvents::TransactionUpdate(t) => { 114 | res.iap_events 115 | .push(format!("Transaction: [{}] {}", t.id, t.product_id)); 116 | } 117 | _ => res.iap_events.push(format!("{:?}", e)), 118 | } 119 | } 120 | } 121 | 122 | fn update( 123 | mut contexts: EguiContexts, 124 | mut res: ResMut, 125 | mut res_iap: ResMut, 126 | ) { 127 | let mut open_state = res.open; 128 | let Some(ctx) = contexts.try_ctx_mut() else { 129 | return; 130 | }; 131 | 132 | egui::Window::new("bevy_ios_iap") 133 | .open(&mut open_state) 134 | .show(ctx, |ui| { 135 | ios_iap_ui(ui, &mut res_iap); 136 | }); 137 | 138 | res.open = open_state; 139 | } 140 | 141 | fn ios_iap_ui(ui: &mut egui::Ui, res: &mut ResMut) { 142 | ui.collapsing("products", |ui| { 143 | ui.label(format!("count: {}", res.iap_products.len())); 144 | 145 | if ui.button("get products").clicked() { 146 | bevy_ios_iap::get_products(-1, res.products_ids.clone()); 147 | } 148 | 149 | if ui.button("buy invalid product id").clicked() { 150 | bevy_ios_iap::purchase(-1, "invalid.id".into()); 151 | } 152 | 153 | TableBuilder::new(ui) 154 | .column(Column::auto()) 155 | .column(Column::initial(200.).resizable(true)) 156 | .column(Column::remainder()) 157 | .header(20.0, |mut header| { 158 | header.col(|ui| { 159 | ui.heading("buy"); 160 | }); 161 | header.col(|ui| { 162 | ui.heading("id"); 163 | }); 164 | header.col(|ui| { 165 | ui.heading("$"); 166 | }); 167 | }) 168 | .body(|mut body| { 169 | for p in &res.iap_products { 170 | body.row(30.0, |mut row| { 171 | row.col(|ui| { 172 | if ui.button("buy").clicked() { 173 | bevy_ios_iap::purchase(-1, p.id.clone()); 174 | } 175 | }); 176 | row.col(|ui| { 177 | ui.label(p.id.clone()); 178 | }); 179 | row.col(|ui| { 180 | ui.label(p.display_price.clone()); 181 | }); 182 | }); 183 | } 184 | }); 185 | }); 186 | 187 | ui.collapsing("transactions", |ui| { 188 | ui.label(format!("count: {}", res.iap_transactions.len())); 189 | 190 | if ui.button("fetch all").clicked() { 191 | bevy_ios_iap::all_transactions(-1); 192 | } 193 | 194 | if ui.button("fetch current").clicked() { 195 | bevy_ios_iap::current_entitlements(-1); 196 | } 197 | 198 | TableBuilder::new(ui) 199 | .column(Column::initial(15.)) 200 | .column(Column::auto()) 201 | .column(Column::initial(200.).resizable(true)) 202 | .column(Column::remainder()) 203 | .header(20.0, |mut header| { 204 | header.col(|ui| { 205 | ui.heading("id"); 206 | }); 207 | header.col(|ui| { 208 | ui.heading("reason (iOS 17+)"); 209 | }); 210 | header.col(|ui| { 211 | ui.heading("product"); 212 | }); 213 | header.col(|ui| { 214 | ui.heading("date"); 215 | }); 216 | }) 217 | .body(|mut body| { 218 | for p in &res.iap_transactions { 219 | body.row(30.0, |mut row| { 220 | row.col(|ui| { 221 | ui.label(p.id.to_string()); 222 | }); 223 | row.col(|ui| { 224 | ui.label(format!("{:?}", p.reason)); 225 | }); 226 | row.col(|ui| { 227 | ui.label(p.product_id.clone()); 228 | }); 229 | row.col(|ui| { 230 | ui.label(p.purchase_date.to_string()); 231 | }); 232 | }); 233 | } 234 | }); 235 | }); 236 | 237 | ui.collapsing("events", |ui| { 238 | ui.label(format!("received: {}", res.iap_events.len())); 239 | 240 | let mut string = res.iap_events.join("\n"); 241 | ui.text_edit_multiline(&mut string); 242 | 243 | if ui.button("clear").clicked() { 244 | res.iap_events.clear(); 245 | } 246 | }); 247 | } 248 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | check: 2 | cd ./bevy_ios_iap/ && just check 3 | cd ./bevy_ios_iap_egui/ && just check 4 | 5 | build-rust-release: 6 | ./bevy_ios_iap/build-rust-release.sh 7 | 8 | build-rust: 9 | ./bevy_ios_iap/build-rust.sh 10 | 11 | copy-generated: 12 | sed -i '' 's/func __swift_bridge__/public func __swift_bridge__/g' bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.swift 13 | echo "import RustXcframework "|cat - ./bevy_ios_iap/generated/SwiftBridgeCore.swift > /tmp/out && mv /tmp/out ./bevy_ios_iap/generated/SwiftBridgeCore.swift 14 | echo "import RustXcframework "|cat - ./bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.swift > /tmp/out && mv /tmp/out ./bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.swift 15 | cp ./bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.h ./RustXcframework.xcframework/ios-arm64/Headers/ 16 | cp ./bevy_ios_iap/generated/SwiftBridgeCore.h ./RustXcframework.xcframework/ios-arm64/Headers/ 17 | cp ./bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.h ./RustXcframework.xcframework/ios-arm64_x86_64-simulator/Headers/ 18 | cp ./bevy_ios_iap/generated/SwiftBridgeCore.h ./RustXcframework.xcframework/ios-arm64_x86_64-simulator/Headers/ 19 | cp ./bevy_ios_iap/generated/bevy_ios_iap/bevy_ios_iap.swift ./Sources/bevy_ios_iap/ 20 | cp ./bevy_ios_iap/generated/SwiftBridgeCore.swift ./Sources/bevy_ios_iap/ 21 | 22 | build: build-rust copy-generated 23 | cp ./bevy_ios_iap/target/universal-ios/debug/libbevy_ios_iap.a ./RustXcframework.xcframework/ios-arm64_x86_64-simulator/ 24 | cp ./bevy_ios_iap/target/aarch64-apple-ios/debug/libbevy_ios_iap.a ./RustXcframework.xcframework/ios-arm64/ 25 | 26 | build-release: build-rust-release copy-generated 27 | cp ./bevy_ios_iap/target/universal-ios/release/libbevy_ios_iap.a ./RustXcframework.xcframework/ios-arm64_x86_64-simulator/ 28 | cp ./bevy_ios_iap/target/aarch64-apple-ios/release/libbevy_ios_iap.a ./RustXcframework.xcframework/ios-arm64/ 29 | ls -lisah ./RustXcframework.xcframework/ios-arm64/ 30 | ls -lisah ./RustXcframework.xcframework/ios-arm64_x86_64-simulator 31 | 32 | zip: build-release 33 | zip -r RustXcframework.xcframework.zip ./RustXcframework.xcframework/ 34 | ls -lisah RustXcframework.xcframework.zip 35 | shasum -a 256 RustXcframework.xcframework.zip 36 | shasum -a 256 RustXcframework.xcframework.zip > RustXcframework.xcframework.sha256.txt 37 | 38 | publish: 39 | cd bevy_ios_iap && cargo publish --no-verify 40 | --------------------------------------------------------------------------------