Android Tutorial Runtime Permissions (Android 6.0+ Permissions)

Status
Not open for further replies.
1. Edit: In B4XPages the permission result event signature is: Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
2. Important to read: https://www.b4x.com/android/forum/threads/android-jar-targetsdkversion-minsdkversion.87610/#content



If the targetSdkVersion is lower than 23 then the standard permissions system will be used on all devices including Android 6+, however soon all Google Play apps will need to set the targetSdkVersion to 26+.

B4A v6.0 adds support for runtime permissions. The nice thing about runtime permissions is that the user is not asked for any permission when they install your application from Google Play. Instead they will be asked to approve "dangerous" permissions at runtime.

Luckily most permissions are not considered dangerous. You can see the list of permissions that are considered dangerous here: https://developer.android.com/guide/topics/permissions/overview.html#permission-groups



upload_2016-6-8_14-48-39.png


The CheckAndRequest method can only be called from an Activity.
There is another method named Check that only tests whether the permission has already been approved or not. This method can be called from any module.
It might be tempting to first test whether there is a permission and only if there is no permission call CheckAndRequest. However it will just make the program flow more complicated as you will need to deal with all cases anyway.
As a general rule, you shouldn't call RuntimePermissions.Check from an Activity. It will be simpler to always call CheckAndRequest.

Listing the permissions

Not many are aware to the fact that you can see the project permissions by clicking on the List Permissions button that is inside the Logs tab:
A very common mistake is to request a permission at runtime that is not listed in the "permissions dialog". It will not work.
SS-2016-06-08_15.06.00.png


The dangerous permissions are marked with * (in B4A v6+).
You don't need to ask for non-dangerous permissions.

READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE

This is the most common dangerous permission. It is added automatically when you use File.DirDefaultExternal or File.DirRootExternal.
However there is a simple workaround for this.

1. Use RuntimePermissions.GetSafeDirDefaultExternal("") instead of File.DirDefaultExternal. The parameter passed is an optional subfolder that will be created under the default folder.

2. Add this code to the manifest editor:
B4X:
AddManifestText(
<uses-permission
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"
  android:maxSdkVersion="19" />
)
The explanation for this is that GetSafeDirDefaultExternal doesn't require any permission on Android 4.4+ (API 19) and requires the WRITE_EXTERNAL_STORAGE on older versions. The code above adds the permission to older devices.

You only need to deal with WRITE_EXTERNAL_STORAGE at runtime if you need access to a folder other than the app's default external folder.

Notes & tips:

- You can only request permissions that were declared in the manifest file (this is usually taken care by the compiler).
- Testing the permissions can be confusing as the user only needs to give permissions once. The solution is to uninstall the app from the device. Click on Ctrl + P (clean project) in the IDE and run again.
- The user actually approves groups of permissions. So if the user has approved the read contacts permission they will not be asked to approve the write contacts permission.
- Once you've uploaded your app to Google Play with targetSdkVersion set to 23 you cannot downgrade the target version back.
- Some Android 4.4 (API 19) devices do not allow access to RuntimePermissions.GetSafeDirDefaultExternal without explicit permission although they should. It it therefore recommended to set android:maxSdkVersion to 19 in the version based permission. It was previously set to 18.
 
Last edited:

Computersmith64

Well-Known Member
Licensed User
Longtime User
So my understanding of GetSafeDirDefaultExternal is that it is still related to the app - so if the app is removed, so is that folder & any data stored in it, correct? If so, then it's not a good alternative to DirRootExternal for items that you want to persist after the app is uninstalled. For example, in some of my apps, I give the user the option to back up & restore stats & high scores (& in one case a database). They are backed up to DirRootExternal so that if for any reason the user needs to uninstall/reinstall the app, they can restore their stats & scores (or in the case of the database, all the data they have entered).

I'm guessing that this wouldn't work using GetSafeDirDefaultExternal?

- Colin.
 

asales

Expert
Licensed User
Longtime User
So my understanding of GetSafeDirDefaultExternal is that it is still related to the app - so if the app is removed, so is that folder & any data stored in it, correct?
Yes.
If so, then it's not a good alternative to DirRootExternal for items that you want to persist after the app is uninstalled. For example, in some of my apps, I give the user the option to back up & restore stats & high scores (& in one case a database). They are backed up to DirRootExternal so that if for any reason the user needs to uninstall/reinstall the app, they can restore their stats & scores (or in the case of the database, all the data they have entered).
Yes. The backup of my app is always write in DirRootExternal (/MyBackups, before send to mail or dropbox) and now I updated my apps with B4A v.8 and included the RuntimePermissions to get permission to write the backups.
 
Last edited:

Computersmith64

Well-Known Member
Licensed User
Longtime User
[QUOTE = "asales, post: 575271, member: 48906"] incluí las RuntimePermissions para obtener permiso para escribir las copias de seguridad. [/ QUOTE]
How?
B4X:
File.MakeDir(File.DirRootExternal, "dirname")

- Colin.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
[QUOTE = "asales, post: 575271, member: 48906"] incluí las RuntimePermissions para obtener permiso para escribir las copias de seguridad. [/ QUOTE]
How?
Oops - getting runtime permissions is well explained in post #1 of this thread.

- Colin.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Yes, but it does not work like that
You're going to have to be more specific. What are you trying to do? If you're trying to obtain runtime permissions in apps targeting SDK 23+ on devices running Android 6+, then the code that Erel wrote in post #1 is what you want.

If you're trying to do something else, then you might want to start a new thread that explains the issue(s) you are having. :)

- Colin.
 

Johan Hormaza

Well-Known Member
Licensed User
Longtime User
[QUOTE = "Computersmith64, post: 575283, miembro: 46005"] Vas a tener que ser más específico. ¿Que estás tratando de hacer? Si intenta obtener permisos de tiempo de ejecución en aplicaciones que se dirigen al SDK 23+ en dispositivos con Android 6+, entonces el código que Erel escribió en la publicación n. ° 1 es lo que desea.

Si intenta hacer algo más, entonces puede comenzar un nuevo hilo que explique los problemas que está teniendo. :)

- Colin. [/ QUOTE]
ok thank!!!
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
- Testing the permissions can be confusing as the user only needs to give permissions once. The solution is to uninstall the app from the device. Click on Ctrl + P (clean project) in the IDE and run again.

Actually, on later Android versions you can go into app manager (Settings->Apps or Settings->Apps & Notifications), tap on the app->Permissions & then turn the permission(s) on/off. If you happen to turn the permission off while the app is running, Android will kill the app & when you restart it you can test the permission again.

- Colin.
 

gregchao

Member
Licensed User
Longtime User
Got this to work on my app but I struggled a little:

1. When I set the SDK to 26, my app stopped working without any explanation. Further investigation revealed that the permissions in the manifest were being ignored because you have to now set the permissions as outlined above.
2. When app is installed, popup occurs to ask user for permissions once. It does not occur every time.

Here is my code for permissions if anyone is interested:

B4X:
Sub Process_Globals
     Private rp as RunTimePermissions
end Sub

Sub Activity_Create(FirstTime As Boolean)
   
    'needed for lastest sdk 26, new permission scheme
    rp.CheckandRequest(rp.PERMISSION_READ_CONTACTS)
    rp.CheckAndRequest(rp.PERMISSION_READ_SMS)
    rp.CheckAndRequest(rp.PERMISSION_SEND_SMS)
    rp.CheckAndRequest(rp.PERMISSION_CALL_PHONE)
    rp.CheckAndRequest(rp.PERMISSION_RECEIVE_SMS)
End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
    If Permission = rp.PERMISSION_READ_CONTACTS Then
        If Result = True Then
           'do something
        Else
            ToastMessageShow("terminating program", True)
            Activity.finish
        End If
    End If
   
    If Permission = rp.PERMISSION_READ_SMS Then
        If Result = True Then
            'do someting
        Else
            ToastMessageShow("terminating program", True)
            Activity.finish
        End If
    End If
   
    If Permission = rp.PERMISSION_RECEIVE_SMS Then
        If Result = True Then
           
        Else
            ToastMessageShow("Auto-update of texts will not work, must restart program for updating tally", True)
        End If
    End If
   
    If Permission = rp.PERMISSION_SEND_SMS Then
        If Result = True Then

        Else
            ToastMessageShow("terminating program", True)
            Activity.finish
        End If
    End If
   
    If Permission = rp.PERMISSION_CALL_PHONE Then
        If Result = True Then
            flagcall = 1
        Else
            ToastMessageShow("Turning off direct call feature", True)
            flagcall = 0  
        End If
    End If
End Sub
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Updated the maxSdkVersion in the version based external storage permission to 19:
B4X:
AddManifestText(
<uses-permission
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"
  android:maxSdkVersion="19" />
)

The explanation is:
Some Android 4.4 (API 19) devices do not allow access to RuntimePermissions.GetSafeDirDefaultExternal without explicit permission although they should. It it therefore recommended to set android:maxSdkVersion to 19 in the version based permission. It was previously set to 18.
 
Status
Not open for further replies.
Top