Nouvelles fonctionnalités d'Android 11, Scoped Storage a une nouvelle astuce

Cet article est publié simultanément sur mon compte officiel WeChat. Scannez le code QR en bas de l'article ou recherchez Guo Lin sur WeChat à suivre. L'article est mis à jour chaque jour ouvrable.

Cela fait plus d'un an et demi depuis la sortie officielle d'Android 11 et il est temps d'écrire des articles sur les nouvelles fonctionnalités d'Android 11.

Au début, j'ai probablement appris quelques changements de comportement sur Android 11. Bien qu'il y ait beaucoup de changements en général, il n'y a pas beaucoup d'endroits qui nécessitent une adaptation. Un domaine qui devra peut-être être adapté est le changement d'autorisation d'Android 11. Concernant cette partie du contenu, je supporte désormais Java dans PermissionX! Il existe également une explication des modifications des autorisations d'Android 11. Cet article a déjà fourni une explication plus détaillée.

De plus, dans Scoped Storage, Android 11 a quelques nouvelles modifications. Dans cet article, nous allons nous concentrer sur cette partie.

Stockage étendu

En fait, Scoped Storage n'est pas une nouvelle fonctionnalité lancée sur Android 11, mais elle existe déjà sous Android 10. Et j'ai également écrit un article pour expliquer cette fonctionnalité à l'époque. Vous pouvez vous référer aux points d'adaptation et à la portée d' Android 10. Stockage .

Ne vous inquiétez pas, le contenu décrit dans l'article précédent n'est pas obsolète. Les fonctions qui étaient disponibles sur Android 10 à l'époque sont toujours disponibles sur Android 11, mais Android 11 a enrichi et étendu Scoped Storage. Il ne fait donc aucun doute que c'est l'objet de notre article.

Forcer l'activation du stockage à portée

Tout d'abord, dans Android 11, Scoped Storage est activé de force.

Alors, que signifie le forcer?

Bien qu'il existe également une fonction Scoped Storage dans Android 10, Google considère qu'il faut du temps pour s'adapter à un large éventail d'applications, cette fonction n'est donc pas obligatoire.

Tant que le targetSdkVersion spécifié par l'application est inférieur à 29, ou que le targetSdkVersion est égal à 29, mais la configuration suivante est ajoutée à AndroidManifest.xml:

<manifest ... >
  <application android:requestLegacyExternalStorage="true" ...>
    ...
  </application>
</manifest>

Ensuite, la fonction Scoped Storage ne sera pas activée.

La configuration ci-dessus est toujours valide dans Android 11, mais uniquement lorsque la targetSdkVersion est inférieure ou égale à 29. Si votre targetSdkVersion est égal à 30, Scoped Storage sera activé de force et l'indicateur requestLegacyExternalStorage sera ignoré.

Y a-t-il donc un impact sur les développeurs après l'activation du stockage étendu?

En fait, si votre application a été adaptée à Scoped Storage de la manière expliquée dans cet article, selon les points d'adaptation Android 10, Scoped Storage, alors félicitations, maintenant vous n'avez rien à faire, vous pouvez déjà vous adapter à Android 11 systèmes.

En d'autres termes, pour la plupart des développeurs, forcer l'activation de Scoped Storage n'a aucun effet, tant que votre application a déjà été adaptée à Android 10 Scoped Storage.

Mais il existe un type d'application très spécial, c'est-à-dire des navigateurs de fichiers, tels que Root Explorer, ES Explorer, etc. La fonction fournie par ce type de programme lui-même est de parcourir et de gérer les fichiers sur SD, et une fois que Scoped Storage est activé de force, il n'y a essentiellement aucun concept de navigation de fichiers, et nous ne pouvons pas gérer les fichiers avec leurs chemins réels.

De ce point de vue, Scoped Storage a causé un coup terrible aux programmes de navigateur de fichiers. Mais ne vous inquiétez pas, Google propose toujours une autre solution pour ce type de programme, apprenons-en ci-dessous.

Gérez tous les fichiers sur l'appareil

Tout d'abord, indiquez clairement que l'activation obligatoire de Scoped Storage dans Android 11 vise à mieux protéger la confidentialité des utilisateurs et à fournir une protection des données plus sécurisée. Pour la plupart des applications, l'API fournie par MediaStore peut déjà répondre à vos besoins de développement. Si vous n'avez pas d'exigence similaire au développement d'un navigateur de fichiers, essayez de ne pas utiliser la technologie qui sera introduite ensuite.

Avoir des autorisations de lecture et d'écriture pour l'ensemble de la carte SD est considéré comme une autorisation très dangereuse sur Android 11. Cela peut également avoir un impact plus important sur la sécurité des données de l'utilisateur.

Mais le navigateur de fichiers doit gérer l'intégralité de la carte SD de l'appareil, que dois-je faire? Pour ces autorisations extrêmement dangereuses, Google utilise généralement Intent pour accéder à une page d'autorisation spéciale afin de guider les utilisateurs vers une autorisation manuelle, telle que des fenêtres flottantes, des services d'accessibilité, etc.

Oui, sous Android 11, si vous souhaitez gérer des fichiers sur l'ensemble de l'appareil, vous devez également utiliser des techniques similaires.

Tout d'abord, vous devez déclarer l'autorisation MANAGE_EXTERNAL_STORAGE dans AndroidManifest.xml, comme indiqué ci-dessous:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.scopedstoragedemo">

    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />

</manifest>

Notez que par rapport à la déclaration traditionnelle d'une permission, un attribut tel que tools: ignore = "ScopedStorage" est ajouté ici. Parce que si vous n'ajoutez pas cet attribut, Android Studio nous rappellera avec un avertissement que la plupart des applications ne devraient pas demander cette autorisation, comme je l'ai présenté précédemment.

Le travail suivant est également assez simple. Nous pouvons utiliser l'action ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION pour accéder à la page d'autorisation spécifiée. Vous pouvez utiliser la fonction Environment.isExternalStorageManager () pour déterminer si l'utilisateur est autorisé. Ci-dessous, j'écris un code relativement simple pour démontrer ceci fonction:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R ||
        Environment.isExternalStorageManager()) {
    
    
    Toast.makeText(this, "已获得访问所有文件权限", Toast.LENGTH_SHORT).show()
} else {
    
    
    val builder = AlertDialog.Builder(this)
        .setMessage("本程序需要您同意允许访问所有文件权限")
        .setPositiveButton("确定") {
    
     _, _ ->
            val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
            startActivity(intent)
        }
    builder.show()
}

On peut voir que si la version du système est inférieure à Android 11, ou que Environment.isExternalStorageManager () retourne true, cela signifie que nous avons déjà le pouvoir de gérer l'intégralité de la carte SD. Vous pouvez désormais utiliser directement la méthode traditionnelle d'écriture pour manipuler les fichiers sous la forme de leurs chemins réels.

Et s'il n'y a pas d'autorisation pour gérer la carte SD, une boîte de dialogue apparaîtra pour informer l'utilisateur de la raison de la demande d'autorisation, puis utiliser Intent pour accéder à la page d'autorisation spécifiée et permettre à l'utilisateur d'autoriser manuellement.

L'effet de fonctionnement du programme est illustré dans la figure ci-dessous:

Avec cette autorisation, vous pouvez développer le navigateur de fichiers comme vous le connaissez par le passé.

Mais il y a une dernière chose à noter. Même si nous sommes autorisés à gérer la carte SD, de nombreuses ressources du répertoire Android sont toujours restreintes. Par exemple, le répertoire Android / data n'est en aucun cas accessible sous Android 11. Étant donné que les informations de données de nombreuses applications seront stockées dans ce répertoire, le but de cette restriction est principalement de prendre en compte la sécurité des données de l'utilisateur. Sinon, il semble inapproprié d'autoriser WeChat à lire les données dans Taobao.

Opérations par lots

Examinons une autre nouvelle fonctionnalité de Scoped Storage dans Android 11.

Scoped Storage stipule que chaque application a le droit de fournir des données à MediaStore, comme l'insertion d'une image dans un album de téléphone mobile. Il a également l'autorisation de lire les données fournies par d'autres applications, telles que l'obtention de toutes les images de l'album du téléphone. Ces fonctionnalités sont illustrées dans cet article sur les points d'adaptation Android 10 et le stockage de portée.

Cependant, si vous souhaitez modifier les données fournies par d'autres applications, désolé, Scoped Storage ne vous permet pas de le faire.

La raison est également très simple: si vous insérez une image dans l'album de votre téléphone, vous avez certainement le pouvoir de la modifier arbitrairement. Mais si cette image est insérée dans l'album du téléphone par une autre application, vous pouvez la modifier de manière arbitraire. Il s'agit d'un autre risque de sécurité dans la vue de Google, donc Scoped Storage limite cette fonction.

Cependant, que se passe-t-il si certaines applications ont juste besoin de modifier les données fournies par d'autres applications? De tels exemples ne sont pas difficiles à trouver, tels que Photoshop, Meitu Xiuxiu, etc. Leur but est de modifier les images de l'album du téléphone portable, que les images soient créées ou non par elles-mêmes.

Pour résoudre ce problème, Android 10 propose une solution:

try {
    
    
    contentResolver.openFileDescriptor(imageContentUri, "w")?.use {
    
    
        Toast.makeText(this, "现在可以修改图片的灰度了", Toast.LENGTH_SHORT).show()
    }
} catch (securityException: SecurityException) {
    
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    
    
        val recoverableSecurityException = securityException as?
            RecoverableSecurityException ?:
            throw RuntimeException(securityException.message, securityException)

        val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender
        intentSender?.let {
    
    
            startIntentSenderForResult(intentSender, IMAGE_REQUEST_CODE,
                    null, 0, 0, 0, null)
        }
    } else {
    
    
        throw RuntimeException(securityException.message, securityException)
    }
}

Laissez-moi vous expliquer brièvement ce code.

Tout d'abord, le but de ce code est de modifier l'échelle de gris d'une image, mais comme cette image n'est pas apportée par l'application actuelle, théoriquement l'application actuelle n'a pas le pouvoir de modifier l'échelle de gris de cette image.

Alors évidemment, nous n'avons pas la permission de modifier, mais que se passe-t-il si nous insistons pour modifier? Ceci est facile à comprendre et, bien sûr, une exception est levée. Voici donc une méthode try catch pour envelopper l'opération en niveaux de gris d'image, puis juger dans le bloc de code catch, si la version actuelle du système est supérieure ou égale à Android 10 et que le type d'exception est RecoverableSecurityException, cela signifie que cela est due à des restrictions de stockage étendues entraînant des opérations anormales sans autorisation.

Ensuite, nous obtiendrons un intentSender de l'objet RecoverableSecurityException, puis utiliserons ce intentSender pour accéder à la page et guiderons l'utilisateur pour qu'il nous accorde manuellement l'autorisation de modifier cette image. L'effet de l'opération est le suivant:

Bien que cette méthode soit faisable, elle présente un inconvénient très évident: nous ne pouvons manipuler qu'une seule image à la fois. Si un programme a besoin de modifier de nombreuses images, il n'y a pas de bon moyen. Vous ne pouvez demander l'autorisation pour chaque image que de la manière ci-dessus.

Je pense que Google est également conscient de ce problème, il a donc introduit une nouvelle fonctionnalité appelée opérations par lots dans Android 11, qui nous permet de demander plusieurs autorisations d'opération de fichiers à la fois.

L'utilisation des opérations par lots est également bien comprise. Google propose au total 4 types d'API d'application d'autorisation, comme indiqué ci-dessous:

  • createWriteRequest () est utilisé pour demander l'autorisation d'écriture sur plusieurs fichiers.
  • createFavoriteRequest () est utilisé pour demander l'autorisation d'ajouter plusieurs fichiers aux Favoris.
  • createTrashRequest () est utilisé pour demander l'autorisation de déplacer plusieurs fichiers vers la corbeille.
  • createDeleteRequest () est utilisé pour demander l'autorisation de supprimer plusieurs fichiers.

Les deux interfaces les plus couramment utilisées sont createWriteRequest () et createDeleteRequest (). Ici, nous prenons createWriteRequest () comme exemple.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    
    
    val urisToModify = listOf(uri1, uri2, uri3, uri4)
    val editPendingIntent = MediaStore.createWriteRequest(contentResolver, urisToModify)
    startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
            null, 0, 0, 0)
}

Le code est très simple. Tout d'abord, nous créons une collection pour stocker tous les fichiers Uris à appliquer pour les autorisations par lots, puis appelons la fonction createWriteRequest () pour créer un PendingIntent, puis appelons startIntentSenderForResult pour demander des autorisations.

En ce qui concerne le résultat de l'application d'autorisation, nous pouvons surveiller dans onActivityResult ():

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    
    
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
    
    
        EDIT_REQUEST_CODE -> {
    
    
            if (resultCode == Activity.RESULT_OK) {
    
    
                Toast.makeText(this, "用户已授权", Toast.LENGTH_SHORT).show()
            } else {
    
    
                Toast.makeText(this, "用户没有授权", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

Le résultat en cours d'exécution du programme est indiqué dans la figure ci-dessous:

L'utilisation de plusieurs autres API est exactement la même, je ne répéterai donc pas l'exemple ici.

Voyant cela, certains amis peuvent dire que les API fournies par Android 10 et Android 11 sont complètement différentes. Android 10 s'appuie sur le mécanisme de capture d'exception pour analyser l'intentionSender de RecoverableSecurityException, tandis qu'Android 11 peut directement utiliser l'API fournie par les opérations Batch. Créer intentSender. Dois-je écrire deux jeux de codes pour Android 10 et Android 11 dans un projet à adapter?

C'est en effet un casse-tête, et je pense qu'il est principalement causé par la conception déraisonnable de l'API de Google dans Android 10. Le schéma qui repose sur le mécanisme de capture d'exceptions ne peut en aucun cas être considéré comme une excellente conception d'API.

Mais avec plus de réflexion plus tard, j'ai trouvé que ce n'est pas un problème insoluble, et la solution est toujours très simple.

Pourquoi? N'oubliez pas qu'il n'est pas obligatoire d'activer le stockage scoped dans Android 10, nous pouvons configurer l'indicateur requestLegacyExternalStorage dans AndroidManifest.xml pour désactiver le stockage scoped. Dans ce cas, Android 10 ne nécessite aucune adaptation. Il suffit d'utiliser une API plus scientifique et standardisée dans Android 11 pour l'adaptation du stockage Scoped.

Eh bien, cet article se termine ici. J'ai écrit tous les exemples de code de l'article sous forme de démonstration et je l'ai mis sur GitHub. Les amis dans le besoin peuvent le consulter sur le site Web suivant:

https://github.com/guolindev/ScopedStorageDemo

De plus, si vous souhaitez apprendre Kotlin et les dernières connaissances d'Android, vous pouvez vous référer à mon nouveau livre "First Line of Code 3rd Edition" , cliquez ici pour plus de détails .


Faites attention à mon compte public technique et publiez des articles techniques de haute qualité chaque jour ouvrable.

Scannez le code QR ci-dessous sur WeChat pour suivre:

Je suppose que tu aimes

Origine blog.csdn.net/sinyu890807/article/details/113954552
conseillé
Classement