Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Feedback The Android Permission class needs serious improvements.

Discussion in 'Android' started by JustAnotherDude, Jul 5, 2019.

  1. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    279
    This class: https://docs.unity3d.com/ScriptReference/Android.Permission.html needs some improvements to be useful.

    1: We need callbacks for the user answer when calling RequestUserPermission:
    https://docs.unity3d.com/ScriptReference/Android.Permission.RequestUserPermission.html

    2: We need a way to check when the user has clicked the “Do not ask me again” option on the system permission dialog, even better if it also comes as a callback from RequestUserPermission.

    From Unity's own documentation:https://docs.unity3d.com/Manual/android-RequestingPermissions.html

    "Note that if the user previously checked the “Do not ask me again” option on the system permission dialog, RequestUserPermission() does not open the system dialog."

    However the class offers no way to tell what you must do, the RequestUserPermission has no return and there's no way to tell if it showed or not, it's useless in this current state. We will never be able to tell if the dialog appeared and if the user denied it, there's no way to tell if we should direct the user to the settings screen to enable the permission...
     
  2. Tomas1856

    Tomas1856

    Unity Technologies

    Joined:
    Sep 21, 2012
    Posts:
    3,875
    Hi,

    thank you for your feedback, I logged your request internally.
     
    JustAnotherDude likes this.
  3. subjectdenied

    subjectdenied

    Joined:
    Jan 3, 2016
    Posts:
    6
    also requesting a permission and checking whether it was granted immediatly after doesn't work for me:

    Code (CSharp):
    1.  
    2. private bool CheckAndroidMicrophonePermission() {
    3.             // check for permission state
    4.             if (Permission.HasUserAuthorizedPermission(Permission.Microphone)) {
    5.                 return true;
    6.             }
    7.  
    8.             // not yet granted => request permission
    9.             Permission.RequestUserPermission(Permission.Microphone);
    10.             // and return final decission
    11.             return Permission.HasUserAuthorizedPermission(Permission.Microphone);
    12.         }
    13.  
    it doesn't matter if i return the result of HasUserAuthorizedPermission(...) immediatly (as done above) or if i assign it to a new value, and return it then. however calling this method a second time, the first condition is TRUE, so to me it seems as while in the documentation it is written explicitly that RequestUserPermission should be synchronous, it actually isn't!

    my guess is this is caused maybe by my method being called from within an event triggered from a flutter application where unity is embedded
     
  4. JonathanFri

    JonathanFri

    Joined:
    Jul 3, 2019
    Posts:
    13
    This doesn't work, as Permission.RequestUserPermission(Permission.Microphone); doesn't halt your code. For now use a Coroutine for example or do magic with OnApplicationFocus, as the app gains focus when accepting/dismissing the dialog
     
  5. sbethge

    sbethge

    Joined:
    Mar 20, 2019
    Posts:
    16
    There is also https://github.com/yasirkula/UnityAndroidRuntimePermissions which supposedly has a blocking call but it doesn't work for me. Maybe needs a small fix. But it illustrates the need. Unity should include something like this or better directly a callback. It's just another one of those this-is-not-a-professional-product moments I keep having lately...
     
  6. Haze-Games

    Haze-Games

    Joined:
    Mar 1, 2015
    Posts:
    186
    +1 @Tomas1856 Any news on this issue?

    We desperately need to know if "Do not ask again" has ben checked by the user in order to give instructions to explain how to enable permission from settings.

    It's a mandatory Google requirement to be considered in any featuring on Google Play. Please address this issue ASAP, as all Unity games are lacking this feature at this time.

    Thank you.
     
    planetfactory likes this.
  7. Tomas1856

    Tomas1856

    Unity Technologies

    Joined:
    Sep 21, 2012
    Posts:
    3,875
    Sadly, no new news.

    I'll try to look in to this. But in any case, since this is not a regression, any improvement applied will only appear in upcoming Unity versions, since 2020.1 and below no longer accepts improvements only bug fixes
     
  8. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,631
    The “unofficial” plugin by a Unity a employee does do this: https://github.com/Over17/UnityAndroidPermissions

    Why the “official” built in support doesn’t have feature parity is a mystery to me.
     
  9. Tomas1856

    Tomas1856

    Unity Technologies

    Joined:
    Sep 21, 2012
    Posts:
    3,875
    We had a talk inside
    Apparently there was a plan to have cross platform API for Permissions, which never happened. Since the status of cross platform API is still unknown we'll move the plugin code into core Unity for UnityEngine.Android.Permissions class.

    Thank you for bringing this to our attention. Sorry for the inconvenience.
     
    AcidArrow likes this.
  10. Tomas1856

    Tomas1856

    Unity Technologies

    Joined:
    Sep 21, 2012
    Posts:
    3,875
    The new API will look like this:

    Code (CSharp):
    1. public class RequestPermissionScript : MonoBehaviour
    2. {
    3.     internal void PermissionCallbacks_PermissionDeniedAndDontAskAgain(string permissionName)
    4.     {
    5.         Debug.Log($"{permissionName} PermissionDeniedAndDontAskAgain");
    6.     }
    7.  
    8.     internal void PermissionCallbacks_PermissionGranted(string permissionName)
    9.     {
    10.         Debug.Log($"{permissionName} PermissionCallbacks_PermissionGranted");
    11.     }
    12.  
    13.     internal void PermissionCallbacks_PermissionDenied(string permissionName)
    14.     {
    15.         Debug.Log($"{permissionName} PermissionCallbacks_PermissionDenied");
    16.     }
    17.  
    18.     void Start()
    19.     {
    20.         if (Permission.HasUserAuthorizedPermission(Permission.Microphone))
    21.         {
    22.             // The user authorized use of the microphone.
    23.         }
    24.         else
    25.         {
    26.             bool useCallbacks = false;
    27.             if (!useCallbacks)
    28.             {
    29.                 // We do not have permission to use the microphone.
    30.                 // Ask for permission or proceed without the functionality enabled.
    31.                 Permission.RequestUserPermission(Permission.Microphone);
    32.             }
    33.             else
    34.             {
    35.                 var callbacks = new PermissionCallbacks();
    36.                 callbacks.PermissionDenied += PermissionCallbacks_PermissionDenied;
    37.                 callbacks.PermissionGranted += PermissionCallbacks_PermissionGranted;
    38.                 callbacks.PermissionDeniedAndDontAskAgain += PermissionCallbacks_PermissionDeniedAndDontAskAgain;
    39.                 Permission.RequestUserPermission(Permission.Microphone, callbacks);
    40.             }
    41.  
    42.         }
    43.     }
    44. }
     
  11. Haze-Games

    Haze-Games

    Joined:
    Mar 1, 2015
    Posts:
    186
    Thanks for letting us know! That will be very useful, especially that iOS and Android don't handle the flow the same way - I think Android is all done "instantly" whereas on iOS we must use a yield in a coroutine, which makes the implementation more complicated than the above.

    Can't wait for this to be added ;)

    Thanks,
     
  12. jgmakes

    jgmakes

    Joined:
    Jan 10, 2019
    Posts:
    75
    While the docs make it seem like it's done instantly, it isn't. I'm waiting for OnApplicationPause( false ) to know when we return from the permission dialog. It'd be great if they both used the same technique (like the callback function design Tomas posted, which I think is more intuitive to a yield for developers coming from other platforms).
     
  13. waldgeist

    waldgeist

    Joined:
    May 6, 2017
    Posts:
    386
    The whole permissions management thing is a huge mess. Now there's even Application.RequestUserAuthorization, but this only works on iOS. And it appears that its counterpart Application.HasUserAuthorization can only be called *after* Application.RequestUserAuthorization, not before like on Android. Also, the docs state that HasUserAuthorization is for "Web Player" (and that Web Player is deprecated), whereas RequestUserAuthorization explicitly suggests using it on iOS. WTF?
     
    monoganog, stm91 and JonathanFri like this.
  14. RicardoF1994

    RicardoF1994

    Joined:
    Dec 24, 2018
    Posts:
    2
    Hi there, I still can't see a possibility to know when the user has selected "Deny and don't ask again" so we know not to ask again. I am checking the permissions at a preloader scene, but now in that scenario it won't go to the game scene since I have no way to tell Unity that it needs to ignore the permission since the user asked to not be bothered anymore.

    I've handled a basic deny and ofcourse the grant. But "Deny and don't ask again" creates is a problem until the user has granted permissions manually.

    Thanks for the help!
     
  15. Haze-Games

    Haze-Games

    Joined:
    Mar 1, 2015
    Posts:
    186
    This was a while ago, but I think I simply used Player Prefs to store if "Never ask again" was requested. That's fine for us because permission remains device-specific so we will ask again if installed on another device and if saved data is completely deleted (acceptable as well, I think).

    At the time there was no other way; I'm not sure if there is now a built-in way to know that distinction of "Deny" VS "Deny and don't ask again".

    Hope this helps,
    Charles
     
  16. Haze-Games

    Haze-Games

    Joined:
    Mar 1, 2015
    Posts:
    186
    Ah wait, I checked again, I think:
    - Initially the permission status is like "Undefined" or something. If the user has Denied in the past, it's no longer "Undefined" but "Denied".

    In that case, I just no longer ask again, by checking if it's already explicitly denied for this app in the past:

    Code (CSharp):
    1. AndroidRuntimePermissions.Permission currentCamPermissionState = AndroidRuntimePermissions.CheckPermission(UnityEngine.Android.Permission.Camera);
    2. wasAlreadyCompletelyDenied = currentCamPermissionState == AndroidRuntimePermissions.Permission.Denied;
    If it wasAlreadyCompletelyDenied is true, then I simply don't ask for the permission. Not sure if it's ideal for you, but worked for my case ;)
     
  17. Haze-Games

    Haze-Games

    Joined:
    Mar 1, 2015
    Posts:
    186
    Apologies, there is a chance I finally switched to using another plugin instead of the Unity system, due to that exact limitation, so maybe what I showed above doesn't work for Unity's permission system.

    It would be a surprise to me that this would still be impossible to do in Unity's permissions for Android.

    I think I used this instead:
    https://github.com/yasirkula/UnityAndroidRuntimePermissions
     
    chachi likes this.
  18. RicardoF1994

    RicardoF1994

    Joined:
    Dec 24, 2018
    Posts:
    2
    I didn't think of saving it in PlayerPrefs. So simple I couldn't see it haha. Thanks. As of Unity 2021.2f1 the options for the permissions are still the same as discussed here originally. I am using it to ask location permission for Mapbox so a restart isn't necessary. (Otherwise the location permission would be asked when loading the map and when given the map already tried to initialize so it won't load again until you reboot the app) I want to do the same thing for IOS, but I can't find anything about that. If you know something, it would be helpfull. Thanks! :)