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

Add in-app purchase for MacOS #11292

Merged
merged 17 commits into from Jan 10, 2018

Conversation

Projects
None yet
10 participants
@AdrienFery
Contributor

AdrienFery commented Nov 30, 2017

In order to release a commercial application on the Mac Apple Store, it must use in-app purchase (see App Store Guidelines). It is why I have added the in-app purchase feature for MacOS into Electron. I have tested the build and it works well but I didn't implement automatic tests.

Let me know if you see some modifications to do.

See in-app-purchase.md for the module documentation.

screen shot

@AdrienFery AdrienFery requested review from electron/docs as code owners Nov 30, 2017

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Nov 30, 2017

Looking forward to seeing this in production... a much needed feature for Electron!

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Nov 30, 2017

Can anyone merge this or tell me what needs to be done before it can be merged?

@jkleinsc

@AdrienFery it looks like our CI is failing because of incorrectly formatted code. You can run npm run lint locally to identify the formatting issues.

'atom/browser/in_app_purchase.h',
'atom/browser/in_app_purchase_mac.mm',
'atom/browser/in_app_purchase_observer.h',
'atom/browser/in_app_purchase_observer_mac.mm',
'atom/browser/atom_browser_main_parts.cc',
'atom/browser/atom_browser_main_parts.h',
'atom/browser/atom_browser_main_parts_mac.mm',

This comment has been minimized.

@alexeykuzmin

alexeykuzmin Nov 30, 2017

Contributor

This feature will never be used on any platform other than macOS,
can you please put all of its files under a OS check at the bottom of the file?
You will need to create a new section ['OS=="mac"', { right under the ['OS=="win"', {.

UPD Files with "_mac" suffix are already fine, they won't used on any other platform,
but I guess we need to filter the other files too.

}
if (typeof callback !== 'function') {
callback = function() {};

This comment has been minimized.

@alexeykuzmin

alexeykuzmin Nov 30, 2017

Contributor

Please handle absence of a callback on the native side.
It doesn't make much sense to create and call an empty function.

return binding.getReceiptURL();
},
purchaseProduct: function(productID, quantity, callback) {

This comment has been minimized.

@alexeykuzmin

alexeykuzmin Nov 30, 2017

Contributor

If you want to allow this method to be called in forms
purchaseProduct(someId, 2) and purchaseProduct(someId, function() {}),
you will have to check the type of the second argument to decide if it is quantity or callback.

You can do it like this:

if (typeof quantity == 'function') {
  quantity = 1
  callback = quantity
}
@@ -8,6 +8,7 @@ module.exports = [
{name: 'dialog', file: 'dialog'},
{name: 'globalShortcut', file: 'global-shortcut'},
{name: 'ipcMain', file: 'ipc-main'},
{name: 'inAppPurchase', file: 'in-app-purchase'},

This comment has been minimized.

@alexeykuzmin

alexeykuzmin Nov 30, 2017

Contributor

It also should be available on macOS only.

This comment has been minimized.

@AdrienFery

AdrienFery Dec 1, 2017

Contributor

What should I do to restrict this to macOS only ?

This comment has been minimized.

@alexeykuzmin

alexeykuzmin Dec 1, 2017

Contributor

Oh, there's not existing way to do it. I guess I or somebody else can add it after this PR is merged.
Let's skip it for now.

@alexeykuzmin

This comment has been minimized.

Contributor

alexeykuzmin commented Nov 30, 2017

but I didn't implement automatic tests.

It means that it will be broken soon.

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Dec 1, 2017

@alexeykuzmin Any idea how to implement automatic tests ? I don't think that it is possible to interact with the Apple Store Dialog to sign in and to confirm the purchase.

@alexeykuzmin

This comment has been minimized.

Contributor

alexeykuzmin commented Dec 1, 2017

Any idea how to implement automatic tests ? I don't think that it is possible to interact with the Apple Store Dialog to sign in and to confirm the purchase.

@zcbenz @deepak1556 any ideas how this feature can be tested?

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Dec 2, 2017

The built on jenkins failed. I don't understand why. I just tested to built on my Mac and it works.

@jkleinsc

This comment has been minimized.

Contributor

jkleinsc commented Dec 4, 2017

@AdrienFery Electron uses the macOS 10.10 SDK to build (see https://electronjs.org/docs/development/build-instructions-osx#macos-sdk) which is why the build failed in CI. This code change needs to be compatible with the macOS 10.10 SDK.

@zcbenz zcbenz self-assigned this Jan 10, 2018

@zcbenz

This comment has been minimized.

Contributor

zcbenz commented Jan 10, 2018

Currently we don't have a way to test things that require code sign, we are simply relying on users to test them, for example the Handoff feature and the Mac App Store build.

I'll add a few simple tests for the APIs to verify the methods actually exist.

@zcbenz

This comment has been minimized.

Contributor

zcbenz commented Jan 10, 2018

I'm going to turn inAppPurchase to an EventEmitter to make it easier to extend the APIs in future.

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Jan 11, 2018

@zcbenz Ok. Is it possible to somehow build a production ready app using the GitHub master branch of electron?

@sferoze

This comment has been minimized.

sferoze commented Jan 18, 2018

@holgersindbaek @zcbenz I am with you here. I would like to build a production-ready app which includes this merge for IAP.

I need to submit my app ASAP, so being able to just build and use this version would be great. Currently, I use the production version of electron using NPM. In the past, I have added NPM packages which point to git URLs. Wonder if that is possible here... or if we need to build it first?

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Jan 18, 2018

@sferoze I've tried to see if I could build a production app using the GitHub version of Electron, but it doesn't seem to be possible. Electron seem to always use the officiel version of Electron to build for production.

You can build for development using the GitHub version, but not for production.

@sferoze

This comment has been minimized.

sferoze commented Jan 18, 2018

@holgersindbaek thanks a lot for the info. this was really helpful in bringing light to the current status of the issue

@nabati

This comment has been minimized.

nabati commented Jan 25, 2018

Thank you for the PR, it's been educational.

We have another use case which also makes use of StoreKit; according to Apples guidelines, it won't be allowed to have custom prompts that request reviews, but one should make use of the requestReview method.

I'm wondering

  • If exposing that method can fit within this module as it is.
  • If exposing that method would fit in this module if it was renamed to something more general such as StoreKit, and move the existing methods to StoreKit.inAppPurchase.
  • If we should create a separate module for that thin slice of the API.

What are you're thoughts?

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Jan 28, 2018

If you want to add more StoreKit features, I think that the module should be renamed to something more general.

@sferoze

This comment has been minimized.

sferoze commented on 6d9c664 Jan 30, 2018

@zcbenz I was reviewing the API for in app purchase and see no method for subscriptions. Does the API only support one time purchases, or can we do subscriptions as well? If so how?

This comment has been minimized.

Contributor

zcbenz replied Feb 1, 2018

I don't think this API can be used for subscriptions, we only exposed a small set of native purchase APIs.

This comment has been minimized.

sferoze replied Feb 1, 2018

@zcbenz Any way I can expand it to include subscriptions. I have an app that runs on all platforms and I cannot put my app in the mac app store unless I use apple subscriptions. This is the same with any developer who wants to put their app in mac app store.

This comment has been minimized.

Contributor

zcbenz replied Feb 2, 2018

If you know Objective-C you can try to implement the feature and create a pull request, this feature was contributed by other developers(#11292), I don't have a plan for adding purchase APIs myself.

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Feb 16, 2018

Any news on when this will go into the official version of Electron?

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Feb 20, 2018

@sferoze In StoreKit, In-App Purchase doesn't have any subscription method. You can use subscription directly with this implementation.

The SKProductSubscriptionPeriod class contains only information about the subscription duration of the product.

Class SKProductSubscriptionPeriod
An object containing the subscription period duration information.

@zeke

This comment has been minimized.

Member

zeke commented Feb 20, 2018

@holgersindbaek we are shooting for a 2.0 beta this week. If I'm not mistaken, this change should land in that release.

@yuri-karkh

This comment has been minimized.

yuri-karkh commented Feb 25, 2018

Hi guys, is there any guide exists? I try to const remote = require( 'electron' ).remote and remote.inAppPurchase.addTransactionListener is undefined, I don't see this method neither via console.log( remote.inAppPurchase ). Any advice?
inapppurchase object

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Feb 27, 2018

Remark: I have added a method GetProducts to this module in my local fork. It allows to get the products (see SKProduct) and the local formatted price of the product. I will create a pull request pretty soon to add this feature and to improve the documentation.

@yuri-karkh Which version of Electron do you use ?

@yuri-karkh

This comment has been minimized.

yuri-karkh commented Feb 27, 2018

I used 2.0.0-beta1 @AdrienFery as it was released only in this new version

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Feb 27, 2018

@yuri-karkh You should listen for the transactions-updated event instead.

const remote = require( 'electron' ).remote;
remote.inAppPurchase.on('transactions-updated', transactionListener);
@zeke

This comment has been minimized.

Member

zeke commented Feb 27, 2018

I will create a pull request pretty soon to add this feature and to improve the documentation.

👍

If you could also add a short tutorial in docs/tutorial/in-app-purchases.md with some basic sample code, that would be 💯

@AdrienFery AdrienFery deleted the AdrienFery:in-app-purchase branch Mar 8, 2018

@yuri-karkh

This comment has been minimized.

yuri-karkh commented Mar 26, 2018

Hi @AdrienFery, could u please advice:
require('electron').remote.inAppPurchase.purchaseProduct("some.product.id",1,function(e){}); calling this method has no any effect as I see, is there anything else I should care about before this call? (v2.0.0-beta5)

@yuri-karkh

This comment has been minimized.

yuri-karkh commented Apr 6, 2018

hi @AdrienFery sorry to bother u again, but have a question again if u have a minute:
I use electron@2.0.0-beta.7, I have changed Info.plist to my bundle id (double checked) and when I calling inAppPurchase.productPurchase nothing happens now. Also tested canMakePayments, getReceiptURL methods they look ok. No errors in console.

console

@AdrienFery

This comment has been minimized.

Contributor

AdrienFery commented Apr 6, 2018

@yuri-karkh What is your bundleID and your productID ?

@yuri-karkh

This comment has been minimized.

yuri-karkh commented Apr 6, 2018

bundleID = "com.gentlereader.dev" and productID = "demoprod" @AdrienFery

@JeganMSD

This comment has been minimized.

JeganMSD commented Jun 23, 2018

As @yuri-karkh said there is no method like getProducts.. @AdrienFery ...
Would you please provide the detailed Tutorial so that developers would feel easy to use this package.

@JeganMSD

This comment has been minimized.

JeganMSD commented Jun 23, 2018

Thread

23 Crashed:: Dispatch queue: SKProductsRequest reply queue
0 libobjc.A.dylib 0x00007fff8dfbd097 objc_msgSend + 23
1 com.apple.StoreKit 0x0000000106324421 -[SKRequest _sendFinishToDelegate] + 55
2 com.apple.StoreKit 0x00000001063240f4 -[SKRequest _sendFinishedForUserInfo:] + 207
3 com.apple.StoreKit 0x00000001063236ab __47-[SKProductsRequest issueRequestForIdentifier:]_block_invoke + 53
4 libxpc.dylib 0x00007fff948c25cc _xpc_connection_call_event_handler + 58
5 libxpc.dylib 0x00007fff948c11df _xpc_connection_mach_event + 2124
6 libdispatch.dylib 0x00007fff9931eae2 _dispatch_client_callout4 + 9
7 libdispatch.dylib 0x00007fff9931f39c _dispatch_mach_msg_invoke + 143
8 libdispatch.dylib 0x00007fff9931d617 _dispatch_queue_drain + 359
9 libdispatch.dylib 0x00007fff9931e682 _dispatch_mach_invoke + 154
10 libdispatch.dylib 0x00007fff9931d617 _dispatch_queue_drain + 359
11 libdispatch.dylib 0x00007fff9931e9c1 _dispatch_queue_invoke + 110
12 libdispatch.dylib 0x00007fff9931cf87 _dispatch_root_queue_drain + 75
13 libdispatch.dylib 0x00007fff9931e177 _dispatch_worker_thread2 + 40
14 libsystem_pthread.dylib 0x00007fff9624fef8 _pthread_wqthread + 314
15 libsystem_pthread.dylib 0x00007fff96252fb9 start_wqthread + 13

I'm getting this error while I called purchaseProduct()

@JeganMSD

This comment has been minimized.

JeganMSD commented Jun 23, 2018

Waiting for your faster reply @AdrienFery .Thanks in advance

@sferoze

This comment has been minimized.

sferoze commented Jun 23, 2018

@JeganMSD @yuri-karkh

With the purchaseProduct() method, you can console.log the response in the callback. It should be true or false if product is valid or not.

This is working for me but the issue I am having is that the response says the product is invalid. Even though I have gone into iTunes Connect and added the subscription just like I have done for iOS.

I think the issue is that you need to call getProducts() before purchaseProduct() otherwise it will always return as an invalid product. @AdrienFery is this correct. You added the getProducts() method and that needs to be called before purchaseProduct() for purchaseProduct() to work?

@JeganMSD

This comment has been minimized.

JeganMSD commented Jun 24, 2018

yes @sferoze now working fine.I will ask you doubts during development.Thanks for your reply

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment