{"id":21601714,"url":"https://github.com/wtto00/tauri-plugin-iap","last_synced_at":"2025-04-11T02:14:29.907Z","repository":{"id":243043536,"uuid":"806457593","full_name":"wtto00/tauri-plugin-iap","owner":"wtto00","description":"A plugin of In App Purchase for Tauri@v1 on MacOS.","archived":false,"fork":false,"pushed_at":"2024-06-19T07:14:12.000Z","size":479,"stargazers_count":21,"open_issues_count":2,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T02:14:25.176Z","etag":null,"topics":["inapppurchase","tauri-plugin"],"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/wtto00.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2024-05-27T08:34:03.000Z","updated_at":"2025-04-07T18:31:33.000Z","dependencies_parsed_at":"2024-06-11T15:24:25.929Z","dependency_job_id":null,"html_url":"https://github.com/wtto00/tauri-plugin-iap","commit_stats":null,"previous_names":["wtto00/tauri-plugin-iap"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wtto00%2Ftauri-plugin-iap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wtto00%2Ftauri-plugin-iap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wtto00%2Ftauri-plugin-iap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wtto00%2Ftauri-plugin-iap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wtto00","download_url":"https://codeload.github.com/wtto00/tauri-plugin-iap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248328163,"owners_count":21085261,"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":["inapppurchase","tauri-plugin"],"created_at":"2024-11-24T19:10:22.867Z","updated_at":"2025-04-11T02:14:29.881Z","avatar_url":"https://github.com/wtto00.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tauri Plugin IAP\n\nA plugin of In App Purchase for Tauri on MacOS.\n\n## Installation\n\n- Add dependencies in file `src-tauri/Cargo.toml`:\n\n  ```yaml\n  [target.'cfg(target_os = \"macos\")'.dependencies]\n  tauri-plugin-iap = { git = \"https://github.com/wtto00/tauri-plugin-iap\", tag = \"v0.0.1\" }\n  ```\n\n- Add dependencies of front-end:\n\n  ```shell\n  pnpm add https://github.com/wtto00/tauri-plugin-iap.git\n  # yarn add https://github.com/wtto00/tauri-plugin-iap.git\n  # npm i --save https://github.com/wtto00/tauri-plugin-iap.git\n  ```\n\n- Enable plugins in `src-tauri/main.rs`\n\n  ```rs\n  fn main() {\n    tauri::Builder::default()\n        .setup(move |app| {\n            // Add this line\n            #[cfg(target_os=\"macos\")]\n            app.app_handle().plugin(tauri_plugin_iap::init())?;\n\n            Ok(())\n        })\n        .run(tauri::generate_context!())\n        .expect(\"error while running tauri application\");\n  }\n  ```\n\n## Prepare\n\n1. This plugin requires a minimum MacOS version of 10.15 or higher, so you must configure it in `src-tauri/tauri.config.json`.\n\n   ```json\n   {\n     \"tauri\": {\n       \"bundle\": {\n         \"macOS\": {\n           \"minimumSystemVersion\": \"10.15\"\n         }\n       }\n     }\n   }\n   ```\n\n1. You can only test IAP in a signed app. Since `Tauri` cannot be signed in development environment, you'll need to sign it and upload it to `AppConnect` for testing, then install and test it from `TestFlight`. See details at: \u003chttps://github.com/tauri-apps/tauri/issues/7930\u003e\n\n   About uploading to `AppConnect`, see [Publish](#publish)\n\n## Usage\n\n```typescript\nimport {\n  canMakePayments,\n  initialize,\n  startQueryProducts,\n  TransactionStatus,\n  finishTransaction,\n  requestPruchase,\n  restorePurchases,\n  type Product,\n  type Transaction,\n  type Exception,\n} from \"tauri-plugin-iap-api\";\n\n// This maybe fetch from your own server api\nconst product_identifiers = [\"product_id_1\", \"product_id_2\"];\n\n// The verified and available products are displayed in the interface.\nlet products_validated = [];\n\n// TODO: Send receiptData to your own server api to validate the transaction is valid or not.\n// You should cache verified receiptData or transactionId to avoid repeatedly verifying the same data. About caching transactionId, you can refer to https://stackoverflow.com/questions/45705069/ios-storekit-transaction-identifier-does-not-match-receipt\nfunction validate(transaction: Transaction) {\n  return true;\n}\n\nfunction onProductsUpdated(products: Product[]) {\n  products_validated.push(...products);\n}\nasync function onTransactionsUpdated(transactions: Transaction[]) {\n  for await (const transaction of transactions) {\n    if (transaction.status === TransactionStatus.pending) {\n      // Just Show loading\n      continue;\n    }\n    let msg = \"\";\n    if (transaction.status === TransactionStatus.failed) {\n      msg ||= transaction.error || \"Something wrong.\";\n    } else if (\n      transaction.status === TransactionStatus.purchased ||\n      transaction.status === TransactionStatus.restored\n    ) {\n      const isValid = await validate();\n      if (isValid) {\n        // TODO: Distribute the verified purchased items to the user.\n        msg ||= \"Success\";\n\n        // if this is not called a transaction will keep being triggered automatically on app start\n        finishTransaction(transaction.transactionId);\n      }\n    }\n    if (msg) {\n      // Just toast msg\n    }\n  }\n}\nfunction onRestoreCompleted() {\n  // If user only purchases items that are not restorable, such as a non-renewing subscription or a consumable product.\n  // In this situation, `onTransactionsUpdated` cannot be called back.\n  // So you can inform the user that the restoration has been completed through this method.\n}\nfunction onException(err: Exception) {\n  // Just toast some error message\n}\nif (await canMakePayments()) {\n  const inited = await initialize({\n    onProductsUpdated,\n    onTransactionsUpdated,\n    onRestoreCompleted,\n    onException,\n  });\n  if (inited) {\n    startQueryProducts(product_identifiers);\n  }\n}\n\n// restore finished purchase\nrestorePurchases();\n\n// request a purchase\nrequestPruchase(product_identifiers[0]);\n```\n\n## Api\n\n### canMakePayments\n\nif the payment platform is ready and available or not.\n\n[Apple Document Link](https://developer.apple.com/documentation/storekit/appstore/3822277-canmakepayments)\n\n```ts\nconst isAvailable = await canMakePayments();\n```\n\n### countryCode\n\nThe three-letter code that represents the country or region associated with the App Store storefront.\n\n[Apple Document Link](https://developer.apple.com/documentation/storekit/storefront/3792000-countrycode)\n\n```ts\nconst code = await countryCode();\n```\n\n### initialize\n\nInitialize the plugin.\n\nIf the initialization is not successful, you cannot call the `startQueryProducts`, `restorePurchases`, `requestPurchase`, `finishTransaction` interfaces.\n\n```ts\nconst inited = await initialize({\n  onProductsUpdated: (products: Product[]) =\u003e {},\n  onTransactionsUpdated: async (transactions: Transaction[]) =\u003e {},\n  onRestoreCompleted: () =\u003e {},\n  onException: (err: Exception) =\u003e {},\n});\n```\n\n### startQueryProducts\n\nRequests product data from the App Store.\n\n[Apple Document Link](https://developer.apple.com/documentation/storekit/product/3851116-products)\n\n```ts\nconst productIdentifiers = [\"com.example.productA\", \"com.example.productB\"];\nvoid startQueryProducts(productIdentifiers);\n```\n\nThe query result is returned in the `onProductsUpdated` callback in the `initialize` function. [Apple Document Link](https://developer.apple.com/documentation/storekit/skproductsrequestdelegate/1506070-productsrequest)\n\n### restorePurchases\n\nAsks the payment queue to restore previously completed purchases.\n\n[Apple Document Link](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506123-restorecompletedtransactions)\n\n```ts\nvoid restorePurchases();\n```\n\n### requestPruchase\n\nRequest a purchase.\n\n```ts\nvoid requestPruchase(\"com.example.productA\");\n```\n\n### finishTransaction\n\n[Apple Document Link](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506003-finishtransaction)\n\n```ts\nvoid finishTransaction(\"someTransactionId\");\n```\n\n## Publish\n\nPlease replace the `COMPANY_NAME`, `TEAM_ID`, `APP_NAME`, `APP_IDENTIFIER` with your specific information.\n\n1. Preparation\n\n   - Ensure that the certificate `3rd Party Mac Developer Application: COMPANY_NAME (TEAM_ID)` and `3rd Party Mac Developer Installer: COMPANY_NAME (TEAM_ID)` is installed on the local machine.  \n     You can see it in `Keychain Access` app.  \n     Created in \u003chttps://developer.apple.com/account/resources/certificates/add\u003e, and select `Mac App Distribution`, `Mac Installer Distribution` in `Software` section.\n   - Make sure to download the correct provision profile file from AppConnect to `src-tauri/entitlements/Mac_App_Distribution.provisionprofile`.  \n     Ceated in \u003chttps://developer.apple.com/account/resources/profiles/add\u003e, and select `Mac App Store Connect` in `Distribution` section.\n   - Ensure that the entitlements file has been created in `src-tauri/entitlements/APP_NAME.entitlements`.  \n     Reference content is as follows:\n\n     ```xml\n     \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n     \u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n     \u003cplist version=\"1.0\"\u003e\n       \u003cdict\u003e\n         \u003ckey\u003ecom.apple.security.app-sandbox\u003c/key\u003e\n         \u003ctrue/\u003e\n         \u003ckey\u003ecom.apple.security.network.client\u003c/key\u003e\n         \u003ctrue/\u003e\n         \u003ckey\u003ecom.apple.security.files.user-selected.read-write\u003c/key\u003e\n         \u003ctrue/\u003e\n         \u003ckey\u003ecom.apple.application-identifier\u003c/key\u003e\n         \u003cstring\u003eTEAM_ID.APP_IDENTIFIER\u003c/string\u003e\n         \u003ckey\u003ecom.apple.developer.team-identifier\u003c/key\u003e\n         \u003cstring\u003eTEAM_ID\u003c/string\u003e\n       \u003c/dict\u003e\n     \u003c/plist\u003e\n     ```\n\n     The list of entitlements can be found [here](https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AboutEntitlements.html#//apple_ref/doc/uid/TP40011195-CH1-SW1). If you want to publish an app on the App Store, you need to ensure that it does not include unused entitlements.\n\n2. Execute the following script\n\n   ```shell\n   unset APPLE_SIGNING_IDENTITY\n   unset APPLE_CERTIFICATE\n   sign_app=\"3rd Party Mac Developer Application: COMPANY_NAME (TEAM_ID)\"\n   sign_install=\"3rd Party Mac Developer Installer: COMPANY_NAME (TEAM_ID)\"\n   profile=\"src-tauri/entitlements/Mac_App_Distribution.provisionprofile\"\n\n   target=\"universal-apple-darwin\"\n\n   npx tauri build --target \"${target}\" --verbose\n   # cargo tauri build --target \"${target}\" --verbose\n\n   app_path=\"src-tauri/target/${target}/release/bundle/macos/APP_NAME.app\"\n   build_name=\"src-tauri/target/${target}/release/bundle/macos/APP_NAME.pkg\"\n   cp_dir=\"src-tauri/target/${target}/release/bundle/macos/APP_NAME.app/Contents/embedded.provisionprofile\"\n   entitlements=\"src-tauri/entitlements/APP_NAME.entitlements\"\n\n   cp \"${profile}\" \"${cp_dir}\"\n\n   codesign --deep --force -s \"${sign_app}\" --entitlements ${entitlements} \"${app_path}\"\n\n   productbuild --component \"${app_path}\" /Applications/ --sign \"${sign_install}\" \"${build_name}\"\n   ```\n\n3. Upload to AppConnect  \n   Now you will find the file `src-tauri/target/${target}/release/bundle/macos/APP_NAME.pkg`. Upload this pkg file to `AppConnect` by `Transporter`.\n\n4. Install from TestFlight\n\n   After you upload to `AppConnect`, you can see the app you just uploaded on `TestFlight` a few minutes later, install it, and test it.\n\n## Debug\n\nYou can see the debug message of this plugin by this command:\n\n```shell\nlog stream --level debug --predicate 'subsystem == \"tauri\" \u0026\u0026 category == \"plugin.apple.iap\"'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwtto00%2Ftauri-plugin-iap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwtto00%2Ftauri-plugin-iap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwtto00%2Ftauri-plugin-iap/lists"}