{"id":28604632,"url":"https://github.com/jaywcjlove/StoreKitHelper","last_synced_at":"2025-06-11T18:03:02.239Z","repository":{"id":282523381,"uuid":"943949174","full_name":"jaywcjlove/StoreKitHelper","owner":"jaywcjlove","description":"A lightweight StoreKit2 wrapper designed specifically for SwiftUI, making it easier to implement in-app purchases.","archived":false,"fork":false,"pushed_at":"2025-06-04T11:42:14.000Z","size":112,"stargazers_count":111,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-05T08:03:46.457Z","etag":null,"topics":["apple","iap","in-app-purchase","ios","ios-swift","jaywcjlove","macos","payment","purchase","receipt","storekit","storekit2","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaywcjlove.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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,"zenodo":null},"funding":{"ko_fi":"jaywcjlove","buy_me_a_coffee":"jaywcjlove","custom":["https://www.paypal.me/kennyiseeyou","https://jaywcjlove.github.io/#/sponsor"]}},"created_at":"2025-03-06T14:33:55.000Z","updated_at":"2025-06-04T11:42:15.000Z","dependencies_parsed_at":"2025-03-15T07:24:09.855Z","dependency_job_id":"e6e3e925-a60c-46b0-9cbb-ad8ed6538f5a","html_url":"https://github.com/jaywcjlove/StoreKitHelper","commit_stats":null,"previous_names":["jaywcjlove/storekithelper"],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaywcjlove%2FStoreKitHelper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaywcjlove%2FStoreKitHelper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaywcjlove%2FStoreKitHelper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaywcjlove%2FStoreKitHelper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaywcjlove","download_url":"https://codeload.github.com/jaywcjlove/StoreKitHelper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaywcjlove%2FStoreKitHelper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259280658,"owners_count":22833432,"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":["apple","iap","in-app-purchase","ios","ios-swift","jaywcjlove","macos","payment","purchase","receipt","storekit","storekit2","swift","swiftui"],"created_at":"2025-06-11T18:01:16.015Z","updated_at":"2025-06-11T18:03:02.234Z","avatar_url":"https://github.com/jaywcjlove.png","language":"Swift","readme":"StoreKit Helper\n===\n\nA lightweight StoreKit2 wrapper designed specifically for SwiftUI, making it easier to implement in-app purchases.\n\n![StoreKit Helper](https://github.com/user-attachments/assets/d0d27552-9d2d-4a09-8d8d-b96b3b3648a9)\n\n✦ My macOS/iOS application ✦\n\n\u003cp style=\"display: inline-block\"\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6746747327\" title=\"Mousio for macOS\"\u003e\u003cimg align=\"center\" alt=\"Mousio\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/9edf61ff-5a6c-4676-9cc2-8fd3c1ad0dfb\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6745227444\" title=\"Musicer for macOS\"\u003e\u003cimg align=\"center\" alt=\"Musicer\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/b7abfba8-88ff-4c86-a125-43073d5aef22\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6743841447\" title=\"Audioer for macOS\"\u003e\u003cimg align=\"center\" alt=\"Audioer\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/7a836865-8c90-4119-87bc-19e06a76c957\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6744690194\" title=\"FileSentinel for macOS\"\u003e\u003cimg align=\"center\" alt=\"FileSentinel\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/28bce2cc-290e-45bf-9068-585ff6ecafe9\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6743495172\" title=\"FocusCursor for macOS\"\u003e\u003cimg align=\"center\" alt=\"FocusCursor\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/d543668a-737b-4853-a6bb-eaa269e69836\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6742680573\" title=\"Videoer for macOS\"\u003e\u003cimg align=\"center\" alt=\"Videoer\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/10ffb0f1-0625-40d6-93f1-2c2496592595\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6740425504\" title=\"KeyClicker for macOS\"\u003e\u003cimg align=\"center\" alt=\"KeyClicker\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/5a19fcb9-cb81-4855-b4ea-31c604d9612a\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6739052447\" title=\"DayBar for macOS\"\u003e\u003cimg align=\"center\" alt=\"DayBar\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/b67d4a2e-92e2-4d8c-8c6f-2a1eb3e2fa93\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6739444407\" title=\"Iconed for macOS\"\u003e\u003cimg align=\"center\" alt=\"Iconed\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/8a35dc7b-4faf-4e2a-9311-f66d6844a896\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6737160756\" title=\"RightMenu Master for macOS\"\u003e\u003cimg align=\"center\" alt=\"RightMenu Master\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/39a76541-71bf-4de7-a01c-c62f0557dff5\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6723903021\" title=\"Paste Quick for macOS\"\u003e\u003cimg align=\"center\" alt=\"Quick RSS\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/bdaad5b7-9810-44ce-8f17-8410864465d2\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6670696072\" title=\"Quick RSS for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"Quick RSS\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/374106b5-a448-4d1d-9ccb-b04b6bc681ed\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6670167443\" title=\"Web Serve for macOS\"\u003e\u003cimg align=\"center\" alt=\"Web Serve\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/e1d9f76f-0f3d-4ba5-8a15-253ee173bb1c\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6503953628\" title=\"Copybook Generator for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"Copybook Generator\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/b90e42ff-158b-4534-82ca-5898fd0e8d73\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6471227008\" title=\"DevTutor for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"DevTutor for SwiftUI\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/f15c154d-0192-48eb-8e0e-9e245ffd974a\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6479819388\" title=\"RegexMate for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"RegexMate\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/aabe5aa9-9a96-4390-8bed-c3e4023d0dea\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6479194014\" title=\"Time Passage for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"Time Passage\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/time-passage/assets/1680273/6f30e429-e6f3-4dbe-9921-a5effe2a05e9\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6478772538\" title=\"IconizeFolder for macOS\"\u003e\u003cimg align=\"center\" alt=\"Iconize Folder\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/fa9d8b9c-1e51-4ded-877c-fa5b21c47220\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6478511402\" title=\"Textsound Saver for macOS/iOS\"\u003e\u003cimg align=\"center\" alt=\"Textsound Saver\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/0595e842-980b-4574-8891-a8ba853a08be\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6476924627\" title=\"Create Custom Symbols for macOS\"\u003e\u003cimg align=\"center\" alt=\"Create Custom Symbols\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/8cd022ce-a3f1-4e89-b7c6-6fbd0d4db77c\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6476452351\" title=\"DevHub for macOS\"\u003e\u003cimg align=\"center\" alt=\"DevHub\" height=\"52\" width=\"52\" src=\"https://github.com/user-attachments/assets/4a44a4fd-67ce-430b-af0a-72f18feaa47d\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6476400184\" title=\"Resume Revise for macOS\"\u003e\u003cimg align=\"center\" alt=\"Resume Revise\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/c9954a20-1905-48de-bdf8-d71837974aa2\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6472593276\" title=\"Palette Genius for macOS\"\u003e\u003cimg align=\"center\" alt=\"Palette Genius\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/27340413-d355-45b2-8f6f-6ac37682d957\"\u003e\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://apps.apple.com/app/6470879005\" title=\"Symbol Scribe for macOS\"\u003e\u003cimg align=\"center\" alt=\"Symbol Scribe\" height=\"52\" width=\"52\" src=\"https://github.com/jaywcjlove/jaywcjlove/assets/1680273/c7249f05-fa70-4def-a1e9-571d5f171fc9\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Documentation\n\nPlease refer to the detailed `StoreKitHelper` [documentation](https://github.com/jaywcjlove/devtutor) in [DevTutor](https://github.com/jaywcjlove/devtutor), which includes multiple quick start examples, custom payment interface examples, and API references, providing comprehensive examples and guidance.\n\n## Usage\n\nAt the entry point of the SwiftUI application, create and inject a `StoreContext` instance, which is responsible for loading the product list and tracking purchase status.\n\n```swift\nimport StoreKitHelper\n\nenum AppProduct: String, InAppProduct {\n    case lifetime = \"focuscursor.lifetime\"\n    case monthly = \"focuscursor.monthly\"\n    var id: String { rawValue }\n}\n\n@main struct DevTutorApp: App {\n    @StateObject var store = StoreContext(products: AppProduct.allCases)\n    var body: some Scene {\n        WindowGroup {\n            ContentView().environmentObject(store)\n        }\n    }\n}\n```\n\nUse `StoreKitHelperView` to directly display an in-app purchase popup view and configure various parameters through a chained API.\n\n```swift\nstruct PurchaseContent: View {\n    @EnvironmentObject var store: StoreContext\n    var body: some View {\n        StoreKitHelperView()\n            .frame(maxWidth: 300)\n            .frame(minWidth: 260)\n            // Triggered when the popup is dismissed (e.g., user clicks the close button)\n            .onPopupDismiss {\n                store.isShowingPurchasePopup = false\n            }\n            // Sets the content area displayed in the purchase interface \n            // (can include feature descriptions, version comparisons, etc.)\n            .pricingContent {\n                AnyView(PricingContent())\n            }\n            .termsOfService {\n                // Action triggered when the [Terms of Service] button is clicked\n            }\n            .privacyPolicy {\n                // Action triggered when the [Privacy Policy] button is clicked\n            }\n    }\n}\n```\n\nClick to open the paid product list interface.\n\n```swift\nstruct PurchaseButton: View {\n    @EnvironmentObject var store: StoreContext\n    var body: some View {\n        if store.hasNotPurchased == true {\n            PurchasePopupButton()\n                .sheet(isPresented: $store.isShowingPurchasePopup) {\n                    /// Popup with the paid product list\n                    PurchaseContent()\n                }\n        }\n    }\n}\n```\n\nYou can use the `hasNotPurchased` property in `StoreContext` to check if the user has made a purchase, and then dynamically display different interface content. For example:\n\n```swift\n@EnvironmentObject var store: StoreContext\n\nvar body: some View {\n    if store.hasNotPurchased == true {\n        // 🧾 User has not purchased - Show restricted content or prompt for purchase\n    } else {\n        // ✅ User has purchased - Show full features\n    }\n}\n```\n\n### filteredProducts\n\nThis is a simple migration solution: the product list is filtered by product ID, retaining the old product IDs so existing users don’t need to repurchase and can restore their purchases, while new users purchase through the new product IDs, achieving a smooth transition.\n    \n```swift\nenum AppProduct: String, InAppProduct {\n    /// old\n    case sponsor = \"focuscursor.Sponsor\"\n    case generous = \"focuscursor.Generous\"\n    /// new\n    case monthly = \"focuscursor.monthly\"\n    case lifetime = \"focuscursor.lifetime\"\n    var id: String { rawValue }\n}\n\nStoreKitHelperView()\n    .filteredProducts() { productID, product in\n        if productID == AppProduct.sponsor.rawValue {\n            return false\n        }\n        if productID == AppProduct.generous.rawValue {\n            return false\n        }\n        return true\n    }\n\nStoreKitHelperSelectionView()\n    .filteredProducts() { productID, product in\n        return true\n    }\n```\n\n## License\n\nLicensed under the MIT License.\n","funding_links":["https://ko-fi.com/jaywcjlove","https://buymeacoffee.com/jaywcjlove","https://www.paypal.me/kennyiseeyou","https://jaywcjlove.github.io/#/sponsor"],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaywcjlove%2FStoreKitHelper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaywcjlove%2FStoreKitHelper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaywcjlove%2FStoreKitHelper/lists"}