feat(android): attachments can be saved, section 3 item 1 is done
Two questions, and the code was only the second one. WHERE THE FILE LANDS. The private directory is useless - no file manager opens it and it leaves with the uninstall - and direct external storage has been closed since Android 10. Of the three remaining doors, MediaStore -> Downloads is the only one needing neither a permission nor an extra screen: since API 29 an app may write what it inserted itself. The destination picker would need an activity result, which FMX makes painful; sharing would need a FileProvider in the manifest. Below API 29 it would take WRITE_EXTERNAL_STORAGE - one of the ten permissions just removed - so it refuses and says so. WHERE THE CONTENT IS. TVault drops it on purpose: a single attachment took the cache from 13 to 174 Ko. It is re-read from the raw snapshot, which has been in memory ever since saving stopped fetching before publishing. The same data now serves two needs that had nothing to do with each other. Decoding and writing happen off the main thread, under the waiting veil: a few megabytes would freeze the screen, and the veil would not even paint. What leaves the application leaves its protection: the file lands in the clear in Downloads. The confirmation names the place rather than saying "saved". Release configuration compiles too - checked, since that is what section 5 caught out.
This commit is contained in:
+29
-1
@@ -271,7 +271,35 @@ Par ordre de gravité, pas de taille.
|
||||
|
||||
Rangé par ce que ça apporte réellement sur un téléphone.
|
||||
|
||||
1. **Pièces jointes** — *listées*, pas encore enregistrables.
|
||||
1. ~~**Pièces jointes**~~ — **enregistrables depuis le 2026-08-22.**
|
||||
|
||||
Deux questions, et le code n'était que la seconde.
|
||||
|
||||
**Où le fichier atterrit.** Le répertoire privé ne sert à rien — aucun
|
||||
gestionnaire de fichiers ne l'ouvre, et il part avec la désinstallation. Le
|
||||
stockage externe direct est fermé depuis Android 10. Restaient trois portes :
|
||||
`MediaStore` → *Téléchargements*, le sélecteur de destination
|
||||
(`ACTION_CREATE_DOCUMENT`), le partage (`ACTION_SEND`). **MediaStore**, parce
|
||||
que c'est la seule qui ne demande **ni permission ni écran supplémentaire** :
|
||||
depuis l'API 29, une application peut écrire ce qu'elle a elle-même inséré.
|
||||
Le sélecteur exigerait un retour d'activité, que FMX rend pénible ; le
|
||||
partage, un `FileProvider` au manifeste.
|
||||
En dessous de l'API 29 il faudrait `WRITE_EXTERNAL_STORAGE` — précisément
|
||||
l'une des dix permissions retirées en §5. On refuse et on le dit.
|
||||
|
||||
**Où retrouver le contenu.** `TVault` le jette à la lecture, et c'est voulu :
|
||||
une seule pièce jointe faisait passer le cache de 13 à 174 Ko. Il se relit
|
||||
donc dans **l'instantané brut**, qui est en mémoire depuis que
|
||||
l'enregistrement ne tire plus avant de publier — la même donnée sert
|
||||
maintenant deux besoins qui n'avaient rien à voir.
|
||||
|
||||
Décodage et écriture hors du thread principal, sous le voile d'attente :
|
||||
quelques mégaoctets figeraient l'écran, et le voile ne se peindrait même pas.
|
||||
|
||||
**Ce qui sort de l'application sort de sa protection** : le fichier atterrit
|
||||
en clair dans *Téléchargements*, lisible par tout ce qui les lit. C'est ce
|
||||
que l'utilisateur demande en appuyant, et le message de confirmation nomme
|
||||
l'endroit plutôt que de dire « enregistré ».
|
||||
|
||||
Une seule pièce jointe a fait passer le cache de **13 à 174 Ko** : le
|
||||
contenu voyage en base64 dans l'instantané, et il est déchiffré en mémoire
|
||||
|
||||
Reference in New Issue
Block a user