- Home /
How to deal with Android runtime permissions?
I'm in the process of implementing Android runtime permissions in the game we're developing because it targets Android SDK 23.
We're requesting the WRITE_EXTERNAL_STORAGE permission because we're taking a screenshot and share that to any app we want. So the user presses the share button, we're showing the request permissions dialog and the permission is set. This all works fine. However, after setting the permission the Application.persistentDataPath still points to the internal storage, instead of the external storage. After we restart the app, it will point to the external storage, as expected.
Restarting the app is undesirable as you can understand. Is there a solution so restarting the app isn't necessary? Or in general, how does everyone handle situations where setting a permission requires an app restart?
I am also looking for a solution to this problem. $$anonymous$$y current thinking is that this is an error with Unity which may have been addressed in a later patch, therefore I'm trying a build with a later version to see if that might help. Failing that I'll write a plugin which returns the persistent data path using android api and use that ins$$anonymous$$d of the unity one. Any help or updates are appreciated.
Answer by liziattwood · Jul 08, 2016 at 12:28 AM
Ok, so I realise you have probably come up with a solution yourselves by now but I thought I'd post an answer for anyone else searching for a solution to this.
The latest version of Unity still showed the same behaviour: the path you get back from Application.persistentDataPath changes after a restart, following the WRITE_EXTERNAL_STORAGE permission being granted. So, if you have obb file download code, for example, and request that permission runtime (to meet Android M [6.0] requirements) then save a file, the next time the user launches your app persistentDataPath will have changed and you will not find the file you saved previously.
The solution I came up with was to add a function to the plugin I wrote to deal with the permissions flow. The function returns the external directory, appends the rest of the path and creates the directory if it doesn't already exist, because this is something Unity takes care of for you as part of Application.persistentDataPath. From inside Unity, as soon as I've detected that the permission has been granted I use this function to cache the external location for save files, then use this instead of persistentDataPath.
Java:
String result = "";
File file = new File(Environment.getExternalStorageDirectory(), path);
if (!file.exists())
{
if (file.mkdirs())
{
result = file.getPath();
}
}
else
{
result = file.getPath();
}
Path is "/Android/data/[Your Bundle Identifier]/files", there is probably a way to grab the identifier within Java but I'm just passing it in from C# using Application.bundleIdentifier. As soon as permission is granted, call this and cache the result. If it doesn't exist and fails to create the directly then result is empty and you have to deal with that.
hello @liziattwood , thank you for sharing this. i'm dealing with the same issue, i need my app to have storage permissions. is the plugin you wrote to deal with this available anywhere? would love to look and learn from it.
thanks, ali
hi @batchku - I don't have the rest of the plugin online anywhere because it was written for a client. But I can help you!
Firstly, I created a basic Android plugin for Unity (I think I followed this tutorial: https://www.thepolyglotdeveloper.com/2014/06/creating-an-android-java-plugin-for-unity3d/).
I then added the entire flow for permissions into the plugin, it uses the built in Android message box to explain to the user why it is asking for permission before it does so. When it asks for permission is passes in a callback for the user response, when the callback is triggered it sets a flag and caches the response. The script in Unity just sits and waits for the plugin function to complete. Once it completes, the unity script calls a plugin function to get the cached response and if permission was granted it calls another plugin function to get the correct path, that function contains the code above (it returns result).
If permission wasn't granted then the plugin actually handles a second attempt (message and permission request) and the Unity script continues to wait, if the second attempt fails then the app quits.
Additionally, I had to disable the default Unity behaviour of trying to request permission itself during start up, so that I could let the user know why permission was being requested as per the Google recommendations.
Your answer
Follow this Question
Related Questions
Avoid android permission prompt when returning to app after changing settings on device? 0 Answers
Using Texture2D created at runtime to create a Sprite decreases Sprite quality. (Android) 1 Answer
Android Location Permission 0 Answers
Loading Audio Files at Runtime for Playback and Processing 1 Answer
Removing unecessary permissions from AndroidManifest that Unity+Plugins put in there? 0 Answers