UWP apps have been designed to be more secure and explicit about what they are allowed to do on the user's device so that she is always in control. Hand in hand with that comes the fact that user can manually grant or deny individual permissions in the system Settings. However, this presents a challenge for developers - how can we make sure we have access to a capability when the user can deny it any time? That's what I would like to show you in this article.
What can go wrong?
Let's illustrate the issue on a straightforward example. Your app declares the Pictures library capability in Package.appxmanifest
.
In the code you usually access the library and expect to work with it without issues.
Everything is bright and shiny until the user explicitly denies the permission in Settings -> Apps -> [App name] -> Advanced settings -> App p ermissions:
When we relaunch the app and try to access Pictures library we end up with an ugly UnauthorizedAccessException
:
The solution
We will wrap access to the capability in a helper method, which will have appropriate logic to make sure our app handles the situation gracefully. The first key element of our fix is not letting the app just crash when we lack the capability permission. A simple try...catch
will do the trick:
Once we are in the catch
statement, we know we have been denied access, and we need the user to grant us the required permission again. We can inform her via a MessageDialog
:
When the user chooses Cancel
, we are merely returning null
. Depending on how much our app relies on the permission we can decide to either keep the app running with limited functionality or just terminate it.
In case the user presses OK
, we will navigate him to the advanced settings page for our app in the system Settings and give us the required permission using the special ms-settings:appsfeatures-app
(see Docs).
This specific example handles check for library capability, but you can analogously implement it for other permissions as well.
Warning - don't forget about user's data
There is one catch with the presented solution - changing application permissions cannot be done at runtime. When the user modifies them in any way, the app will get terminated. That is the reason why the MessageDialog
informs the user to reopen the app after granting the required permission. The key takeaway for your app is then the fact that you should always make sure all user data are safely saved before accessing a permission-bound API. This way you will be able to restore the user's current action and will not break her flow when the app is reopened. Alternatively, you can check for all permissions which are really required for your app to run properly at startup. The advantage of this is the fact that the user doesn't have any work in progress at that point, so it is perfectly safe to close.
Source code
Full code of our helper method looks like this:
You can find the example solution for this article on my GitHub.
Summary
We have seen how we can gracefully handle the situation when user has denied us permission we require for our app to run properly. This way we offer excellent user experience and can even specifically explain why the given API is needed.