All Projects → iaphub → React Native Iaphub

iaphub / React Native Iaphub

Licence: gpl-3.0
The easiest way to implement IAP (In-app purchase) in your React Native app.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to React Native Iaphub

Pandoraplayer
🅿️ PandoraPlayer is a lightweight music player for iOS, based on AudioKit and completely written in Swift.
Stars: ✭ 1,037 (+502.91%)
Mutual labels:  itunes
Neptunes
simple and reliable Last.fm scrobbler for iTunes and Spotify for macOS
Stars: ✭ 98 (-43.02%)
Mutual labels:  itunes
Homebridge Dacp
Remotely control Apple TV and iTunes via HomeKit.
Stars: ✭ 128 (-25.58%)
Mutual labels:  itunes
Forked Daapd
Linux/FreeBSD DAAP (iTunes) and MPD media server with support for AirPlay devices (multiroom), Apple Remote (and compatibles), Chromecast, Spotify and internet radio.
Stars: ✭ 1,073 (+523.84%)
Mutual labels:  itunes
Podcast
iTunes and RSS 2.0 Podcast Generator in Golang
Stars: ✭ 91 (-47.09%)
Mutual labels:  itunes
Itunes store transporter
Upload and manage your assets in the iTunes Store using the iTunes Store’s Transporter (iTMSTransporter).
Stars: ✭ 117 (-31.98%)
Mutual labels:  itunes
Teslatunes
Copy your iTunes library, automatically converting Apple Lossless to flac, to a destination for use with your Tesla Model S
Stars: ✭ 37 (-78.49%)
Mutual labels:  itunes
Itunes Remote
Remotely control iTunes on Mac without Internet 🎶📱
Stars: ✭ 160 (-6.98%)
Mutual labels:  itunes
Carol Xamarin
A minimal and beautiful lyrics app for macOS built with Xamarin and C#
Stars: ✭ 97 (-43.6%)
Mutual labels:  itunes
Music Bar
🎶 Control Apple Music right from your macOS menu bar.
Stars: ✭ 128 (-25.58%)
Mutual labels:  itunes
Russia It Podcast
Список русскоязычных подкастов на тему информационных технологий
Stars: ✭ 1,095 (+536.63%)
Mutual labels:  itunes
Developing Ios 11 Apps With Swift
Stanford 公开课,Developing iOS 11 Apps with Swift 字幕翻译
Stars: ✭ 1,237 (+619.19%)
Mutual labels:  itunes
Alltomp3
Node module to download and convert in MP3 with tags an online video
Stars: ✭ 120 (-30.23%)
Mutual labels:  itunes
Itunespy
🐍 A simple library to fetch data from the iTunes Store API made for Python >= 3.5
Stars: ✭ 47 (-72.67%)
Mutual labels:  itunes
Musaicfm
Screensaver inspired by Apple’s inbuilt iTunes Screensaver. It can display Artwork by Spotify or last.fm Profile Data.
Stars: ✭ 144 (-16.28%)
Mutual labels:  itunes
Retroactive
Run Aperture, iPhoto, and iTunes on macOS Big Sur and macOS Catalina. Xcode 11.7 on macOS Mojave. Final Cut Pro 7, Logic Pro 9, and iWork ’09 on macOS Mojave or macOS High Sierra.
Stars: ✭ 1,027 (+497.09%)
Mutual labels:  itunes
Ytmdl
A simple app to get songs from YouTube in mp3 format with artist name, album name etc from sources like iTunes, Spotify, LastFM, Deezer, Gaana etc.
Stars: ✭ 2,070 (+1103.49%)
Mutual labels:  itunes
Itunes Api
🎵 A simple server providing a RESTful service for controlling iTunes
Stars: ✭ 166 (-3.49%)
Mutual labels:  itunes
Notunes
A simple macOS application that will prevent iTunes or Apple Music from launching.
Stars: ✭ 145 (-15.7%)
Mutual labels:  itunes
Itunes Iap
Apple iTunes In-app purchase verification tool
Stars: ✭ 126 (-26.74%)
Mutual labels:  itunes
IAPHUB

npm npm Shoutem

Implementing and developping all the tools to manage your In-App purchases properly can be very complex and time consuming. You should spend this precious time building your app!

IAPHUB has all the features you need to increase your sales 🚀

Features
📜 Receipt validation - Send the receipt, we'll take care of the rest.
📨 Webhooks - Receive webhooks directly to your server to be notified of any event such as a purchase or a subscription cancellation.
📊 Realtime Analytics - Out of the box insights of on all your sales, subscriptions, customers and everything you need to improve your revenues.
🧪 A/B Testing - Test different pricings and get analytics of which one performs the best.
🌎 Product Segmentation - Offer different product or pricings to your customers depending on defined criterias such as the country.
👤 Customer Management - Access easily the details of a customer, everything you need to know such as the past transactions and the active subscriptions on one page.

Getting started

Implementing In-app purchases in your app should be a piece of cake!
This module implements the IAPHUB API on top of the react-native-iap module 👏

  1. Create an account on IAPHUB

  2. Install the package

// Install react-native-iap which is a required peer dependency (Be sure you install version 5.1.1)
npm install react-native-iap@5.1.1 --save-exact
// Install react-native-iaphub
npm install react-native-iaphub --save
// Update dependency on xcode (in the ios folder)
pod install

Init

Call the init method at the start of your app to initialize your configuration

ℹ️ It should be called as soon as possible when starting your app.

  await Iaphub.init({
    // The app id is available on the settings page of your app
    appId: "5e4890f6c61fc971cf46db4d",
    // The (client) api key is available on the settings page of your app
    apiKey: "SDp7aY220RtzZrsvRpp4BGFm6qZqNkNf",
    // App environment (production by default, other environments must be created on the IAPHUB dashboard)
    environment: "production"
  });

Set user id

Call the setUserId method to authenticate an user.

If you have an authentication system, provide the user id of the user right after the user log in.
If you don't and want to handle IAP on the client side, you can provide the device id when the app start instead by using a module such as react-native-device-info to get a device unique ID.

⚠ You should provide an id that is non-guessable and isn't public. (Email not allowed)

await Iaphub.setUserId("1e5494930c48ed07aa275fd2");

Set user tags

Call the setUserTags method to update the user tags.
User tags will appear on the user page of the IAPHUB dashboard.
When using IAPHUB's smart listings, you'll be able to return different products depending on the user tags.

// To set a tag
await Iaphub.setUserTags({status: 'vip'});
// To clear the user tags
await Iaphub.setUserTags({status: null});

A few details:

  • A tag must be created on the IAPHUB dashboard (otherwise the method will throw an error)
  • When creating a tag on the IAPHUB dashboard you must check the option to allow editing the tag from the client (otherwise you'll only be able to edit the tag using the IAPHUB API from your server)
  • A tag key is limited to 32 characters
  • A tag value is limited to 64 characters

Set device params

Call the setDeviceParams method to set parameters for the device
When using IAPHUB's smart listings, you'll be able to return different products depending on the device params.

// For instance you can provide the app version on app launch
// Useful to return a product only supported in a new version
Iaphub.setDeviceParams({appVersion: '1.2.0'});
// To clear the device params
Iaphub.setDeviceParams({});

A few details:

  • The params are not saved on the device, they won't persist if the app is restarted
  • The params are not saved on IAPHUB, they are just provided to the API when fetching the products for sale
  • A param key limited to 32 characters and must be a valid key (^[a-zA-Z_]*$)
  • A param value limited to 32 characters
  • You can provide up to 5 params

Get products for sale

Call the getProductsForSale method to get the user's products for sale
You should use this method when displaying the page with the list of your products for sale.

⚠ If the request fails because of a network issue, the method returns the latest request in cache (if available, otherwise an error is thrown).

⚠ If a product is returned by the API but the sku cannot be loaded, it'll be filtered from the list and an error message will be displayed in the console

var products = await Iaphub.getProductsForSale();

console.log(products);
[
  {
    id: "5e5198930c48ed07aa275fd9",
    type: "renewable_subscription",
    sku: "membership2_tier10",
    group: "3e5198930c48ed07aa275fd8",
    groupName: "subscription_group_1",
    title: "Membership",
    description: "Become a member of the community",
    price: "$9.99",
    priceAmount: 9.99,
    priceCurrency: "USD",
    subscriptionPeriodType: "normal",
    subscriptionDuration: "P1M"
  },
  {
    id: "5e5198930c48ed07aa275fd9",
    type: "consumable",
    sku: "pack10_tier15",
    title: "Pack 10",
    description: "Pack of 10 coins",
    price: "$14.99",
    priceAmount: 14.99,
    priceCurrency: "USD"
  }
]

Product properties

Prop Type Description
id string Product id (From IAPHUB)
type string Product type (Possible values: 'consumable', 'non_consumable', 'subscription', 'renewable_subscription')
sku string Product sku (Ex: "membership_tier1")
price string Localized price (Ex: "$12.99")
priceCurrency string Price currency code (Ex: "USD")
priceAmount number Price amount (Ex: 12.99)
title string Product title (Ex: "Membership")
description string Product description (Ex: "Join the community with a membership")
group string ⚠ Only available if the product as a group
Group id (From IAPHUB)
groupName string ⚠ Only available if the product as a group
Name of the product group created on IAPHUB (Ex: "premium")
platform string ⚠ Only available for an active product
Platform of the purchase (Possible values: 'ios', 'android')
purchase string ⚠ Only available for an active product
Purchase id (From IAPHUB)
purchaseDate string ⚠ Only available for an active product
Purchase date
subscriptionDuration string ⚠ Only available for a subscription
Duration of the subscription cycle specified in the ISO 8601 format (Possible values: 'P1W', 'P1M', 'P3M', 'P6M', 'P1Y')
expirationDate string ⚠ Only available for an active subscription
Subscription expiration date
autoResumeDate string ⚠ Only available for an android active subscription currently paused
Subscription resume date
isSubscriptionRenewable boolean ⚠ Only available for an active subscription
If the subscription can be renewed
subscriptionState string ⚠ Only available for an active subscription
State of the subscription
(Possible values: 'active', 'grace_period', 'retry_period', 'paused')
subscriptionPeriodType string ⚠ Only available for a subscription
Subscription period type (Possible values: 'normal', 'trial', 'intro')
If the subscription is active it is the current period otherwise it is the period if the user purchase the subscription
subscriptionIntroPrice string ⚠ Only available for a subscription with an introductory price
Localized introductory price (Ex: "$2.99")
subscriptionIntroPriceAmount number ⚠ Only available for a subscription with an introductory price
Introductory price amount (Ex: 2.99)
subscriptionIntroPayment string ⚠ Only available for a subscription with an introductory price
Payment type of the introductory offer (Possible values: 'as_you_go', 'upfront')
subscriptionIntroDuration string ⚠ Only available for a subscription with an introductory price
Duration of an introductory cycle specified in the ISO 8601 format (Possible values: 'P1W', 'P1M', 'P3M', 'P6M', 'P1Y')
subscriptionIntroCycles number ⚠ Only available for a subscription with an introductory price
Number of cycles in the introductory offer
subscriptionTrialDuration string ⚠ Only available for a subscription with a trial
Duration of the trial specified in the ISO 8601 format

Get active products

If you're relying on IAPHUB on the client side (instead of using your server with webhooks) to detect if the user has active products (auto-renewable subscriptions, non-renewing subscriptions or non-consumables), you should use the getActiveProducts method when the app is brought to the foreground.

⚠ If the request fails because of a network issue, the method returns the latest request in cache (if available with no expired subscription, otherwise an error is thrown).

⚠ If an active product is returned by the API but the sku cannot be loaded, the product will be returned but only with the properties coming from the API (The price, title, description.... properties won't be returned).

class App extends Component {

  state = {
    appState: AppState.currentState
  };

  componentDidMount() {
    AppState.addEventListener("change", this.handleAppStateChange);
  }

  componentWillUnmount() {
    AppState.removeEventListener("change", this.handleAppStateChange);
  }

  handleAppStateChange = (nextAppState) => {
    if (
      this.state.appState.match(/inactive|background/) &&
      nextAppState === "active"
    ) {
      var products = await Iaphub.getActiveProducts();
      
      console.log(products);
      [{
        id: "5e5198930c48ed07aa275fd9",
        type: "renewable_subscription",
        sku: "membership1_tier5",
        purchase: "5e5198930c48ed07aa275fe8",
        purchaseDate: "2020-03-11T00:42:28.000Z",
        expirationDate: "2021-03-11T00:42:28.000Z",
        isSubscriptionRenewable: true,
        group: "3e5198930c48ed07aa275fd8",
        groupName: "subscription_group_1",
        title: "Membership",
        description: "Become a member of the community",
        price: "$4.99",
        priceAmount: 4.99,
        priceCurrency: "USD",
        subscriptionState: 'active',
        subscriptionDuration: "P1M",
        subscriptionPeriodType: "intro",
        subscriptionIntroPrice: "$1.99",
        subscriptionIntroPriceAmount: 1.99,
        subscriptionIntroPayment: "as_you_go",
        subscriptionIntroDuration: "P1M",
        subscriptionIntroCycles: 3
      }]
    }
    this.setState({ appState: nextAppState });
  };

  render() {
    return (
      <View>
        <Text>My app</Text>
      </View>
    );
  }
}

Subscription state

Value Description
active The subscription is active
grace_period The subscription is in the grace period, the user should still access the features offered by your subscription
retry_period The subscription is in the retry period, you must restrict the access to the features offered by your subscription and display a message asking for the user to update its payment informations.
paused The subscription is paused (Android only) and will automatically resume at a later date (autoResumeDate property), you must restrict the access to the features offered by your subscription.

By default only subscriptions with an active or grace_period state are returned by the getActiveProducts() method because you must restrict the access to the features offered by your subscription on a retry_period or paused state.

If you're looking to display a message when a user has a subscription on a retry_period or paused state, you can use the includeSubscriptionStates option.

  var allActiveProducts = await iaphub.getActiveProducts({
    includeSubscriptionStates: ['retry_period', 'paused']
  });

Buy a product

Call the buy method to buy a product

ℹ️ The method needs the product sku that you would get from one of the products of getProductsForSale().
ℹ️ The method will process a purchase as a subscription replace if you currently have an active subscription and you buy a subscription of the same group (product group created on IAPHUB).

try {
  var transaction = await Iaphub.buy("pack10_tier15", {
    // Optional callback triggered before the receipt is processed
    onReceiptProcess: (receipt) => {
      console.log('Purchase success, processing receipt...');
    }
  });
  console.log(transaction);
  {
    id: "2e5198930c48ed07aa275fd3",
    type: "consumable",
    sku: "pack10_tier15",
    purchase: "4e5198930c48ed07aa275fd2",
    purchaseDate: "2020-03-11T00:42:27.000Z",
    webhookStatus: "success",
    group: "3e5198930c48ed07aa275fd8",
    groupName: "pack",
    title: "Pack 10",
    description: "Pack of 10 coins",
    price: "$14.99",
    priceAmount: 14.99,
    priceCurrency: "USD"
  }

  /*
   * The purchase has been successful but we need to check that the webhook to our server was successful as well
   * If the webhook request failed, IAPHUB will send you an alert and retry again in 1 minute, 10 minutes, 1 hour and 24 hours.
   * You can retry the webhook directly from the dashboard as well
   */
  if (transaction.webhookStatus == "failed") {
    Alert.alert(
      "Purchase delayed",
      "Your purchase was successful but we need some more time to validate it, should arrive soon! Otherwise contact the support ([email protected])"
    );
  }
  // Everything was successful! Yay!
  else {
    Alert.alert(
      "Purchase successful",
      "Your purchase has been processed successfully!"
    );
  }
} catch (err) {
  // Purchase popup cancelled by the user (ios only)
  if (err.code == "user_cancelled") return
  // Couldn't buy product because it has been bought in the past but hasn't been consumed (restore needed)
  else if (err.code == "product_already_owned") {
    Alert.alert(
      "Product already owned",
      "Please restore your purchases in order to fix that issue",
      [
        {text: 'Cancel', style: 'cancel'},
        {text: 'Restore', onPress: () => Iaphub.restore()}
      ]
    );
  }
  // The payment has been deferred (its final status is pending external action such as 'Ask to Buy')
  else if (err.code == "deferred_payment") {
    Alert.alert(
      "Purchase awaiting approval",
      "Your purchase has been processed but is awaiting approval"
    );
  }
  /*
   * The receipt has been processed on IAPHUB but something went wrong
   * It is probably because of an issue with the configuration of your app or a call to the Itunes/GooglePlay API that failed
   * IAPHUB will send you an email notification when a receipt fails, by checking the receipt on the dashboard you'll find a detailed report of the error
   * After fixing the issue (if there's any), just click on the 'New report' button in order to process the receipt again
   * If it is an error contacting the Itunes/GooglePlay API, IAPHUB will retry to process the receipt automatically as well
   */
  else if (err.code == "receipt_validation_failed") {
    Alert.alert(
      "We're having trouble validating your transaction",
      "Give us some time, we'll retry to validate your transaction ASAP!"
    );
  }
  /*
   * The receipt has been processed on IAPHUB but is invalid
   * It could be a fraud attempt, using apps such as Freedom or Lucky Patcher on an Android rooted device
   */
  else if (err.code == "receipt_invalid") {
    Alert.alert(
      "Purchase error",
      "We were not able to process your purchase, if you've been charged please contact the support ([email protected])"
    );
  }
  /*
   * The receipt hasn't been validated on IAPHUB (Could be an issue like a network error...)
   * The user will have to restore its purchases in order to validate the transaction
   * An automatic restore should be triggered on every relaunch of your app since the transaction hasn't been 'finished'
   * Android should automatically refund transactions that are not 'finished' after 3 days
   */
  else if (err.code == "receipt_request_failed") {
    Alert.alert(
      "We're having trouble validating your transaction",
      "Please try to restore your purchases later (Button in the settings) or contact the support ([email protected])"
    );
  }
  /*
   * The user has already an active subscription on a different platform (android or ios)
   * This security has been implemented to prevent a user from ending up with two subscriptions of different platforms
   * You can disable the security by providing the 'crossPlatformConflict' parameter to the buy method (Iaphub.buy(sku, {crossPlatformConflict: false}))
   */
  else if (err.code == "cross_platform_conflict") {
    Alert.alert(
      `Seems like you already have a subscription on ${err.params.platform}`,
      `You have to use the same platform to change your subscription or wait for your current subscription to expire`
    );
  }
  // Couldn't buy product for many other reasons (the user shouldn't be charged)
  else {
    Alert.alert(
      "Purchase error",
      "We were not able to process your purchase, please try again later or contact the support ([email protected])"
    );
  }
}

Proration mode (Android only)

You can specify the proration mode when replacing a subscription.

var transaction = await Iaphub.buy("membership_tier1", {
  prorationMode: 'immediate_and_charge_prorated_price'
});
Value Description
immediate_with_time_proration The replacement takes effect immediately, the remaining time will be prorated for the new subscription. (default)
immediate_and_charge_prorated_price The replacement takes effect immediately, the price of the previous subscription will be prorated (partial refund).
immediate_without_proration The replacement takes effect immediately with no extra charge, the new price will be charged on next recurrence time.
deferred The replacement takes effect when the current subscription expires

Restore user purchases

Call the restore method to restore the user purchases

ℹ️ You should display a restore button somewhere in your app (usually on the settings page).
ℹ️ If you logged in using the device id, an user using a new device will have to restore its purchases since the device id will be different.

await Iaphub.restore();

Full example

You should check out the Example app.

FAQ

I'm already validating receipts on my server, can I run receipt validation on both my server and IAPHUB?

Yes! It can be pretty handy if you want to:

  • Slowly migrate over IAPHUB
  • Give IAPHUB a try without shutting down your current receipt validation system
  • Implement a fallback system to validate receipts when an error occurs
  • Run both systems in parallel

It's easy to implement by using the onReceiptProcessed event that is triggered after IAPHUB processed a receipt

  await Iaphub.init({
    appId: "5e4890f6c61fc971cf46db4d",
    apiKey: "SDp7aY220RtzZrsvRpp4BGFm6qZqNkNf",
    environment: "production"
    /*
     * Event triggered after IAPHUB processed a receipt
     * @param {Object} err Error object if the receipt processing failed (otherwise null)
     * @param {Object} receipt - Receipt object
     * @param {String} receipt.sku - Product sku
     * @param {String} receipt.token - Receipt token
     * @param {Boolean} receipt.isRestore - If the event is triggered from a restore
     */
    onReceiptProcessed: async (err, receipt) => {
      console.log(receipt);
      {
        sku: "pack10_tier15",
        token: "dzw4d....sd",
        isRestore: false
      }
      /*
       * Send the receipt to yout server
       * If you want to override the transaction returned by the buy method, your server must return the new transactions of the receipt
       * Warning: Do not return the old transactions already processed!
       */
      var newTransactions = await fetch("https://api.myapp.com/receipt", {
        method: "POST",
        headers: {'Accept': 'application/json', 'Content-Type': 'application/json'},
        body: JSON.stringify(receipt)
      });
      console.log(newTransactions);
      [{
        sku: "pack10_tier15"
      }]
      /*
       * If an array is returned by this function it'll override the receipt transactions returned by IAPHUB
       * For instance, below we only override the transactions if the receipt processing failed with an error
       * A transaction must contain at least the property 'sku' in order to identify the transaction that will be returned from the buy method
       */
      if (err) {
        return newTransactions;
      }
    }
  });
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].