Can anyone provide an accurate tutorial on how to save files on Android Q publicily available, since getExternalFilesDir() is unavailable to use in Android Q+.
I've been dealing with this issue for some days, and can't figure out any solution.
I am trying to download some css, js, and HTML files for loading them on a Webview.
Right now, I have the following code, written in Kotlin:
companion object {
private const val TAG = "MainActivity"
private var rootDir: Path? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
rootDir = getExternalFilesDir(null)
Log.v(TAG, "RootDir: ${rootDir!!.path}")
val cacheDir = File(rootDir!!, "cache")
if(!cacheDir.exists()) {
Log.v(TAG, "Creating cache dir (${cacheDir.path})")
try {
if (cacheDir.mkdirs())
Log.v(TAG, "Created cache dir correctly")
else
Log.v(TAG, "Could not create cache dir")
}catch (ex: IOException){
Log.e(TAG, "Could not create cache dir: ", ex)
}catch (ex: SecurityException) {
Log.e(TAG, "Not allowed to create cache dir: ", ex)
}
}
val cssDir = File(cacheDir, "css")
if(!cssDir.exists()){
Log.v(TAG, "Creating css dir (${cssDir.path})")
try {
if (cacheDir.mkdirs())
Log.v(TAG, "Created css dir correctly")
else
Log.v(TAG, "Could not create css dir")
}catch (ex: IOException){
Log.e(TAG, "Could not create css dir: ", ex)
}catch (ex: SecurityException) {
Log.e(TAG, "Not allowed to create css dir: ", ex)
}
}
val siteGlobal = File(cssDir, "site_global.css")
if(!siteGlobal.exists())
DownloadFileAsyncTask().execute(DownloadFileAsyncTask.DownloadArgs("...", siteGlobal.path))
}
And DownloadFileAsyncTask:
private class DownloadFileAsyncTask :
AsyncTask<DownloadFileAsyncTask.DownloadArgs, Int, Void?>() {
data class DownloadArgs(val url : String, val savePath : String)
override fun doInBackground(vararg downloadFiles: DownloadArgs?): Void? {
for(downloadFile in downloadFiles) {
val urlStr = downloadFile!!.url
val outputFilePath = downloadFile.savePath
val outputFile = File(outputFilePath)
val url = URL(urlStr)
Log.v(TAG, "Connecting...")
val connection = url.openConnection() as HttpURLConnection
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
throw InterruptedException("Server returned HTTP ${connection.responseCode} ${connection.responseMessage}")
}
Log.v(TAG, "Connection correct")
if (!outputFile.exists()) {
Log.v(TAG, "Creating ${outputFile.path}")
outputFile.createNewFile()
}
val fileLength = connection.contentLength
val input = connection.inputStream
val output = FileOutputStream(outputFile)
val data = ByteArray(4096)
var total: Long = 0
var count: Int
Log.v(TAG, "Starting download...")
while (true) {
count = input.read(data)
if (count < 0) break
total += count
if (fileLength > 0)
publishProgress((total * 10 / fileLength).toInt())
output.write(data, 0, count)
}
output.close()
input?.close()
connection.disconnect()
}
return null
}
}
And my response on Logcat is:
V/MainActivity: RootDir: /storage/emulated/0/Android/data/.../files
V/MainActivity: Creating cache dir (/storage/emulated/0/Android/data/.../files/cache)
V/MainActivity: Created cache dir correctly
V/MainActivity: Creating css dir (/storage/emulated/0/Android/data/.../files/cache/css)
V/MainActivity: Could not create css dir
V/MainActivity: Connecting...
V/MainActivity: Connection correct
V/MainActivity: Creating /storage/emulated/0/Android/data/.../files/cache/css/site_global.css
And obviously, it crashes with java.io.IOException: No such file or directory
at outputFile.createNewFile()
in AsyncTask, since the directory doesn't exist.
Since no error on the folder creation is shown, it only tells that the directory couldn't be created, I don't know what am I doing wrong.
I've added and granted <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in case of it was the issue, and it didn't solve anything.