Android Question fail to create dir

marcick

Well-Known Member
Licensed User
Longtime User
My app is running since two years on a hundred devices and suddenly I have problems creating a directory.
I don't know if it is related to Android 6 or the latest B4A updates.
This is the code

B4X:
Dim AppPath As String=File.DirRootExternal & "/test"
If File.exists("",AppPath)=False Then
   Log("creating apppath")
   File.MakeDir("",AppPath)
End If
If File.exists("",AppPath)=False Then Log("dir not exists")

The code is executed in the StarterService and I have the log "dir not exists" (and the dir is really not created).

If I start from a blank project the code works, as it had worked for two years.
But inside my app, the code fails (I test it in release after a clean project).
Where could be the problem ?

I'm looking for another device to test it, to see if it is device related or not.
 

DonManfred

Expert
Licensed User
Longtime User
if you use api 23 then you need to use the runtimepermissions library to get the correct path... There is a method in RTP lib for this...
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
I was just now realizing that moving back to API22 the problem does not exists ....
I'll search for RTP, many thanks
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
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:
Code:
AddManifestText(
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
)
The explanation for this is that GetSafeDirDefaultExternal doesn't require any permission on Android 4.4+ (API 18) and requires the WRITE_EXTERNAL_STORAGE on older versions. The code above adds the permission to older devices.
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
I'm reading, but it is not clear to me how to obtain the DirRootExternal path.
What to do before using this ?

Dim AppPath As String=File.DirRootExternal & "/test"
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
I've tried this but have the same problem:

B4X:
Private rp As RuntimePermissions
rp.GetAllSafeDirsExternal("")
Dim AppPath As String=File.DirRootExternal & "/test"
If File.exists("",AppPath)=False Then
   Log("creating apppath")
   File.MakeDir("",AppPath)
End If
If File.exists("",AppPath)=False Then Log("dir not exists")
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
You cannot access File.DirRootExternal without the WRITE_EXTERNAL_STORAGE permission.

If you don't want to handle runtime permissions then set the targetSdkVersion to 22 instead of 23. Note that if you have already uploaded your app to Google Play then you cannot change this.

Another, better option is to use a different external storage path such as the one returned from RuntimePermissions.GetSafeDirDefaultExternal("").

Runtime permissions tutorial:
https://www.b4x.com/android/forum/threads/runtime-permissions-android-6-0-permissions.67689/#content
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
I have the WRITE_EXTERNAL_STORAGE permission in the manifest as explained. And I need target 23.
What to do then to access to DirRootExternal ?
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private rp As RuntimePermissions
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim sdcardEnabled As Boolean
End Sub
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    sdcardEnabled = False
End Sub
Sub Activity_Resume
    If sdcardEnabled = False Then
        rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    End If
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Activity_PermissionResult (Permission As String, Result As Boolean)
  If Permission = rp.PERMISSION_WRITE_EXTERNAL_STORAGE Then
     If Result Then
       sdcardEnabled = true
       Log("You NOW can write to File.DirRootExternal")    
       File.WriteString(File.DirRootExternal, "String.txt", _
  "This is some string" & CRLF & "and this is another one.")
     End If
  End If
End Sub
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
I would have removed the sdcardenabled variable. It is not needed (specifically in your code it should be a process_global variable).
Sorry, i used the RTP lib the first time yesterday to create a working code which writes to DirRootExternal.

specifically in your code
Code was simplified to do a write to RootExternal when the permission is granted...

Thank you for correcting me. You are surely right that the variable should be a process global one. Especially for @marcick requirements.
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
Another, better option is to use a different external storage path such as the one returned from RuntimePermissions.GetSafeDirDefaultExternal("").

I'm oriented on this solution, but the actaul app (target 22) is working with DirRootExternal.
If I publish the updated app (target 23) can I simply read the DirRootExternal and copy all what is related to my app to the new path returned by RuntimePermissions.GetSafeDirDefaultExternal("") ?
Or do I need to acquire the permission also for read DirRootExternal ? (this would be a dog biting its tail ...)
 
Upvote 0

marcick

Well-Known Member
Licensed User
Longtime User
My intention moving the existing app to GetSafeDirDefaultExternal, was to avoid the permission request, that cause me troubles in the program flow......
Need to think.
Once again thanks to Google, every update causes us to waste time and invent some workaround.
Once again thanks to the people of this forum that are always here to help us.
 
Upvote 0
Top