web-dev-qa-db-fra.com

Comment permettre aux utilisateurs d'accéder au répertoire de stockage interne de mon application?

Mon application stocke les fichiers dans son répertoire de stockage interne (/Android/data/com.mycompany.myapp/files, tel que renvoyé par getFilesDir ()), et je voudrais autoriser les utilisateurs à accéder à ces fichiers directement à partir d'une application de gestion de fichiers sur leur appareil mobile ou l'application Android File Transfer Desktop Application.

Le Guide du développeur d'options de stockage dit:

Par défaut, les fichiers enregistrés sur le stockage interne sont privés de votre application et les autres applications ne peuvent pas y accéder (ni l'utilisateur).

"Par défaut" implique que je peux modifier les autorisations par défaut pour permettre aux utilisateurs d'accéder à ces fichiers, mais je ne trouve aucune documentation sur la façon de procéder. Actuellement, le répertoire com.mycompany.myapp est masqué lorsque je parcours le répertoire/Android/data avec une application de gestion de fichiers.

J'enregistre actuellement des données de fichier comme ceci:

String fileName = "myfile.jpg";
String filePath = getFilesDir() + File.separator + fileName;
FileOutputStream fileStream = new FileOutputStream(filePath);
fileData.writeTo(fileStream); // fileData is a ByteArrayOutputStream
fileStream.close();

J'ai essayé de définir les autorisations des fichiers individuels sur World-Readable, mais cela n'a pas rendu le répertoire visible:

FileOutputStream fileStream = this.app.openFileOutput(fileName, Context.MODE_WORLD_READABLE);

J'ai également vérifié la documentation du fichier AndroidManifest et n'y ai rien vu. Est-ce que quelqu'un sait comment je peux faire ça?

13
arlomedia

J'ai examiné de plus près le résultat de getFilesDir() vs getExternalFilesDir() et j'ai constaté que getFilesDir() renvoie /data/data/[packagename]/files Tandis que getExternalFilesDir() renvoie /Android/data/[packagename]/files. Je pensais que les fichiers d'application que je parcourais dans /Android/data Étaient les répertoires de stockage internes, mais maintenant je vois que ce sont en fait les répertoires de stockage externes.

Si les répertoires de stockage interne ne sont en effet jamais disponibles pour les utilisateurs réguliers, j'aimerais que la documentation le dise au lieu de dire qu'ils ne sont pas disponibles "par défaut". Pour moi au moins, dire "par défaut" implique que le comportement par défaut peut être changé.

Quoi qu'il en soit, j'ai testé et confirmé que si je supprime mon application, les fichiers enregistrés dans la getExternalFilesDir() sont supprimés automatiquement. Cela répond donc à mon besoin d'un emplacement de stockage clairement connecté à l'application (utilise un nom de répertoire spécifique à l'application et est supprimé avec l'application) mais est accessible aux utilisateurs pour une gestion manuelle occasionnelle des fichiers.

Voici une comparaison qui pourrait être utile à quelqu'un d'autre lisant ceci:

  • getFilesDir () - crée un répertoire spécifique à l'application; caché aux utilisateurs; supprimé avec l'application
  • getExternalFilesDir () - crée un répertoire spécifique à l'application; accessible aux utilisateurs; supprimé avec l'application
  • getExternalStoragePublicDirectory () - utilise un répertoire partagé (par exemple, Musique); accessible aux utilisateurs; reste lorsque l'application est supprimée
45
arlomedia

Je pense que la documentation des développeurs vous embrouille, je ne peux pas vous en vouloir, ce n'est pas la meilleure documentation que j'ai jamais lue. Quoi qu'il en soit, Android fournit deux façons d'enregistrer des fichiers dans le système de fichiers:

  1. Utilisation du stockage interne
  2. Utilisation du stockage externe

Le stockage interne est TOUJOURS disponible et est UNIQUEMENT accessible à votre application, aucune autre application du système ne peut accéder aux fichiers enregistrés par votre application sur cette partition.

Maintenant, je pense que ce dont vous avez besoin est le stockage externe car il est "lisible par le monde" et peut être consulté par n'importe qui et n'importe quelle application. L'inconvénient est qu'il peut ne pas être disponible car l'utilisateur peut le monter sur un périphérique USB - qui peut être retiré par l'utilisateur à tout moment.

Vous ne devez pas utiliser non plus MODE_WORLD_WRITEABLE ni MODE_WORLD_READABLE selon les états de la documentation, car c'est très dangereux. De plus, ces constantes sont obsolètes depuis l'API niveau 17

Recommandation

Si vous devez rendre vos fichiers publics, enregistrez-les dans le stockage externe . Vous devrez déclarer une autorisation dans votre fichier manifeste pour éviter que votre application ne plante à chaque fois qu'elle accède au stockage externe ...

<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />

parce que le stockage externe peut ne pas être disponible, vous devrez en déterminer l'état avant d'effectuer une opération, sinon votre application se bloquera ...

public enum StorageState{
  NOT_AVAILABLE, WRITEABLE, READ_ONLY
}

public StorageState getExternalStorageState() {
    StorageState result = StorageState.NOT_AVAILABLE;
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return StorageState.WRITEABLE;
    }
    else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return StorageState.READ_ONLY;
    }

    return result;
}

Il y a plus d'informations sur la documentation et les choses que vous devez connaître. Par exemple, vous pouvez donner à votre application la propriété de ces fichiers afin que, lorsque votre application est désinstallée, le système puisse automatiquement supprimer ces fichiers. Pour plus d'informations, reportez-vous à la documentation sur le Android

11
Leo

ajoutez ceci pour manifester

puis ajoutez ceci dans votre activité:

private static final String RequieredPermission = Manifest.permission.READ_EXTERNAL_STORAGE;

puis appelez HandlePermission() où vous devez vérifier l'autorisation, généralement dans la méthode Oncreate d'une activité. Ces fonctions sont alors nécessaires:

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Log.d("amir", "onRequestPermissionsResult: called");
        switch (requestCode) {
            case REQUEST_PERMISSION_READING_STATE:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, "Permission Granted!", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
                }
        }

    }

    private void HandlePermission() {
        int permissionCheck = ContextCompat.checkSelfPermission(
                this, RequieredPermission);
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    RequieredPermission)) {
                showExplanationaboutPermission("Permission Needed", "Rationale", RequieredPermission, REQUEST_PERMISSION_READING_STATE);
            } else {
                requestPermission(RequieredPermission, REQUEST_PERMISSION_READING_STATE);
            }
        } else {
            Toast.makeText(MainActivity.this, "Permission (already) Granted!", Toast.LENGTH_SHORT).show();
        }
    }

    private void showExplanationaboutPermission(String title,
                                                String message,
                                                final String permission,
                                                final int permissionRequestCode) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(title)
                .setMessage(message)
                .setPositiveButton(Android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        requestPermission(permission, permissionRequestCode);
                    }
                });
        builder.create().show();
    }

    private void requestPermission(String permissionName, int permissionRequestCode) {
        ActivityCompat.requestPermissions(this,
                new String[]{permissionName}, permissionRequestCode);
    }
0
Nabat Farsi