chirag04 / react-native-in-app-utils

A react-native wrapper for handling in-app payments
MIT License
890 stars 185 forks source link

Listen for purchase events + optional promise support + other updates #128

Open superandrew213 opened 6 years ago

superandrew213 commented 6 years ago

Updates:

* breaking change

To install and test:

npm i --save https://github.com/superandrew213/react-native-in-app-utils#listen-for-purchase-event

To trigger purchase initiated from App Store, open this link in safari. Replace bundleId and productIdentifier with your own.

itms-services://?action=purchaseIntent&bundleId=com.example.app&productIdentifier=product_name
jeremyhicks commented 6 years ago

@superandrew213 I tested on the device for In-App purchases using the itms link and it works great. Thanks for also setting up index.js that makes it easier to use. I'm actually submitting to the App Store tonight.

chirag04 commented 6 years ago

awesome! i will find some time over the weekend for this.

jeremyhicks commented 6 years ago

@superandrew213 and @chirag04 I discovered an issue. My app has a Keyboard Extension target that bundles and runs the RN app. The extension crashes with this updated code in place. I have more discovery to do but wanted to let you know. I do not use this package in the code running inside of the extension, that is not allowed anyway, but having it linked and available is causing it to crash.

superandrew213 commented 6 years ago

@jeremyhicks what is the error output?

jeremyhicks commented 6 years ago

@superandrew213 I wasn't getting any in the console. I need to explore further. When opening the Keyboard Extension it would crash. Debugging that is not easy.

jeremyhicks commented 6 years ago

@superandrew213 @chirag04 I have found the source of the issue when this library is included in a project that gets bundled in an iOS extension. The libInAppUtils.a library still needs to be included even though the extension itself doesn't support IAP. I've updated my apps to use this branch and it is working good, no crashes.

superandrew213 commented 6 years ago

@chirag04 will you have some time soon to take this in soon? I've had it in a production app for over 3 weeks now and have had no issues.

chirag04 commented 6 years ago

@superandrew213 sorry i haven't had a chance to look at it yet. i'm still planning to review and merge this soon.

superandrew213 commented 6 years ago

@chirag04 sure no problem!

merryejik commented 6 years ago

Hi! Any changes here?

merryejik commented 6 years ago

@superandrew213 I started test your solution, but this link don't work for me itms-services://?action=purchaseIntent&bundleId=com.example.app&productIdentifier=product_name (with my bundleId and productIdentifier, for purchase testing).

I use your branch and subscribe on events as written in your readme.

superandrew213 commented 6 years ago

@merryejik what happens when you press the link? Does it open your app?

merryejik commented 6 years ago

No...

superandrew213 commented 6 years ago

Hmm there must be something wrong with your bundleId.

Paste this in your safari browser on your phone and make sure you have the right bundleId. Just to trigger app to open productIdentifier doesn't matter as long as you have a value.

itms-services://?action=purchaseIntent&bundleId=com.example.app&productIdentifier=product_name
merryejik commented 6 years ago

Safari wants to open this link in iTunes and opens nothing after that. I will investigate SKPaymentTransactionObserver more carefully. Maybe there is need to be some changes in Info.plist or in AppDelegate?

raduflp commented 6 years ago

would love to see this merged

NipperInShorts commented 6 years ago

Excited for this. Any new updates?

christophby commented 6 years ago

@superandrew213 I always get the following error when I call addEventListener :

InAppUtils.addListener was called with 2 arguments but expects 1 arguments. If you haven't changed this method yourself, this usually means that your versions of the native code and JavaScript code are out of sync. Updating both should make this error go away.

I call it as mentioned in your README:

InAppUtils.addListener('PurchaseCompleted',` purchase => { console.log('PurchaseCompleted'); if (purchase && purchase.productIdentifier) { alert('Purchase Successful', 'Your Transaction ID is ' + purchase.transactionIdentifier); //unlock store here. } });

superandrew213 commented 6 years ago

@christophby copy and paste this and try again:

InAppUtils.addListener('PurchaseCompleted', purchase => {
  if(purchase && purchase.productIdentifier) {
      Alert.alert('Purchase Successful', 'Your Transaction ID is ' + purchase.transactionIdentifier);
      //unlock store here.
   }
});
superandrew213 commented 6 years ago

@chirag04 any news on this?

chirag04 commented 6 years ago

hey @superandrew213, haven't had a chance to look at it. It would be nice if somebody here can review and test it.

rodrigopk commented 6 years ago

Looking forward to see this merged. @merryejik Had a similar problem as you, which was caused by trying to open the url using an old device (iPhone 5c, which cannot update the OS past version 10.3.3).

rodrigopk commented 6 years ago

@superandrew213 @chirag04 I was trying to use those changes but ran into a problem when trying to add a listener with the following code:

InAppUtils.addListener('purchaseCompleted', purchase => {
  if (purchase && purchase.productIdentifier) {
    console.log(
      `Purchase Successful, Your Transaction ID is ${purchase.transactionIdentifier}`,
    );
  }
});

The problem seems to be related to InAppUtilsEmitter. When it calls the calls the addListener method:

  addListener(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
   if (Platform.OS === 'ios') {
      invariant(nativeModule, 'Native module cannot be null.');
      this._nativeModule = nativeModule;
    }
    return super.addListener(eventType, listener, context);
  }

this._nativeModule is not defined and this throws an error. I'm using react-native v0.47.2. The implementation of this method in NativeEventEmitter in a later version (v0.54.0-rc.2), but I could not test it on newer versions, so I cannot guarantee it can not be reproduced after this one.

Eyesonly88 commented 6 years ago

Hey @chirag04 and @superandrew213 great work on this. I'm just wondering is it possible to just have the "Listen for purchase events" feature merged and split the remaining work into another PR? Thanks.

adamski commented 6 years ago

I agree this PR should be split up if possible, so we can have the purchase events feature merged in.

idris commented 6 years ago

@superandrew213 this needs to piggy-back off of #135 and force the user to call finishTransaction.

Use case: If the user purchases something from the appstore, we need to notify our back-end, and verify that it worked before calling finishTransaction.

idris commented 6 years ago

I added a comment on #135 with how I think the API should work: https://github.com/chirag04/react-native-in-app-utils/pull/135#issuecomment-383614510

Happy to help implement if we think this is the right direction.

clementinoux commented 5 years ago

Hi everyone,

I read all the stuff. I'm not sure... Finally, is there a working way to listen in-app coming from the store ? If so, how to ? Does the branch will be merge soon?

Thanks a lot,

superandrew213 commented 5 years ago

@clementinoux yes, but you have to use my fork.

npm i --save https://github.com/superandrew213/react-native-in-app-utils#listen-for-purchase-event

You can see how here: https://github.com/superandrew213/react-native-in-app-utils/tree/listen-for-purchase-event#listen-for-purchase-events

I use my fork in production and haven't had any issues.

jeremyhicks commented 5 years ago

How's this coming along? Do you need more test coverage or any other contributions?

andreiciceu commented 5 years ago

With react-native 0.56, this happens: TypeError: Cannot read property 'addSubscription' of undefined at Object.addListener

replacing index.js:45 with: addListener: (event, cb, context) => InAppUtilsEmitter.addListener(event, cb, context), seems to fix it

superandrew213 commented 5 years ago

Thanks @andreiciceu

Dexwell commented 5 years ago

This should be merged asap

andreiciceu commented 5 years ago

@superandrew213 great work; i'm currently using this branch as more and more user seem to be purchasing from AppStore.

Adding the following at line 46 would be useful:

removeListener: (event, cb, context) => InAppUtilsEmitter.removeListener(event, cb, context),
superandrew213 commented 5 years ago

@andreiciceu you should be able to do:

const listener = InAppUtils.addListener(...)
listener.remove();

Does this not work for you?

andreiciceu commented 5 years ago

@superandrew213 yes, it works perfectly Many thanks! Also, latest changes from chirag04:master can be merged, to work with new RN versions without warnings (mainly Main queue setup warning)

Dexwell commented 5 years ago

@superandrew213 Those latest additions are fantastic. Is there a way to get unfinished purchases, e.g. on start or resume, so I can unlock stuff server-side, and then call InAppUtils.finishCurrentTransaction()?

Since this package is on life support, have you considered publishing and maintaining your fork as your own package on NPM, e.g. as react-native-in-app-purchases?

superandrew213 commented 5 years ago

@Dexwell that's plan. Just haven't had any time. So it has been easier & faster to just use github fork for now.

Have you tried InAppUtils.addListener('purchaseCompleted', purchase => ...) on app start?

Or do you mean for purchases that are still in purchasing state?

Dexwell commented 5 years ago

Or do you mean for purchases that are still in purchasing state?

Yeah

chirag04 commented 5 years ago

@superandrew213 This PR is looking great! I won't have the time review it further or merge. Would you be interested in managing this library?

superandrew213 commented 5 years ago

@chirag04 I just don't have the time to maintain it. I am just adding the features that I need.

It might not be best to merge this since it is a breaking change. If we will be doing a breaking change then we should consider using events (while still supporting callbacks if possible). This PR is heading towards that direction.

I will continue working on it. When it is ready, then we can release it as v7.

pennersr commented 5 years ago

With these changes I am able to catch auto renewable subscriptions on application startup just fine by listening for the purchaseCompleted event. However, this event is also emitted for regular purchases (as in, purchases that are user initiated through purchaseProduct).

@superandrew213 Is there some way of distinguishing the automatic events from the user initiated ones?

superandrew213 commented 5 years ago

@pennersr you can track the purchases that have been processed by using the transactionId.

Otherwise you could remove the listener as soon as you have caught the subscription purchase initiated from the AppStore. You could also set a timeout incase there are no purchases.

pennersr commented 5 years ago

@superandrew213 I am not sure how you would use transactionId reliably, as it assumes a certain ordering. For example, when the user initiates InAppUtils.purchaseProduct() and a transaction ID is received from it, one cannot be certain that the purchaseCompleted event did not already emit that very same transaction ID first, unless, ofcourse, we can rely on ordering here. Using timeouts or unsubscribing feels a bit kludgy.

superandrew213 commented 5 years ago

@pennersr the callback will be triggered first.

Eyesonly88 commented 5 years ago

Hey @superandrew213, thank you for all your work. I'm wondering, what's left on this PR to get it merged? and if this is not going to be merged and stay here, how would someone use it (since you mention there are breaking changes)? Any docs would be appreciated.

superandrew213 commented 5 years ago

@Eyesonly88 you can install it like this:

yarn add https://github.com/superandrew213/react-native-in-app-utils#listen-for-purchase-event

or

npm i https://github.com/superandrew213/react-native-in-app-utils#listen-for-purchase-event

The docs on my fork tell you how to use it. I have kept them updated.

The only breaking changes are related to how errors are handled. My fork returns error objects instead of just a string.

thanakij commented 3 years ago

Just came across this, @superandrew213 so while we are waiting for v7.

How about changing your default branch in your repo from master to listen-for-purchase-event for now. This would definitely help improve the visibility of your doc (especially, on the listener part).

superandrew213 commented 3 years ago

@thanakij done 🙂

caifu23 commented 2 years ago

In-app purchase, after the product has been purchased and paid for. I didn't call finishTransaction to end the transaction. Why can't I get the pending transaction the next time I come in and print an empty array