web-dev-qa-db-ja.com

Android 10(api-29)ファイル書き込み

getExternalFilesDir() はAndroid Q +では使用できないため、誰でもAndroid Qにファイルを保存する方法に関する正確なチュートリアルを公開できますか?.

私はこの問題に数日間取り組んできましたが、解決策を見つけることができません。

Webビューにロードするために、css、js、およびHTMLファイルをダウンロードしようとしています。

現在、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))
}
_

そして、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
        }
    }
_

そして、Logcatに関する私の応答は次のとおりです。

_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
_

そして明らかに、ディレクトリが存在しないため、AsyncTaskのoutputFile.createNewFile()で_Java.io.IOException: No such file or directory_でクラッシュします。

フォルダーの作成に関するエラーは表示されないため、ディレクトリを作成できなかったことが示されるだけで、何が問題なのかわかりません。

問題が発生した場合に備えて_<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />_を追加して許可しましたが、何も解決しませんでした。

4
Arnyminer Z

getExternalStorageDirectory()はAPI-29で廃止されました

ステップを確認してください

  1. ウェブサーバーからファイルをダウンロードしてアップロードします "ユーザーFTP接続(これは方法ですが、方法だけではありません)

FTPサーバーからAndroidデバイス? にファイルをダウンロードする方法

  1. 外部ストレージに保存します
    //private static void createFile(Context ctx, String fileName, byte text)
    private static void createFile(Context ctx, String fileName, String text) {
        File filesDir = ctx.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
        assert filesDir != null;
        if (!filesDir.exists()){
           if(filesDir.mkdirs()){
            }
        }
        File file = new File(filesDir, fileName);
        try {
            if (!file.exists()) {
                if (!file.createNewFile()) {
                    throw new IOException("Cant able to create file");
                }
            }    
            OutputStream os = new FileOutputStream(file);
            byte[] data = text.getBytes();
            os.write(data);
            os.close();
            Log.e("TAG", "File Path= " + file.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }    
    }
  1. ロードURLを使用してファイルをWebビューにロードし、この質問のように挿入します Android Web-View:ローカルJavascriptファイルをリモートWebページに挿入します および Android-Webビューの外部WebページにカスタムCSSを挿入する方法
1
Prashant