Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to manage subscribed users? #862

Closed
wmonecke opened this issue Nov 23, 2019 · 8 comments
Closed

How to manage subscribed users? #862

wmonecke opened this issue Nov 23, 2019 · 8 comments
Labels
🙏 help wanted Extra attention is needed ❓ question Further information is requested

Comments

@wmonecke
Copy link

Hi!
I am having a bit of trouble planning how the flow of the information should be.
How can I know if my user has paid for a subscription and would this method work offline?
Should I always check the result of said method to update the apps state to a premium version or how should I go about it? Sorry if the question is a bit broad. Any help is welcome.

@hyochan hyochan added 🙏 help wanted Extra attention is needed ❓ question Further information is requested labels Nov 24, 2019
@hyochan
Copy link
Owner

hyochan commented Nov 24, 2019

There is related post in react-native-iap repo. The idea is, you should check the receipt. Since checking receipt requires the internet, I don't think it is possible offline. Please update me if I am outdated.

@wmonecke
Copy link
Author

@hyochan I read the whole thread and see they are having my same issues.
I thought Apple/Google would handle the subscription status for us (online or offline) but I will just save the receipt in my own server and then recheck its validity every time the app starts up.

@wmonecke
Copy link
Author

wmonecke commented Nov 24, 2019

@hyochan

I have another issue that might be stupid but is driving me nuts. I read the related post and I am implementing the posted method to get to know if the user is a paying user:

import * as RNIap from 'react-native-iap';
import {ITUNES_CONNECT_SHARED_SECRET} from 'react-native-dotenv';

const SUBSCRIPTIONS = {
  // This is an example, we actually have this forked by iOS / Android environments
  ALL: ['monthlySubscriptionId', 'yearlySubscriptionId'],
}

async function isSubscriptionActive() {
  if (Platform.OS === 'ios') {
    const availablePurchases = await RNIap.getAvailablePurchases();
    const sortedAvailablePurchases = availablePurchases.sort(
      (a, b) => b.transactionDate - a.transactionDate
    );
    const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;

    const isTestEnvironment = __DEV__;
    const decodedReceipt = await RNIap.validateReceiptIos(
      {
        'receipt-data': latestAvailableReceipt,
        password: ITUNES_CONNECT_SHARED_SECRET,
      },
      isTestEnvironment
    );
    const {latest_receipt_info: latestReceiptInfo} = decodedReceipt;
    const isSubValid = !!latestReceiptInfo.find(receipt => {
      const expirationInMilliseconds = Number(receipt.expires_date_ms);
      const nowInMilliseconds = Date.now();
      return expirationInMilliseconds > nowInMilliseconds;
    });
    return isSubValid;
  }

  if (Platform.OS === 'android') {
    // When an active subscription expires, it does not show up in
    // available purchases anymore, therefore we can use the length
    // of the availablePurchases array to determine whether or not
    // they have an active subscription.
    const availablePurchases = await RNIap.getAvailablePurchases();

    for (let i = 0; i < availablePurchases.length; i++) {
      if (SUBSCRIPTIONS.ALL.includes(availablePurchases[i].productId)) {
        return true;
      }
    }
    return false;
  }
} 

However, the following method is not working for me. I am working on iOS right now and when I call
const availablePurchases = await RNIap.getAvailablePurchases(); I get prompted to Sign In into iTunes (even though I am already signed in with my Apple Id). When putting in the credentials nothing else happens and just get this error after a while:

Cannot connect to iTunes Store
    at createErrorFromErrorData (NativeModules.js:152)
    at NativeModules.js:104
    at MessageQueue.__invokeCallback (MessageQueue.js:442)
    at MessageQueue.js:127
    at MessageQueue.__guard (MessageQueue.js:343)
    at MessageQueue.invokeCallbackAndReturnFlushedQueue (MessageQueue.js:126)
    at debuggerWorker.js:80

I don't know what to do. I made a Sandbox user and tried signing in with those credentials as well and it didn't work. Do you have any idea or hint why this is not working?

Thank you for your time and patience!!

@hyochan
Copy link
Owner

hyochan commented Nov 25, 2019

The prompted to Sign In into iTunes only appears in the debug scheme. I am not sure what's going on internally in your case. Trying out for a different user, or doing the whole step once again would help I think.

Also, try out for live purchase either. Sometimes it is hard to track the mistake because there are several things to go over carefully such as is wifi on? Have you signed out for a newly updated tax agreement? and so on.

@wmonecke
Copy link
Author

wmonecke commented Nov 25, 2019

@hyochan

Screenshot 2019-11-25 at 15 42 42

I did agree to the new tax agreement, however I just added the bank account yesterday and it says the status is active (but pending)? Is this also crucial to be able to test iap (i.e. the dot has to be green)?

I reset the iPhone Simulator with no user signed-in in the Settings app. I loaded the component that allows in app purchases and got my subscriptions with const subscriptions = await RNIap.getSubscriptions(itemSubs)

You should be able to test on a simulator right?

When I press to actually make the purchase of a sub it instantly throws the following error (When I was expecting the prompt to Sign-in into iTunes):

Error requesting Subscription Error: Cannot connect to iTunes Store
    at createErrorFromErrorData (NativeModules.js:152)
    at NativeModules.js:104
    at MessageQueue.__invokeCallback (MessageQueue.js:442)
    at MessageQueue.js:127
    at MessageQueue.__guard (MessageQueue.js:343)
    at MessageQueue.invokeCallbackAndReturnFlushedQueue (MessageQueue.js:126)

This is also a new sandbox user since I read that trying to log in with an account into your iPhone will reject said account.

@alexpchin
Copy link

Have you logged into the Sandbox on iTunes account? https://developer.apple.com/apple-pay/sandbox-testing/

@wmonecke
Copy link
Author

Have you logged into the Sandbox on iTunes account? https://developer.apple.com/apple-pay/sandbox-testing/

I had to test it on an iPhone and not the simulator. Apparently, it has worked before but on iOS 12.4 you cant test IAP in the Simulator.

@bang9
Copy link
Contributor

bang9 commented Nov 27, 2019

@wmonecke
*tip
you should check cancellation_date field in iOS latestReceiptInfo receipt

// The time Apple customer support canceled a transaction
// in a date-time format similar to the ISO 8601. This field is only present for refunded transactions.
const nonCancelledReceiptsInfo: = latestReceiptInfo.filter(
   receipt => !receipt.cancellation_date
);

@hyochan hyochan closed this as completed Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🙏 help wanted Extra attention is needed ❓ question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants