bizz84 / SwiftyStoreKit

Lightweight In App Purchases Swift framework for iOS 8.0+, tvOS 9.0+ and macOS 10.10+ ⛺
MIT License
6.55k stars 796 forks source link

mac app, SwiftyStoreKit.purchaseProduct, callback has never been executed #98

Open womandroid opened 7 years ago

womandroid commented 7 years ago

hi, i use the following code to purchase non consumable product for my mac app, at the beginning, everything is ok: i fill the test account and password, click confirmation buttons and so on, but after I confirm the last dialog, i wait and wait and wait, but nothing is happend, the callback has never been executed. i try again and again and again, but every time is the same. what should i do? did I do something wrong? thanks.

SwiftyStoreKit.purchaseProduct(productIdentifier) { (result) in
    print(result) //the code here has never been executed
}

Now i found that i should use a new test account to purchase the product, if the account has purchased the product already, the callback will not be executed. what should i do if i want the callback always be executed?

bizz84 commented 7 years ago

If you try to purchase a non-consumable product again on iOS, you always get a message confirming that you will not be charged again, and if you continue the callback will be called.

I'm not sure if there are differences on this between iOS and macOS. More investigation needed.

bizz84 commented 7 years ago

There have been some major improvements to the purchase flows recently.

@womandroid Could you retest this on version 0.8.0?

If this issue is not updated in the next few weeks I'll assume everything works fine and will close it.

womandroid commented 7 years ago

Unfortunately, it still doesn't work for the latest version 0.8.4.

womandroid commented 7 years ago

Here is the log message when I purchase the product by a purchased account:

unhandledTransactions:
productId: com.xxx.app.product, transactionId: null, state: purchasing, date: nil
Unexpected restored transaction for payment com.xxx.app.product
Finishing transaction for payment "com.xxx.app.product" with state: restored

After that, nothing happend. The callback still doesn't execute.

cp3hnu commented 6 years ago

I have same problem. I found code, if transactionState == .restored { print("Unexpected restored transaction for payment \(transactionProductIdentifier)") } no callback be executed

doffen commented 6 years ago

This problem has never been fixed since it was first identified in #105, but I have a proposed fix here, which I have tested in SwiftyStoreKit v0.10.7 with Swift 3 (and the same should apply to v0.11.0).

The problem occurs only in Mac OS when you try to re-purchase a non-consumable item that you have previously purchased. The completion closure never gets called. The reason it works in iOS and not in macOS can be found and fixed in the processTransaction function in the file PaymentsController.swift. When the iOS App Store acknowledges the prior purchase it sends a transactionState == .purchased, but when the Mac App Store acknowledges the prior purchase it sends a transactionState == .restored! The fix is to change

if transactionState == .purchased {

to

if transactionState == .purchased || transactionState == .restored {

and to remove the test for transactionState == .restored at the end of the processTransaction function (which doesn't really do anything anyway). As I am not adept at submitting updates to the code base, I hope someone will read this and apply this change to a future release.

zhudengdengdeng commented 6 years ago

@doffen Same here too, but your fix is a little rough. What if I do want to restore? Callback for restore will never be called.

doffen commented 6 years ago

I tested restore and it works for me, on both iPhone and Mac OS. zhudengdengdeng, have you seen it fail to restore when using this change?

zhudengdengdeng commented 6 years ago

@doffen Sorry for my mistake, I have looked into the code and found no issue.

houmie commented 4 years ago

@Sam-Spencer this issue is back again for Mac. It would be great to add a unit test so another contributor isn't deleting it again. Or adding comments there may prevent it from being removed.

I can see you have merged it: https://github.com/bizz84/SwiftyStoreKit/pull/465/files/b216b219bda55252390e2d5b89142963b8a9ee14

But when will the CocoaPod be updated with this fix, please? Many Thanks

baijiahei888 commented 4 years ago

Mac上复现了这个问题,复现方式: 1.购买自动续订套餐,然后再购买其他续订套餐 会报这个异常 2.续订套餐到期后,再次手动购买续订套餐,就可以复现了

omarojo commented 3 years ago

Im also getting this issue. 1- I restore purchases, after success, it verifies all inApps. 2- monthly subscription is detected as previously bought. 3- I select the Yearly Subscription (same group as the monthly). 4- I try to buy the Yearly Subscription so that is switches from the monthly to the yearly. 5- I get a success buy callback, but no Apple Alert or purchase process of anykind. It simply returns as successfully buy immediately. I see in the console the message: "Unexpected restored transaction for payment com.xxx.app.product"

iOS 14.0

what are we suppose to do here ? any ideas?

santogioia commented 3 years ago

Also for me it happens in iOS

blankdata commented 3 years ago

I encountered similar problems a week ago. Purchasing worked. However, restoring my old (expired) purchases first, and purchasing a new subscription afterwards failed. The purchase requests returned already expired restored purchases instead of new ones. I have used two subscriptions: 1 weekly (for fast tests) and 1 yearly (for slow tests). Over the years my sandbox account collected more than 400 transactions.

Before blaming yourself, your software, or SwiftyStoreKit, you should try to purchase your products with Apple’s sample code (available here: https://developer.apple.com/documentation/storekit/in-app_purchase/offering_completing_and_restoring_in-app_purchases)

Compile & run Apple’s software. Then try to restore your old purchases and buy new products again. If it fails, it is not your fault.

The following solution worked for me: (1) create a new sandbox account in iTunes Connect (2) logout of old sandbox account (in iOS-App Settings > App Store > Sandbox-account) (3) login new sandbox account (4) delete your own app on your test device (5) Restart the device (6) then re-install your app using Xcode. (7) delete old sandbox account (8) test purchases with new sandbox account