Android Onboarding

I recently submitted my game hoping to be featured in Indie Corner on Google Play. They reviewed it and responded with the following:

We have reviewed Zantics Racing and found some issues that need to be resolved before it can be considered for featuring. Please review the feedback below and reply to this email when the issues raised have been resolved. This feedback below is based on our quality guidelines (http://developer.android.com/distribute/googleplay/quality/index.html).

---- Feedback Report -----
Android OS on devices for review: 7.0, 8.1
Reviewed app ver.: PRODUCTION
Version Name: 7.1
Version code: 71

I. Must resolve for feature consideration:

  • Permissions critical to app’s launch should be easily understood and tied directly to the app’s primary function(s) or explained to the user through onboarding to justify their use within the app. Currently, the onboarding is skipped and permissions are required without context. Context is provided if the user denies the permission requests, however this context should be provided before the permission requests appear in the first place.

For more info: https://material.io/guidelines/patterns/permissions.html#permissions-denied-permissions

I’m not exactly sure how to implement what they are asking for. Any advice out there for how to best implement Onboarding for a new user?

Throwing up a message explaining the need for each permission is easy enough… but how could I know if the user accepted that permission?  I’m using a local database and could store that in memory if there was a way to know that the user accepted the permission.  Right now, other than putting the permissions needed in build.settings, I don’t see a way to control or interface with anything related to the permissions.  Has anyone else out there done anything like this?

Corona provides API’s to check that.  Please look at the SampleCode/Media/Camera sample app and study the permission code there. Once you know that information, you can then easily display messages to your end user.

Rob

Thanks for the reply Rob… but I’m still struggling with this.  I can’t get my device to recognize the native.showPopup function for “Storage” at all.  It simply acts as though that code isn’t even there.  

I’m getting a popup message that looks like it is Android reacting to my build.settings permissions (see attached image).  What I need to do is control this message by editing it or placing my own popup message prior to this one. 

Below is the latest iteration of my code… I threw in some Alert Popups for testing to tell me on the device what is happening.  In the simulator, it works fine as if permissions had already been granted in the past… this includes the Alert.  I can’t get this behavior on my device, however, even after clicking Allow on the attached image.  Also, closing the app and opening again only gives me a black screen… not even an Alert comes on screen.

I truly appreciate any help…

local function canUseStorage() -- Ensure that we have permission to use external storage. local grantedPermissions = system.getInfo("grantedAppPermissions") if ( grantedPermissions ) then if ( not isValueInTable( grantedPermissions, "Storage" ) ) then print( "Lacking storage permission!" ) return false end end return true end local function permissionsListener( event ) -- Print out granted/denied permissions. print( "permissionsListener( " .. json.prettify( event or {} ) .. " )" ) -- Check again for storage access. -- Note that we use our helper function, canUseStorage(), as the -- permissions listed in the event are ONLY for what has been just denied -- or granted. if ( canUseStorage() ) then --Permission has been granted local function onComplete(event) goToGame() end local alert = native.showAlert( "Zantics Racing", "Permission Granted to Storage, Activate Game.", { "OK" }, onComplete ) else -- The user hasn't given us the required permissions. native.showAlert( "Corona", "Required permissions not granted... give user chance to accept again.", { "OK" } ) end end -- We can't assume that the user has given us permission to use storage. -- Get access to Storage! if ( canUseStorage() ) then -- If we have access to the storage, activate game. print( "Calling to activate game!" ) local function onComplete(event) goToGame() end local alert = native.showAlert( "Zantics Racing", "We have access to Storage, Activate Game.", { "OK" }, onComplete ) else -- If we don't have access to storage, request permission to use it, if we can. if ( native.canShowPopup( "requestAppPermission" ) ) then local permissionsToRequest = { "Storage" } local rationaleTitleMessage = "Zantics Racing needs permissions!" local rationaleMessage = "Zantics Racing needs Storage permission to save data and progress through the game." -- Make the actual request from the user. native.showPopup( "requestAppPermission", { appPermission = permissionsToRequest, urgency = "Normal", rationaleTitle = rationaleTitleMessage, rationaleDescription = rationaleMessage, listener = permissionsListener, } ) else -- We can't ask for permission to use storage. -- Tell the user to enable it in Settings. native.showAlert( "Zantics Racing", "Permission to use your Device Storage cannot be requested. Please go to Settings and grant this app access.", { "OK" } ) end end

Maybe try to use “android.permission-group.STORAGE” instead of “Storage”?

Rob

Any idea what triggers Android to throw up the permissions popup when a user starts the app for the first time?

You have to determine if you’ve asked for the permission or not. Our API’s let you detect if it’s been granted or not. You can save a setting to check on startup to know if you should ask again.

Rob

The APIs seem to work fine for other permissions such as calendar and camera (based on my testing), but I’ve tried every rendition I could think of for Storage, and it simply doesn’t work. Has anyone been able to make it work for Storage?

Can you put together a simple demo project that asks for the storage permission and put it in a .zip file and share a link to it here? I may have you file a bug report about it.

Rob

I put together a Demo project and may have figured something out in the process.  The Allow Message thrown up by Android pops up regardless of whether or not I put the API Function in my code.  In the Demo Project I made, it seemed to work in the order in which I put the permissions.  But in Zantics Racing, it’s immediately Requesting Permissions over the top of anything else and not giving me the chance to explain the permission in my own words prior.  It’s as if something else is triggering the requested permissions.  So far, I’ve placed anything related to the SQLite database after the Permissions API, but Android is still Requesting Permissions over the top.  

Does anyone know what else could trigger Android to request permissions outside of the API?

I think I might have figured out what’s causing this issue, but I don’t think it’s in my control to fix it.  If I deny access to the Storage Permission that is automatically thrown up by Android, I get the message:

“Zantics Racing uses Expansion Files and needs external storage permission to access them.  Re-request access?”

This is not a message I created.  It is generated by Android as far as I can tell. 

I believe that because I am using “useExpansionFile = true” in my build.settings, Android is requesting permission before I can ever use the Corona API to do so in a custom fashion.  

Does anyone have any advice on this?

This behavior is staying very consistent and I can’t find a way around it.  I believe this might be a bug in Corona when using “useExpansionFile = true”.

Have you filed this as a bug report yet using your sample project?

Rob

Rob, I just submitted a bug report… but I suspect this won’t be remedied in time to save my Indie Corner application.  Thanks for the help though.

Throwing up a message explaining the need for each permission is easy enough… but how could I know if the user accepted that permission?  I’m using a local database and could store that in memory if there was a way to know that the user accepted the permission.  Right now, other than putting the permissions needed in build.settings, I don’t see a way to control or interface with anything related to the permissions.  Has anyone else out there done anything like this?

Corona provides API’s to check that.  Please look at the SampleCode/Media/Camera sample app and study the permission code there. Once you know that information, you can then easily display messages to your end user.

Rob

Thanks for the reply Rob… but I’m still struggling with this.  I can’t get my device to recognize the native.showPopup function for “Storage” at all.  It simply acts as though that code isn’t even there.  

I’m getting a popup message that looks like it is Android reacting to my build.settings permissions (see attached image).  What I need to do is control this message by editing it or placing my own popup message prior to this one. 

Below is the latest iteration of my code… I threw in some Alert Popups for testing to tell me on the device what is happening.  In the simulator, it works fine as if permissions had already been granted in the past… this includes the Alert.  I can’t get this behavior on my device, however, even after clicking Allow on the attached image.  Also, closing the app and opening again only gives me a black screen… not even an Alert comes on screen.

I truly appreciate any help…

local function canUseStorage() -- Ensure that we have permission to use external storage. local grantedPermissions = system.getInfo("grantedAppPermissions") if ( grantedPermissions ) then if ( not isValueInTable( grantedPermissions, "Storage" ) ) then print( "Lacking storage permission!" ) return false end end return true end local function permissionsListener( event ) -- Print out granted/denied permissions. print( "permissionsListener( " .. json.prettify( event or {} ) .. " )" ) -- Check again for storage access. -- Note that we use our helper function, canUseStorage(), as the -- permissions listed in the event are ONLY for what has been just denied -- or granted. if ( canUseStorage() ) then --Permission has been granted local function onComplete(event) goToGame() end local alert = native.showAlert( "Zantics Racing", "Permission Granted to Storage, Activate Game.", { "OK" }, onComplete ) else -- The user hasn't given us the required permissions. native.showAlert( "Corona", "Required permissions not granted... give user chance to accept again.", { "OK" } ) end end -- We can't assume that the user has given us permission to use storage. -- Get access to Storage! if ( canUseStorage() ) then -- If we have access to the storage, activate game. print( "Calling to activate game!" ) local function onComplete(event) goToGame() end local alert = native.showAlert( "Zantics Racing", "We have access to Storage, Activate Game.", { "OK" }, onComplete ) else -- If we don't have access to storage, request permission to use it, if we can. if ( native.canShowPopup( "requestAppPermission" ) ) then local permissionsToRequest = { "Storage" } local rationaleTitleMessage = "Zantics Racing needs permissions!" local rationaleMessage = "Zantics Racing needs Storage permission to save data and progress through the game." -- Make the actual request from the user. native.showPopup( "requestAppPermission", { appPermission = permissionsToRequest, urgency = "Normal", rationaleTitle = rationaleTitleMessage, rationaleDescription = rationaleMessage, listener = permissionsListener, } ) else -- We can't ask for permission to use storage. -- Tell the user to enable it in Settings. native.showAlert( "Zantics Racing", "Permission to use your Device Storage cannot be requested. Please go to Settings and grant this app access.", { "OK" } ) end end

Maybe try to use “android.permission-group.STORAGE” instead of “Storage”?

Rob

Any idea what triggers Android to throw up the permissions popup when a user starts the app for the first time?

You have to determine if you’ve asked for the permission or not. Our API’s let you detect if it’s been granted or not. You can save a setting to check on startup to know if you should ask again.

Rob