Google Play licensing: Not getting NOT_LICENSED response

Has anyone gotten the Google Play licensing stuff to work consistently?

I just added the Google Play licensing code, and I tried testing on a device.

This is the listener code I am using, based on the sample code:

function licensingListener( event )     local verified = event.isVerified     message = "Address: " .. event.address .. "\n\nName: " .. event.name .. "\n\nProvider: " .. event.provider .. "\n\nisVerified: " .. event.isVerified .. "\n\nisError: " .. event.isError .. "\n\nError type: " .. event.errorType .. "\n\nError response: " .. event.response     native.showAlert( "App Name", message, { "OK" }, exitApp ) end

I never get an alert, regardless of what I set the License Test Response to in the Google Play Developer tool for my account.

If I use this listener code:

local function licensingListener( event ) local verified = event.isVerified if not event.isVerified then native.showAlert( "App Name", "Error type: " .. event.errorType .. "\n\nError response: " .. event.response, { "OK" }, exitApp ) end end

In the Google Play developer tool, if I set my account to get a License Test Response of NOT_LICENSED, I never get an alert. 

If I change it to ERROR_SERVER_FAILURE, I do get an alert.  If I change it to any of the other ERROR_XXX options, I do get an alert.  Why is there no alert if the License Test Response is sent as NOT_LICENSED?

How can one actually check that that the response was NOT_LICENSED and not one of the other possible errors that might cause the user to not be verified?

There are a few Google hoops that you need to jump through to get it to work.

  1. Upload a Draft APK (The Version Code must be higher than the one currently in Prod).

  2. The account on your device must either be the same account as your Developer Console account, or be listed in the ‘accounts with testing access’ list.

  3. The Version Code of the test-APK on the device must be the same as the one given in the uploaded Draft APK.

  4. Make sure your config.lua has the correct license key listed.

NOTE: It may take some time before the Draft APK info has propagated across the Google servers. For me it can take anywhere from a couple of minutes to a couple of hours. 

Also, the Draft APK only needs to be uploaded once. You can then freely re-compile and install new APK’s to your device as long as the Version Code remains the same across builds.

ingemar,

Thanks for the reply.  I was not aware of the need to upload a Draft/Test APK.  I had done the other parts, but not that, so I will do that this evening and see if that fixes my issue.

Appreciate your help!

Well, that did not work either.

I find that if I use the

message = "Address: " .. event.address .. "\n\nName: " .. event.name .. "\n\nProvider: " .. event.provider .. "\n\nisVerified: " .. event.isVerified .. "\n\nisError: " .. event.isError .. "\n\nError type: " .. event.errorType .. "\n\nError response: " .. event.response

line, I never get any alert to display, regardless of what I set the response to in the tool.

Change it to:

message = "Error type: " .. event.errorType .. "\n\nError response: " .. event.response

And I do get the response if I set it to one of the errors, but I get nothing if I change it to NOT_LICENSED.

Which makes me think that we need to test to see if it comes back isVerified, and if it does not, check to see if there is an error, because if there is, it likely doesn’t mean that it is not licensed, but that something else happened.

So confused.

Nope, that didn’t work either.

function licensingListener( event ) local verified = event.isVerified if not event.isVerified then if event.errorType = "network" then else native.showAlert( "App Name", "The Google Play store indicates that this app is not a legal copy. Please install the application from the Google Play store.\n\nThe application will now close.", { "OK" }, exitApp ) end end end

So if it is a network error, then don’t show the Pirate message, otherwise show it.

But if I set it as NOT_LICENSED in the developer tool, it must be verifying since it never hits that IF block.

I just do not understand.   :slight_smile:

Has anyone actually used the built-in Google Licensing with the non-Enterprise version of the Corona SDK?

That’s weird. When I was testing this a few weeks ago while updating one of my apps to use the new Licensing API I didn’t have any problems. I got the exact response as I had set in the Developer Tool.

I was using the stock Corona SDK without any Enterprise features for this project as well. 

I’m going to be doing final testing before release during this week with the latest SDK and report back my findings here.

Thanks, I’d love to hear what you get.  Specifically, I’d love to know if you actually get an event.response when you set it to NOT_LICENSED.

When I was originally testing, I was getting it not verifying, but that’s because other things were wrong.  Like if I disabled an Internet connection, it would come back as not verified, but unlike the Corona example, you don’t want to call them a pirate then because it could just be the Google server wasn’t contactable.  It seems like we really need to get the NOT_LICENSED response.

I’ve just tested with both my Android test-devices using Corona 2013.1168.

Galaxy-S (Android 2.3.6) and Nexus 7 (Android 4.2.2).

Both report NOT_LICENSED correctly.

Here’s the code that I use: 

local onStartError = function(event) if (string.find("clicked,cancelled", event.action)) then native.requestExit(); end end local licensingListener = function(event) local verified = event.isVerified; local networkError = (event.errorType == "network"); if ((not verified) and (not networkError)) then print("ERROR: No valid licence"); native.showAlert( "Error", "Sorry, no valid license found.\nPlease download the app from the Google Play Store.", {"OK"}, onStartError); end end local licensing = require("licensing"); licensing.init("google"); licensing.verify(licensingListener);

I had a similar battle with the licensing check, especially around the network connection and returned messages. The key changes I had to make were:

  1. The messages returned by Corona are slightly different to those listed by Google (e.g. NOT_LICENSED from Google vs “Not licensed” in Corona).
  2. I also decided to cache the response to use where a network error is returned. In your example above, if a user gets the “pirated” message, they could disable their WiFi / 3G, re-launch the app and all would be well.

The code I have implemented which seems to work well is:

local function licensingListener( event ) local verified = event.isVerified print "Google license response" print("response ", event.response) -- If response is not one of those listed below, app will use cached version of -- "pirated" that was loaded with loadgame() previously if event.response == "Not licensed" or event.response == "Not market managed" then pirated = 1 savegame() -- Save updated setting into user area elseif event.response == "Licensed" then pirated = 0 savegame() -- Save updated setting into user area end -- In my app, if I detect a license violation, convert app to free version rather -- than exiting. if pirated == 1 then version = "free" native.showAlert( "License error", "Unable to verify license with Google, reverting to free version", {"OK"} ) end end

Whilst not perfect, (if a pirate sideloads the app and always launches with network disabled then they will be able to play), it only takes the pirate to launch the game once with network to trigger the response for all future times the game is loaded.

OFF-TOPIC:

@ian14

I’d recommend to only use event.isVerified and not to test against strings returned in event.response.

It’s better to let the Corona API determine the ‘verified’ logic instead of building it into the app itself.

Regarding pirates, you could use network.setStatusListener() to test if they have disabled Wifi/Cellular and set up a grace counter where the user is allowed x number of app-starts before the app requires an Internet connection as well.

Hi,

A few things to check:

  1. The package names are the same on the developers console and what you built.

  2. The key you’ve pasted into config.lua is correct.

  3. The user is actually a test account on the developers console.

There are a few Google hoops that you need to jump through to get it to work.

  1. Upload a Draft APK (The Version Code must be higher than the one currently in Prod).

  2. The account on your device must either be the same account as your Developer Console account, or be listed in the ‘accounts with testing access’ list.

  3. The Version Code of the test-APK on the device must be the same as the one given in the uploaded Draft APK.

  4. Make sure your config.lua has the correct license key listed.

NOTE: It may take some time before the Draft APK info has propagated across the Google servers. For me it can take anywhere from a couple of minutes to a couple of hours. 

Also, the Draft APK only needs to be uploaded once. You can then freely re-compile and install new APK’s to your device as long as the Version Code remains the same across builds.

ingemar,

Thanks for the reply.  I was not aware of the need to upload a Draft/Test APK.  I had done the other parts, but not that, so I will do that this evening and see if that fixes my issue.

Appreciate your help!

Well, that did not work either.

I find that if I use the

message = "Address: " .. event.address .. "\n\nName: " .. event.name .. "\n\nProvider: " .. event.provider .. "\n\nisVerified: " .. event.isVerified .. "\n\nisError: " .. event.isError .. "\n\nError type: " .. event.errorType .. "\n\nError response: " .. event.response

line, I never get any alert to display, regardless of what I set the response to in the tool.

Change it to:

message = "Error type: " .. event.errorType .. "\n\nError response: " .. event.response

And I do get the response if I set it to one of the errors, but I get nothing if I change it to NOT_LICENSED.

Which makes me think that we need to test to see if it comes back isVerified, and if it does not, check to see if there is an error, because if there is, it likely doesn’t mean that it is not licensed, but that something else happened.

So confused.

Nope, that didn’t work either.

function licensingListener( event ) local verified = event.isVerified if not event.isVerified then if event.errorType = "network" then else native.showAlert( "App Name", "The Google Play store indicates that this app is not a legal copy. Please install the application from the Google Play store.\n\nThe application will now close.", { "OK" }, exitApp ) end end end

So if it is a network error, then don’t show the Pirate message, otherwise show it.

But if I set it as NOT_LICENSED in the developer tool, it must be verifying since it never hits that IF block.

I just do not understand.   :slight_smile:

Has anyone actually used the built-in Google Licensing with the non-Enterprise version of the Corona SDK?

That’s weird. When I was testing this a few weeks ago while updating one of my apps to use the new Licensing API I didn’t have any problems. I got the exact response as I had set in the Developer Tool.

I was using the stock Corona SDK without any Enterprise features for this project as well. 

I’m going to be doing final testing before release during this week with the latest SDK and report back my findings here.

Thanks, I’d love to hear what you get.  Specifically, I’d love to know if you actually get an event.response when you set it to NOT_LICENSED.

When I was originally testing, I was getting it not verifying, but that’s because other things were wrong.  Like if I disabled an Internet connection, it would come back as not verified, but unlike the Corona example, you don’t want to call them a pirate then because it could just be the Google server wasn’t contactable.  It seems like we really need to get the NOT_LICENSED response.

I’ve just tested with both my Android test-devices using Corona 2013.1168.

Galaxy-S (Android 2.3.6) and Nexus 7 (Android 4.2.2).

Both report NOT_LICENSED correctly.

Here’s the code that I use: 

local onStartError = function(event) if (string.find("clicked,cancelled", event.action)) then native.requestExit(); end end local licensingListener = function(event) local verified = event.isVerified; local networkError = (event.errorType == "network"); if ((not verified) and (not networkError)) then print("ERROR: No valid licence"); native.showAlert( "Error", "Sorry, no valid license found.\nPlease download the app from the Google Play Store.", {"OK"}, onStartError); end end local licensing = require("licensing"); licensing.init("google"); licensing.verify(licensingListener);

I had a similar battle with the licensing check, especially around the network connection and returned messages. The key changes I had to make were:

  1. The messages returned by Corona are slightly different to those listed by Google (e.g. NOT_LICENSED from Google vs “Not licensed” in Corona).
  2. I also decided to cache the response to use where a network error is returned. In your example above, if a user gets the “pirated” message, they could disable their WiFi / 3G, re-launch the app and all would be well.

The code I have implemented which seems to work well is:

local function licensingListener( event ) local verified = event.isVerified print "Google license response" print("response ", event.response) -- If response is not one of those listed below, app will use cached version of -- "pirated" that was loaded with loadgame() previously if event.response == "Not licensed" or event.response == "Not market managed" then pirated = 1 savegame() -- Save updated setting into user area elseif event.response == "Licensed" then pirated = 0 savegame() -- Save updated setting into user area end -- In my app, if I detect a license violation, convert app to free version rather -- than exiting. if pirated == 1 then version = "free" native.showAlert( "License error", "Unable to verify license with Google, reverting to free version", {"OK"} ) end end

Whilst not perfect, (if a pirate sideloads the app and always launches with network disabled then they will be able to play), it only takes the pirate to launch the game once with network to trigger the response for all future times the game is loaded.

OFF-TOPIC:

@ian14

I’d recommend to only use event.isVerified and not to test against strings returned in event.response.

It’s better to let the Corona API determine the ‘verified’ logic instead of building it into the app itself.

Regarding pirates, you could use network.setStatusListener() to test if they have disabled Wifi/Cellular and set up a grace counter where the user is allowed x number of app-starts before the app requires an Internet connection as well.