Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

IAP not working correctly with Corona-2019.3528 and IOS 13
Started by accounting7 Sep 24 2019 08:34 AM

66 replies to this topic
[TOPIC CONTROLS]
Page 3 of 3 1 2 3
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#51

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,539 posts
  • Enterprise

You should use a table printing function like print(json.prettify(event)) to dump the event table and see what's being returned.

 

Rob



[TOPIC: post.html]
#52

deniz

[GLOBAL: userInfoPane.html]
deniz
  • Contributor

  • 160 posts
  • Corona SDK

guys, the new plugin-iap-apple is NOT a drop-in replacement for old store library. Thats why your old store transaction callback functions fail.

 

if event.name == "init", there is no event.transaction. Because of this your event.transaction.isError fails.

 

Also event.transaction.receipt does not contain full receipt. You should call store.receiptBase64Data() to get the receipt. Then use something like https://www.revenuecat.com/apple-receipt-checker to check the validity of it if you care.

 

Corona's documentation about apple IAPs is seriously broken now. 



[TOPIC: post.html]
#53

mlhdyx

[GLOBAL: userInfoPane.html]
mlhdyx
  • Enthusiast

  • 60 posts
  • Corona SDK

Thank you for your tips, Deniz.

 

Never Mind, we've rolled back the system to iOS 12.1 to build the APP, the old APIs works well.

 

Hope Corona Team would fix this issue in the future release.

 

 

 

guys, the new plugin-iap-apple is NOT a drop-in replacement for old store library. Thats why your old store transaction callback functions fail.

 

if event.name == "init", there is no event.transaction. Because of this your event.transaction.isError fails.

 

Also event.transaction.receipt does not contain full receipt. You should call store.receiptBase64Data() to get the receipt. Then use something like https://www.revenuecat.com/apple-receipt-checker to check the validity of it if you care.

 

Corona's documentation about apple IAPs is seriously broken now. 



[TOPIC: post.html]
#54

GamingStudio17

[GLOBAL: userInfoPane.html]
GamingStudio17
  • Contributor

  • 183 posts
  • Corona SDK

Thank you for your tips, Deniz.

 

Never Mind, we've rolled back the system to iOS 12.1 to build the APP, the old APIs works well.

 

Hope Corona Team would fix this issue in the future release.

Like  ^_^



[TOPIC: post.html]
#55

deniz

[GLOBAL: userInfoPane.html]
deniz
  • Contributor

  • 160 posts
  • Corona SDK

I recommend everyone who is using new apple-iap plugin to test their transactionCallback functions extensively for all possible event.name, event.transaction.state combinations. This function does not behave like good old store callback function we used to trust. For example; there is a new event.transaction.state: "restoreCompleted". In this case you have a transaction object, which is not a user-data?!. It's a regular lua table. So if you are finishing transactions by calling store.finishTransaction(event.transaction), your code going to fail. This is just one case showing inconsistent callback interface design. 

 

Either those new interfaces should be changed to match old practices or documented thoroughly. 



[TOPIC: post.html]
#56

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 373 posts
  • Corona SDK

@Rob,

 

This problem seems to be the one I've been trying to solve for the past month. A growing number of my users have reported failed purchase and the only thing I could find is this truncated receipt that apparently started showing with iOS13.

 

I've tried working with the new plugin for apple store but there is no documentation on how to use it. specifically how to use the new methods around receipt validation. There should be some best practice on how to use it.

 

In addition, how should we tackle users with iOS12 and older when using the new plug-in 



[TOPIC: post.html]
#57

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,539 posts
  • Enterprise

We are looking into the issues.

 

Rob



[TOPIC: post.html]
#58

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

Hey guys. Next daily build should not have receipts truncated, both in new plugin and core. New plugin is up now, but it would take couple hours for a new build to build. Also, added empty "transaction" table to IAP plugin.

 

Btw, about receipt validation. You can validate receipts locally without any 3rd party services using new plugin. Check decrypted receipt. It is checked locally on the device, and contains list of all purchases and subscriptions on the device, signed by Apple and verified with public key cryptography. I would suggest experimenting a little with it, and if you could share your experience, it would be great. Like, try to make some purchases and do

require("json").prettify(store.receiptDecrypted())

Cheers!

Vlad.



[TOPIC: post.html]
#59

colinmorgan

[GLOBAL: userInfoPane.html]
colinmorgan
  • Enthusiast

  • 40 posts
  • Corona SDK

Vlad,

Great news- thank you.

Do I understand you correctly that it's most likely safe to just continue using the built-in Apple IAP?

Thanks again!



[TOPIC: post.html]
#60

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

OK. Here is the differene:

1. Plugin: can be updated separately from the core. So plugin would have proper receipts with any version of Core. Also, plugin has some additional functionality, like using modern API to read receipt, as well as decode it, so you can locally verify purchase using public key cryptography, as well as read contents of receipts, which contains information about subscriptions and all purchases client made. Very useful.

2. Core: apps are slightly smaller, because you don't link the plugin. Also, what you get depends on version of the Corona you are using. Like, to get proper receipts in iOS13 SDK you would have to use 2019.3564+ or something.

 

They have pretty much identical code. Except that Core doesn't have empty init event... It is really added only for compatibility with Android.



[TOPIC: post.html]
#61

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 373 posts
  • Corona SDK

@vlads,

 

Great News. Thanks for your help in this!

Just two questions:

1. If I remain with the core and build using 3564+, is it backwards compatible? meaning, do I cover iOS13 but also iOS12 and back?

2. There are additional methods in the Plug-in version and its not clear what each does and how they integrate to the previous workflow we had in core. can someone provide the intended behavior end to end with the new plug-in?



[TOPIC: post.html]
#62

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

1. Yes. It is backward compatible.

2. https://docs.coronalabs.com/plugin/apple-iap/ contains list of methods and basic information about them.

But you are right, Guide is needed for sure.

Meanwhile:

This methods are wrappers around appStoreReceiptURL

Method store.receiptRequest() is a wrapper around SKReceiptRefreshRequest.



[TOPIC: post.html]
#63

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

After some consideration. I removed empty "transaction" table from the Init event. Sorry, it should not be there and breaking existing code.



[TOPIC: post.html]
#64

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

For your convenience, here is example of decrypted receipt. I don't think this format can change:

https://pastebin.com/embed_iframe/UQ18tuuJ

 

As you can see, it is a table. Here are some important bits:

decrypted = store.receiptDecrypted()
decrypted.in_app -- array containing all in apps

Example entry of decrypted.in_app:

{
      "transaction_id":"1000000454925773", // same as store listener transaction.identifier. Unique for each purchase, restore, or renewal
      "is_in_intro_offer_period":0, // 1 if subscription is in free trial still, 0 otherwise
      "product_id":"com.coronalabs.IapTest.goodies", // same as transaction.productIdentifier
      "expires_date":1539096727, // for subscriptions, this will be time subscription ends, same as purchase time for one timers
      "quantity":1, // ...
      "purchase_date":1539096427, // UNIX time of when purchase was made
      "cancellation_date":0, // time when user cancelled auto-renewing sub, 0 otherwise
      "original_transaction_id":"1000000454914195", // transaction.originalIdentifier, identifier of original purchase
      "original_purchase_date":1539095266,
      "web_order_line_item_id":"1000000040727298" // seems to be some apple internal stuff

}

Fields in this structure are documented on Apple website: https://developer.apple.com/documentation/appstorereceipts



[TOPIC: post.html]
#65

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 373 posts
  • Corona SDK

Hi @vlads,

 

I've tested the new core code and have a few notes:

1. The app now receives full receipt in iOS13 - Great!

2. Our previous receipt validation code via Apple server now fails with code ["21002"] = "The data in the receipt-data property was malformed." perhaps there is a difference compared to previous receipt data, but I couldn't identify what. Not sure how to proceed in this track yet.

 

I then tried to switch to the plug-in. Some notes:

3. The plugin has some differences vs the core as already noted above (change in init, new event restoreCompleted, might be others)

4. It's not clear if I should use for each incoming transaction event store.receiptRequest(listener) or just try store.receiptDecrypted()

5. In both cases I get All transactions history, where our previous validation received only the latest (we used exclude_old_transactions = true on the request post data).

6. finishTransaction now fails when using the transaction object in two events: A. init B. restoreCompleted

7. RestoreCompleted event seem to have no useful info. only type='restore' and isError='false'

 

This is all I could find so far.

Thanks for investing the time on this.

 

Adi



[TOPIC: post.html]
#66

vlads

[GLOBAL: userInfoPane.html]
vlads
  • Corona Geek

  • 1,005 posts
  • Corona Staff

1. Yay!

2. Our data before was formatted like "< 01234567 89abcdef .... .... .... >", base64 representation in <> quotes and groupped in 8 symbols. Plugin and core now return base64 representation without <> or spaces. I hope it'll help. Showing what code you were using to verify purchases previously might help to understand what the issue is. For now I have no idea what's going on.

3. Yes. I has init which can be ignored, really, and done for just compatibility with android iap, and restoreCompleted. That's it.

4. In all my tests receipt is ready right after purchase.

5. No idea what it means, because you're talking about code I never saw... We just passing what Apple APIs give us. "Before" we ware using [SKPaymentTransaction transactionReceipt] which is long deprecated. This is one returned with lua's transaction.receipt. We still returning it. New store.receipt* functions are all receipts.

6. I changed plugins' finish transaction so it doesn't fail.

7. It is by itself. Before it was like you hit store.restore() and never know when it is finished. Now you can see it in the event.

 

Also, here is some verification code I threw in. It seems to work fine. 100% local verification, no need for server:

local function verifyPurchase( identifier )
    print("Verifying", identifier)
    local iaps = (store.receiptDecrypted() or {}).in_app
    for i=1,#iaps do
        local iap = iaps[i]
        if iap.original_transaction_id == identifier then
            return true
        end
    end
    return false
end

store.init( "apple", function(event)
    local t = event.transaction
    if t then
        if t.state == "restored" or t.state == "purchased" then
            local verified = verifyPurchase(t.originalIdentifier or t.identifier)
            print("Verified purchase", verified)
            native.showAlert("Purchase Verified", tostring(verified), {"OK"})
        end
    end
    store.finishTransaction( t )
end)

Here is my sample's full code: https://pastebin.com/embed_iframe/SiBkHAnC
 



[TOPIC: post.html]
#67

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 373 posts
  • Corona SDK

@vlads,

 

Thats exactly what I needed! previously we had to pre-process the receipt before sending it, now we can simply use it as is for validation. The core code now works for iOS13. I'll also verify it formats the receipt the same way for earlier OS versions.

 

I will also try modifying our code to use the plug-in and see if we can safely switch.

Thanks again for your help!




[topic_controls]
Page 3 of 3 1 2 3
 
[/topic_controls]