{"id":22840828,"url":"https://github.com/rustunit/bevy_ios_iap","last_synced_at":"2025-04-09T16:04:53.526Z","repository":{"id":236763280,"uuid":"793108290","full_name":"rustunit/bevy_ios_iap","owner":"rustunit","description":"Provides access to iOS native StoreKit2 Swift API from inside Bevy Apps","archived":false,"fork":false,"pushed_at":"2025-03-30T07:42:08.000Z","size":10649,"stargazers_count":30,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T16:04:44.254Z","etag":null,"topics":["bevy-engine","ios","rust","storekit2","swift"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/bevy_ios_iap","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rustunit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"rustunit"}},"created_at":"2024-04-28T12:58:25.000Z","updated_at":"2025-03-30T20:32:08.000Z","dependencies_parsed_at":"2024-05-12T12:29:40.858Z","dependency_job_id":"eb4176e9-9703-48dd-a4e9-ad0f934bef22","html_url":"https://github.com/rustunit/bevy_ios_iap","commit_stats":{"total_commits":74,"total_committers":2,"mean_commits":37.0,"dds":"0.013513513513513487","last_synced_commit":"c2db5dd1deec8ce17f88f77286febbc3b3443959"},"previous_names":["rustunit/bevy_ios_iap"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustunit%2Fbevy_ios_iap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustunit%2Fbevy_ios_iap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustunit%2Fbevy_ios_iap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustunit%2Fbevy_ios_iap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rustunit","download_url":"https://codeload.github.com/rustunit/bevy_ios_iap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248065289,"owners_count":21041871,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bevy-engine","ios","rust","storekit2","swift"],"created_at":"2024-12-13T01:13:34.728Z","updated_at":"2025-04-09T16:04:53.498Z","avatar_url":"https://github.com/rustunit.png","language":"Swift","funding_links":["https://github.com/sponsors/rustunit"],"categories":[],"sub_categories":[],"readme":"# bevy_ios_iap\n\n[![crates.io][sh_crates]][lk_crates]\n[![docs.rs][sh_docs]][lk_docs]\n[![discord][sh_discord]][lk_discord]\n\n[sh_crates]: https://img.shields.io/crates/v/bevy_ios_iap.svg\n[lk_crates]: https://crates.io/crates/bevy_ios_iap\n[sh_docs]: https://img.shields.io/docsrs/bevy_ios_iap\n[lk_docs]: https://docs.rs/bevy_ios_iap/latest/bevy_ios_iap/\n[sh_discord]: https://img.shields.io/discord/1176858176897953872?label=discord\u0026color=5561E6\n[lk_discord]: https://discord.gg/rQNeEnMhus\n\nProvides access to iOS native StoreKit2 Swift API from inside Bevy Apps.\nIt uses [Swift-Bridge](https://github.com/chinedufn/swift-bridge) to auto-generate the glue code and transport datatypes.\n\n![demo](./assets/demo.gif)\n\n\u003e Demo from our game using this crate: [zoolitaire.com](https://zoolitaire.com)\n\n## Features\n* fetch products\n* purchase products\n* listen to changes in transaction states\n* fetch list of all transactions (to restore old purchases of non-consumables)\n* supports subscriptions\n* convenient observer based API\n* egui based debug ui crate see [bevy_ios_iap_egui folder](./bevy_ios_iap_egui/README.md)\n\n## Notes\n* does not return locally un-signed/un-verified transactions\n\n## Todo\n* allow access to signature for remote verification\n* support offers\n* support family sharing\n\n## Instructions\n\n1. Add to XCode: Add SPM (Swift Package Manager) dependency\n2. Add Rust dependency\n3. Setup Plugin\n\n### 1. Add to XCode\n\n* Add `StoreKit` framework:\n![gamekit](./assets/framework.png)\n\n* Go to `File` -\u003e `Add Package Dependencies` and paste `https://github.com/rustunit/bevy_ios_iap.git` into the search bar on the top right:\n![xcode](./assets/xcode-spm.png)\n\n* 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.\n\n**Note:** \nThe rust crate used must be **exactly** the same version as the Swift Package (for binary compatibility reasons).\nI suggest using a specific version (like `0.2.0` in the screenshot) to make sure to always use binary matching versions!\n\n### 2. Add Rust dependency\n\n```\ncargo add bevy_ios_iap\n``` \n\nor \n\n```toml\n# always pin to the same exact version you also of the Swift package\nbevy_ios_iap = { version = \"=0.2.1\" }\n```\n\n### 3. Setup Plugin\n\nInitialize Bevy Plugin:\n\n```rust\n// request initialisation right on startup\napp.add_plugins(IosIapPlugin::new(true));\n```\n\n```rust\nfn bevy_system(mut iap: BevyIosIap) {\n    // If you set the plugin to manual init, this will register the \n    // TranscactionObserver to listen to updates to any Transactions and trigger\n    // `IosIapEvents::Transaction` accordingly.\n    // Note: this will require the user to be logged in into their apple-id and popup a login dialog if not\n    bevy_ios_iap::init();\n\n    // request product details, product IDs have to be explicitly provided\n    iap.products(vec![\"com.rustunit.zoolitaire.levelunlock\".into()])\n        .on_response(|trigger: Trigger\u003cProducts\u003e| match \u0026trigger.event().0 {\n            IosIapProductsResponse::Done(products) =\u003e {\n                info!(\"products loaded: {}\", products.len());\n\n                for p in products {\n                    info!(\"product: {:?}\", p);\n                }\n            }\n            IosIapProductsResponse::Error(e) =\u003e error!(\"error fetching products: {e}\"),\n        });\n\n    // trigger a product purchase for a specific product ID\n    iap.purchase(\"com.rustunit.zoolitaire.levelunlock\".into())\n        .on_response(|trigger: Trigger\u003cPurchase\u003e|{\n            match \u0026trigger.event().0 {\n                IosIapPurchaseResponse::Success(t) =\u003e {\n                    info!(\"just purchased: '{}' {}\", t.product_id, t.id);\n\n                    iap.finish_transaction(t.id).on_response(on_finish_transaction);\n                }\n                _ =\u003e {}\n            }\n        });\n\n    // request to restore active subscriptions and non-consumables\n    iap.current_entitlements()\n        .on_response(|trigger: Trigger\u003cCurrentEntitlements\u003e|{\n            info!(\"current entitlements: {}\", trigger.event());\n        });\n}\n```\n\nProcess Response Events from iOS back to us in Rust:\n\n```rust\nfn process_iap_events(\n    mut events: EventReader\u003cIosIapEvents\u003e,\n) {\n    for e in events.read() {\n        match e {\n            // this is triggered when a transaction verification state changes during the runtime of the app\n            IosIapEvents::TransactionUpdate(_) =\u003e todo!(),\n        }\n    }\n}\n```\n\n## Local development\n\n1. Build locally via `just build`\n2. Change the `Package.swift` to use the locally built `xcframework`\n3. Switch XCode package dependency to use local repo via path\n4. Patch `Cargo.toml` to use local repository\n\n## Our Other Crates\n\n- [bevy_debug_log](https://github.com/rustunit/bevy_debug_log)\n- [bevy_device_lang](https://github.com/rustunit/bevy_device_lang)\n- [bevy_web_popups](https://github.com/rustunit/bevy_web_popups)\n- [bevy_libgdx_atlas](https://github.com/rustunit/bevy_libgdx_atlas)\n- [bevy_ios_review](https://github.com/rustunit/bevy_ios_review)\n- [bevy_ios_gamecenter](https://github.com/rustunit/bevy_ios_gamecenter)\n- [bevy_ios_alerts](https://github.com/rustunit/bevy_ios_alerts)\n- [bevy_ios_notifications](https://github.com/rustunit/bevy_ios_notifications)\n- [bevy_ios_impact](https://github.com/rustunit/bevy_ios_impact)\n- [bevy_ios_safearea](https://github.com/rustunit/bevy_ios_safearea)\n\n## Bevy version support\n\n|bevy|bevy\\_ios\\_iap|\n|---|---|\n|0.15|0.5,main|\n|0.14|0.3,0.4|\n|0.13|0.2|\n\n# License\n\nAll code in this repository is dual-licensed under either:\n\n- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)\n- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)\n\nat your option. This means you can select the license you prefer.\n\n## Your contributions\nUnless 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustunit%2Fbevy_ios_iap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frustunit%2Fbevy_ios_iap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustunit%2Fbevy_ios_iap/lists"}