Code Monkey home page Code Monkey logo

tauri-plugin-iap's Introduction

Tauri Plugin IAP

A plugin of In App Purchase for Tauri on MacOS.

Installation

  • Add dependencies in file src-tauri/Cargo.toml:

    [target.'cfg(target_os = "macos")'.dependencies]
    tauri-plugin-iap = { git = "https://github.com/wtto00/tauri-plugin-iap", tag = "v0.0.1" }
  • Add dependencies of front-end:

    pnpm add https://github.com/wtto00/tauri-plugin-iap.git
    # yarn add https://github.com/wtto00/tauri-plugin-iap.git
    # npm i --save https://github.com/wtto00/tauri-plugin-iap.git
  • Enable plugins in src-tauri/main.rs

    fn main() {
      tauri::Builder::default()
          .setup(move |app| {
              // Add this line
              #[cfg(target_os="macos")]
              app.app_handle().plugin(tauri_plugin_iap::init())?;
    
              Ok(())
          })
          .run(tauri::generate_context!())
          .expect("error while running tauri application");
    }

Prepare

  1. This plugin requires a minimum MacOS version of 10.15 or higher, so you must configure it in src-tauri/tauri.config.json.

    {
      "tauri": {
        "bundle": {
          "macOS": {
            "minimumSystemVersion": "10.15"
          }
        }
      }
    }
  2. 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: tauri-apps/tauri#7930

    About uploading to AppConnect, see Publish

Usage

import {
  canMakePayments,
  initialize,
  startQueryProducts,
  TransactionStatus,
  finishTransaction,
  requestPruchase,
  restorePurchases,
  type Product,
  type Transaction,
  type Exception,
} from "tauri-plugin-iap-api";

// This maybe fetch from your own server api
const product_identifiers = ["product_id_1", "product_id_2"];

// The verified and available products are displayed in the interface.
let products_validated = [];

// TODO: Send receiptData to your own server api to validate the transaction is valid or not.
// 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
function validate(transaction: Transaction) {
  return true;
}

function onProductsUpdated(products: Product[]) {
  products_validated.push(...products);
}
async function onTransactionsUpdated(transactions: Transaction[]) {
  for await (const transaction of transactions) {
    if (transaction.status === TransactionStatus.pending) {
      // Just Show loading
      continue;
    }
    let msg = "";
    if (transaction.status === TransactionStatus.failed) {
      msg ||= transaction.error || "Something wrong.";
    } else if (
      transaction.status === TransactionStatus.purchased ||
      transaction.status === TransactionStatus.restored
    ) {
      const isValid = await validate();
      if (isValid) {
        // TODO: Distribute the verified purchased items to the user.
        msg ||= "Success";

        // if this is not called a transaction will keep being triggered automatically on app start
        finishTransaction(transaction.transactionId);
      }
    }
    if (msg) {
      // Just toast msg
    }
  }
}
function onRestoreCompleted() {
  // If user only purchases items that are not restorable, such as a non-renewing subscription or a consumable product.
  // In this situation, `onTransactionsUpdated` cannot be called back.
  // So you can inform the user that the restoration has been completed through this method.
}
function onException(err: Exception) {
  // Just toast some error message
}
if (await canMakePayments()) {
  const inited = await initialize({
    onProductsUpdated,
    onTransactionsUpdated,
    onRestoreCompleted,
    onException,
  });
  if (inited) {
    startQueryProducts(product_identifiers);
  }
}

// restore finished purchase
restorePurchases();

// request a purchase
requestPruchase(product_identifiers[0]);

Api

canMakePayments

if the payment platform is ready and available or not.

Apple Document Link

const isAvailable = await canMakePayments();

countryCode

The three-letter code that represents the country or region associated with the App Store storefront.

Apple Document Link

const code = await countryCode();

initialize

Initialize the plugin.

If the initialization is not successful, you cannot call the startQueryProducts, restorePurchases, requestPurchase, finishTransaction interfaces.

const inited = await initialize({
  onProductsUpdated: (products: Product[]) => {},
  onTransactionsUpdated: async (transactions: Transaction[]) => {},
  onRestoreCompleted: () => {},
  onException: (err: Exception) => {},
});

startQueryProducts

Requests product data from the App Store.

Apple Document Link

const productIdentifiers = ["com.example.productA", "com.example.productB"];
void startQueryProducts(productIdentifiers);

The query result is returned in the onProductsUpdated callback in the initialize function. Apple Document Link

restorePurchases

Asks the payment queue to restore previously completed purchases.

Apple Document Link

void restorePurchases();

requestPruchase

Request a purchase.

void requestPruchase("com.example.productA");

finishTransaction

Apple Document Link

void finishTransaction("someTransactionId");

Publish

Please replace the COMPANY_NAME, TEAM_ID, APP_NAME, APP_IDENTIFIER with your specific information.

  1. Preparation

    • 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.
      You can see it in Keychain Access app.
      Created in https://developer.apple.com/account/resources/certificates/add, and select Mac App Distribution, Mac Installer Distribution in Software section.

    • Make sure to download the correct provision profile file from AppConnect to src-tauri/entitlements/Mac_App_Distribution.provisionprofile.
      Ceated in https://developer.apple.com/account/resources/profiles/add, and select Mac App Store Connect in Distribution section.

    • Ensure that the entitlements file has been created in src-tauri/entitlements/APP_NAME.entitlements.
      Reference content is as follows:

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
        <dict>
          <key>com.apple.security.app-sandbox</key>
          <true/>
          <key>com.apple.security.network.client</key>
          <true/>
          <key>com.apple.security.files.user-selected.read-write</key>
          <true/>
          <key>com.apple.application-identifier</key>
          <string>TEAM_ID.APP_IDENTIFIER</string>
          <key>com.apple.developer.team-identifier</key>
          <string>TEAM_ID</string>
        </dict>
      </plist>

      The list of entitlements can be found here. If you want to publish an app on the App Store, you need to ensure that it does not include unused entitlements.

  2. Execute the following script

    unset APPLE_SIGNING_IDENTITY
    unset APPLE_CERTIFICATE
    sign_app="3rd Party Mac Developer Application: COMPANY_NAME (TEAM_ID)"
    sign_install="3rd Party Mac Developer Installer: COMPANY_NAME (TEAM_ID)"
    profile="src-tauri/entitlements/Mac_App_Distribution.provisionprofile"
    
    target="universal-apple-darwin"
    
    npx tauri build --target "${target}" --verbose
    # cargo tauri build --target "${target}" --verbose
    
    app_path="src-tauri/target/${target}/release/bundle/macos/APP_NAME.app"
    build_name="src-tauri/target/${target}/release/bundle/macos/APP_NAME.pkg"
    cp_dir="src-tauri/target/${target}/release/bundle/macos/APP_NAME.app/Contents/embedded.provisionprofile"
    entitlements="src-tauri/entitlements/APP_NAME.entitlements"
    
    cp "${profile}" "${cp_dir}"
    
    codesign --deep --force -s "${sign_app}" --entitlements ${entitlements} "${app_path}"
    
    productbuild --component "${app_path}" /Applications/ --sign "${sign_install}" "${build_name}"
  3. Upload to AppConnect
    Now you will find the file src-tauri/target/${target}/release/bundle/macos/APP_NAME.pkg. Upload this pkg file to AppConnect by Transporter.

  4. Install from TestFlight

    After you upload to AppConnect, you can see the app you just uploaded on TestFlight a few minutes later, install it, and test it.

Debug

You can see the debug message of this plugin by this command:

log stream --level debug --predicate 'subsystem == "tauri" && category == "plugin.apple.iap"'

tauri-plugin-iap's People

Contributors

wtto00 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

angryberryms

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.