I am creating an upgrade to an old app which used File.DirDefaultExternal to store its databases. Under the newer APIs, when compiled under release mode I'm getting an EACCES permission error error trying to open the file:
I found the (https://www.b4x.com/android/forum/threads/runtime-permissions-android-6-0-permissions.67689/) following information on the new access requests:
I added the manifest text, created a RuntimePermissions object and used its .GetSafeDirDefaultExternal method instead of File.DirDefaultExternal but the error persists.
What did I miss?
B4X:
--------- beginning of main
--------- beginning of system
~i:** Service (starter) Create **
~e:starter_service_create (java line: 940)
~e:java.io.FileNotFoundException: /storage/emulated/0/MyAndroidApp/db_food_data_v02.db3: open failed: EACCES (Permission denied)
~e: at libcore.io.IoBridge.open(IoBridge.java:452)
~e: at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
~e: at anywheresoftware.b4a.objects.streams.File.OpenOutput(File.java:370)
~e: at anywheresoftware.b4a.objects.streams.File.Copy(File.java:336)
~e: at phx.rcc.starter._service_create(starter.java:940)
~e: at java.lang.reflect.Method.invoke(Native Method)
~e: at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
~e: at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
~e: at phx.rcc.starter.onCreate(starter.java:55)
~e: at android.app.ActivityThread.handleCreateService(ActivityThread.java:3808)
~e: at android.app.ActivityThread.access$2100(ActivityThread.java:222)
~e: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1883)
~e: at android.os.Handler.dispatchMessage(Handler.java:102)
~e: at android.os.Looper.loop(Looper.java:158)
~e: at android.app.ActivityThread.main(ActivityThread.java:7229)
~e: at java.lang.reflect.Method.invoke(Native Method)
~e: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
~e: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
~e:Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
~e: at libcore.io.Posix.open(Native Method)
~e: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
~e: at libcore.io.IoBridge.open(IoBridge.java:438)
~e: ... 17 more
java.io.FileNotFoundException: /storage/emulated/0/MyAndroidApp/db_food_data_v02.db3: open failed: EACCES (Permission denied)
at libcore.io.IoBridge.open(IoBridge.java:452)
at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
at anywheresoftware.b4a.objects.streams.File.OpenOutput(File.java:370)
at anywheresoftware.b4a.objects.streams.File.Copy(File.java:336)
at phx.rcc.starter._service_create(starter.java:940)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
at phx.rcc.starter.onCreate(starter.java:55)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3808)
at android.app.ActivityThread.access$2100(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1883)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
at libcore.io.IoBridge.open(IoBridge.java:438)
... 17 more
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:
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
I added the manifest text, created a RuntimePermissions object and used its .GetSafeDirDefaultExternal method instead of File.DirDefaultExternal but the error persists.
What did I miss?