From b5ccf63a85649cc3be3a3093fe46ebb58f896ab6 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 15 Aug 2026 15:44:43 +0100 Subject: [PATCH] feat(android): Skia renders the text, so Arabic reads properly An Arabic attachment name displayed scrambled. Not a missed setting: FMX's original text engine does not shape complex scripts - no bidirectional reordering, no letter joining. Separating the size from the name limited the damage without removing it. Skia carries HarfBuzz and does the work. GlobalUseSkia goes before Application.Initialize; the canvas is chosen at init and switching later does not reclaim what is already built. The price is libsk4d.so, 25 MB raw, and an APK from 13 to 22 MB. Deploy rebuilds library\\lib just before calling aapt, so a hand-placed library disappears. A proper DeployFile entry was tried first - MSBuild ignores it, as it ignores every other one in this project. Hence repack-apk.ps1, which redoes aapt, zipalign and signing on the folder already prepared. Co-Authored-By: Claude Opus 5 --- android-client/PLAN.md | 17 ++++++++++++++++ android-client/README.md | 10 ++++++++++ android-client/repack-apk.ps1 | 37 +++++++++++++++++++++++++++++++++++ pmserverApk.dpr | 17 ++++++++++++++-- pmserverApk.dproj | 12 ++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 android-client/repack-apk.ps1 diff --git a/android-client/PLAN.md b/android-client/PLAN.md index c2cfb24..aac4775 100644 --- a/android-client/PLAN.md +++ b/android-client/PLAN.md @@ -138,6 +138,23 @@ confort, ce qui est le mauvais sens pour un gestionnaire de mots de passe. +## 1 ter. Écritures complexes — Skia (2026-08-15) + +Un nom de pièce jointe en arabe s'affichait en désordre. Ce n'était pas un +réglage manqué : le moteur de texte d'origine de FMX ne met pas en forme les +écritures complexes — pas de réordonnancement bidirectionnel, pas de liaison +des lettres. Séparer la taille du nom limitait les dégâts sans les supprimer. + +`GlobalUseSkia := True` avant `Application.Initialize` remplace le moteur de +rendu ; Skia embarque HarfBuzz et fait ce travail. Le prix est `libsk4d.so`, +25 Mo (8,9 Mo compressés), et un **APK qui passe de 13 à 22 Mo**. + +Conséquence sur la fabrication : `Deploy` reconstruit `library\lib` avant +`aapt`, donc la bibliothèque posée à la main disparaît. D'où +[repack-apk.ps1](repack-apk.ps1), qui refait *aapt → zipalign → signature* sur +le dossier déjà prêt. Une entrée `DeployFile` en bonne et due forme a été +tentée d'abord : MSBuild l'ignore, comme il ignore toutes les autres ici. + ## 2. Durcissement — petit, à faire avant tout usage réel Par ordre de gravité, pas de taille. diff --git a/android-client/README.md b/android-client/README.md index c13b9f2..45d6466 100644 --- a/android-client/README.md +++ b/android-client/README.md @@ -207,6 +207,16 @@ Ensuite `msbuild pmserverApk.dproj /p:Platform=Android64 /p:Config=Debug /t:Deploy` produit et signe `bin\pmserverApk.apk`, et `adb install -r` l'installe. Le correctif durable serait d'écrire ces entrées une fois dans le `.dproj`. +Enfin, **le rendu du texte passe par Skia**, ce qui ajoute `libsk4d.so` à +livrer. `Deploy` reconstruit `library\lib` juste avant d'appeler `aapt`, donc +toute bibliothèque posée à la main y disparaît — et les entrées de déploiement +ne fonctionnent pas ici. D'où un dernier passage qui refait *aapt → zipalign → +signature* sur le dossier déjà prêt, sans le vider : + +```bash +android-client\repack-apk.ps1 +``` + > **Place disque.** Le `.so` de debug pèse **91 Mo** (symboles), et le volume > `Z:` n'en fait que 2 Go. Le dépouiller avec le `strip` du NDK le ramène à > 54 Mo, et l'APK final à 16 Mo — mais `strip` écrit sa copie temporaire **à diff --git a/android-client/repack-apk.ps1 b/android-client/repack-apk.ps1 new file mode 100644 index 0000000..1cbdc16 --- /dev/null +++ b/android-client/repack-apk.ps1 @@ -0,0 +1,37 @@ +# Refait les trois dernieres etapes de l'empaquetage Android, sur le dossier +# deja prepare - sans le vider au prealable. +# +# POURQUOI : la cible Deploy de MSBuild reconstruit library\lib avant d'appeler +# aapt, ce qui efface toute bibliotheque native ajoutee a la main. Or ce projet +# n'a pas d'entrees de deploiement fonctionnelles (voir README), donc libsk4d.so +# - le moteur Skia, indispensable au rendu de l'arabe - ne peut y arriver +# autrement. On laisse donc Deploy faire son travail, puis on remet la +# bibliotheque et on refait aapt / zipalign / signature. +# +# A lancer depuis la racine du depot, apres un Deploy reussi. + +$ErrorActionPreference = 'Stop' + +$sdk = 'C:\Users\Public\Documents\Embarcadero\Studio\23.0\CatalogRepository\AndroidSDK-2525-23.0.51511.6924' +$bds = 'C:\Program Files (x86)\Embarcadero\Studio\23.0' +$jdk = 'C:\Program Files\Eclipse Adoptium\jdk-11.0.15.10-hotspot' +$pac = "$bds\bin\paclient.exe" +$p = '.\Android64\Debug\pmserverApk' + +# 1. Remettre Skia, que Deploy vient d'effacer. +Copy-Item "$bds\binandroid64\libsk4d.so" "$p\library\lib\arm64-v8a\libsk4d.so" -Force + +# 2. aapt : reconstruit l'archive non alignee depuis library, classes, res. +& $pac -u8 --aaptpackage="$sdk\build-tools\33.0.2\Aapt.exe,$p\library,$p\classes,$p\res,$p\assets,$p\AndroidManifest.xml,$sdk\platforms\android-33\android.jar,$p\bin\pmserverApk-unaligned.apk" +if ($LASTEXITCODE -ne 0) { throw "aapt a echoue" } + +# 3. zipalign refuse d'ecraser sa sortie : l'APK precedent doit disparaitre. +Remove-Item "$p\bin\pmserverApk.apk" -Force -ErrorAction SilentlyContinue +& $pac -u8 --zipalign="$sdk\build-tools\33.0.2\ZipAlign.exe,$p\bin\pmserverApk-unaligned.apk,$p\bin\pmserverApk.apk,4" +if ($LASTEXITCODE -ne 0) { throw "zipalign a echoue" } + +& $pac -u8 --apksign="$jdk\bin\java.exe,$sdk\build-tools\33.0.2\lib\apksigner.jar,$p\bin\pmserverApk.apk,androiddebugkey,$env:APPDATA\Embarcadero\BDS\23.0\debug.keystore,android,android" +if ($LASTEXITCODE -ne 0) { throw "signature echouee" } + +$apk = Get-Item "$p\bin\pmserverApk.apk" +"APK {0:N1} Mo" -f ($apk.Length / 1MB) diff --git a/pmserverApk.dpr b/pmserverApk.dpr index edbbc44..0dd6b7d 100644 --- a/pmserverApk.dpr +++ b/pmserverApk.dpr @@ -3,6 +3,16 @@ program pmserverApk; uses System.StartUpCopy, FMX.Forms, + // Skia remplace le moteur de rendu de FMX. Ce n'est pas un choix esthetique : + // celui d'origine ne met pas en forme les ecritures complexes - pas de + // reordonnancement bidirectionnel, pas de liaison des lettres arabes - et un + // nom de piece jointe en arabe s'affichait donc en desordre. Skia embarque + // HarfBuzz et fait ce travail correctement. + // + // Le prix est libsk4d.so, 25 Mo, a poser dans lib/arm64-v8a de l'APK. Le + // deploiement automatique s'en chargerait ; ici il ne deploie rien, donc la + // bibliotheque est mise en place a la main comme le manifeste et les .dex. + FMX.Skia, mainApk in 'mainApk.pas' {Form8}, PMA.Crypto in 'android-client\PMA.Crypto.pas', PMA.TestVector in 'android-client\PMA.TestVector.pas', @@ -18,9 +28,12 @@ uses {$R *.res} begin + // AVANT Application.Initialize : le canevas est choisi a l'initialisation, + // et le basculer ensuite ne rattrape pas ce qui est deja construit. + GlobalUseSkia := True; Application.Initialize; - // Avant la creation de la forme : appliquer un style apres coup laisse les - // controles deja construits avec l'ancien. + // Le style se pose apres l'initialisation mais avant la forme : l'appliquer + // plus tard laisserait les controles deja construits avec l'ancien. ApplyDarkTheme; Application.CreateForm(TForm8, Form8); Application.Run; diff --git a/pmserverApk.dproj b/pmserverApk.dproj index 747c126..47a1f89 100644 --- a/pmserverApk.dproj +++ b/pmserverApk.dproj @@ -344,6 +344,18 @@ true + + + libsk4d.so + true + + + + + library\lib\arm64-v8a + 1 + + 1