web-dev-qa-db-fra.com

Android 10 (api-29) écriture de fichiers

Quelqu'un peut-il fournir un didacticiel précis sur la façon d'enregistrer des fichiers sur Android Q publiquement disponible, car getExternalFilesDir () ne peut pas être utilisé dans Android Q +.

Je traite ce problème depuis quelques jours et je ne trouve aucune solution.

J'essaie de télécharger des fichiers css, js et HTML pour les charger sur une vue Web.

En ce moment, j'ai le code suivant, écrit en 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))
}

Et 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
        }
    }

Et ma réponse sur Logcat est:

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

Et évidemment, il plante avec Java.io.IOException: No such file or directory Dans outputFile.createNewFile() dans AsyncTask, car le répertoire n'existe pas.

Puisqu'aucune erreur sur la création de dossier n'est montrée, elle indique seulement que le répertoire n'a pas pu être créé, je ne sais pas ce que je fais mal.

J'ai ajouté et accordé <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" /> Au cas où c'était le problème, et cela n'a rien résolu.

4
Arnyminer Z

getExternalStorageDirectory() est déprécié dans API-29

Vérifiez l'étape

  1. Téléchargez et téléchargez le fichier à partir du serveur Web "Connexion FTP utilisateur. (C'est un moyen mais pas le seul moyen)

Comment télécharger un fichier depuis un serveur FTP vers Android appareil?

  1. Enregistrez-le sur un stockage externe
    //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. Utilisez l'URL de chargement pour charger les fichiers dans la vue Web et injectez comme cette question Android Web-View: Injectez le fichier Javascript local sur la page Web distante et Android - Comment injecter des CSS personnalisés dans une page Web externe dans la vue Web
1
Prashant