Affichage d'un document Office sous Android

4,305 views
4,207 views

Published on

Présentation réalisée à l'occasion de Devoxx France 2012.
Auteurs : Johann Hilbold et Alain Boudard

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,305
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
25
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Affichage d'un document Office sous Android

  1. 1. Visualiser un documentdans une appli Android by Johann Hilbold & Alain Boudard @OxianeIT 1
  2. 2. Abstract• Ce que je veux faire: afficher un document Office ou PDF dans une application Android• Comment pallier à l‟absence de gestion native des documents Office et PDF?• Présentation des différentes solutions• Un retour sur expérience d‟une aventure folle  Portabilité de Java vers Android  Utilisation du code natif “quand y‟a pas le choix!” 2
  3. 3. Johann Hilbold & Alain BoudardDéveloppeur Android Développeur AndroidDéveloppeur Swing à ses débuts WebdesignerOxiane Oxiane Studio 3
  4. 4. Plan• Introduction• Contraintes• Solutions• Conclusion 4
  5. 5. Contraintes• Ne pas sortir de l‟application pour ouvrir un document (!)• Ne pas sortir le document du SI (= pas de google docs)• Afficher des documents Office (Office 2003, 2007) et PDF 5
  6. 6. Solutions• Afficher un document Office « binaire » dans une app• Afficher un document Office « xml » dans une app• Afficher un PDF dans une app 6
  7. 7. Afficher un fichier Office « binaire » - 1C‟est l‟exemple le plus simple:Il suffit d‟utiliser la librairie Apache POI.3 jars à télécharger:• poi-scratchpad-3.8.jar,• poi-3.8.jar• et commons-codec.jarCopier des fichiers de test dans le répertoire Assets 7
  8. 8. Afficher un fichier Office « binaire » - 2public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);//copier les fichiers de test depuis mon répertoire assets vers la SDCard copyAssetToSDCard("test.doc"); copyAssetToSDCard("testxls.xls");//lancer la conversion avec les jars dapache POI(source, dest) WordToHtmlConverter.main(new String[]{"/mnt/sdcard/test.doc","/mnt/sdcard/test.html"}); ExcelToHtmlConverter.main(new String[]{"/mnt/sdcard/testxls.xls", "/mnt/sdcard/testxls.html"});} 8
  9. 9. Afficher un fichier Office « binaire » - 3private final int BUF_SIZE = 8192;private File copyAssetToSDCard(String assetName) { File copiedFileStoragePath = new File("/mnt/sdcard/"+assetName); BufferedInputStream bis = null; OutputStream dexWriter = null; try { bis = new BufferedInputStream(getAssets().open(assetName)); dexWriter = new BufferedOutputStream(new FileOutputStream(copiedFileStoragePath)); byte[] buf = new byte[BUF_SIZE]; int len; while((len = bis.read(buf, 0, BUF_SIZE)) > 0) { dexWriter.write(buf, 0, len); } dexWriter.close(); bis.close(); } catch (Exception e) {e.printStackTrace(); return null;} Log.d("OfficeCopy", "copied "+assetName+" to /sdcard"); return copiedFileStoragePath;} 9
  10. 10. Afficher un fichier Office « binaire » - 4 Et voila! Maintenant, on peut afficher le résultat dans une webviewWebView v = (WebView) findViewById(R.id.ma_web_view);v.loadUrl("file://mnt/sdcard/test.html"); DEMO 10
  11. 11. Afficher un document Office « xml » - 1Apache POI offre des services de lecture/écriture de fichiers Open XMLMais c‟est plus compliqué!Si on essaye la méthode précédente (documents binaires)…org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF) 11
  12. 12. Afficher un document Office « xml » - 2 Utilisation d‟Apache POI – XSSFLe plan:Utiliser le même raisonnement que pour les documents « binaires »: • télécharger les jars pour les documents Open XML http://poi.apache.org/overview.html#components  OK! • Les ajouter au build path  OK! • Créer une petite classe pour appeler les bonnes méthodes org.apache.poi.ss.examples.html.ToHtml.main(String[] files)  OK! • Lancer le projet et prier!  NOK! 12
  13. 13. Afficher un document Office « xml » - 3Que s‟est-il passé?Avant même de pouvoir installer l‟APK sur le device,[Dex Loader] Unable to execute dex: null[myProject] Conversion to Dalvik format failed: Unable to execute dex: nullLors de la génération du fichier APK, tous les fichiers .class sont transformés en un unique fichier .dex (Dalvik EXecutable).Cette transformation est limitée à 64k références de méthodes (!)Nos jars (de 24Mo) pèsent plus de 64k méthodes! 13
  14. 14. Afficher un document Office « xml » - 4 La solution du blog Android DevelopperIl « suffit » de découper nos classes en plusieurs fichiers .jarPuis de lancer la dx.bat sur chacun des jarsIl convient d‟utiliser le script Ant fourni dans le SDKandroid-sdktoolsantbuild.xmlEt de le modifier de la sorte:<dex-helper-mod input-dir="${basedir}/libsToSpecialDEX/1"output-dex-file="${out.absolute.dir}/onary_dex_dir/classes.dex"/><jar destfile="${asset.absolute.dir}/onary_dex.jar" basedir="${out.absolute.dir}/onary_dex_dir" includes="classes.dex" /> 14
  15. 15. Afficher un document Office « xml » - 5 Si tout s‟est bien passé…On peut maintenant charger les classes en mémoire à l‟exécutionprivate Class loadClass(String className) { new File("/sdcard/office/opti").mkdirs(); final File optimizedDexOutputPath = new File("/sdcard/office/opti"); DexClassLoader cl = new DexClassLoader("/sdcard/office/one.jar:/sdcard/office/two.jar", optimizedDexOutputPath.getAbsolutePath(), null, TestOfficeAndroidActivity.this.getClassLoader()); Class libProviderClazz = null; try { libProviderClazz = cl.loadClass(className); } catch(Exception e) {e.printStackTrace();} return libProviderClazz;} 15
  16. 16. Afficher un document Office « xml » - 6 Une fois la classe chargée en mémoire…Class cl = loadClass( "org.apache.poi.ss.examples.html.ToHtml");Class[] paramTypes = new Class[] { String[].class };Method main = cl.getMethod("main", paramTypes);main.invoke(o, (Object) new String[] {"/sdcard/office/SampleSS.xlsx", "/sdcard/office/SampleSS.html"});Et c‟est seulement à partir d‟ici que ça devient vraiment intéressant!W/System.err(370): Caused by: java.lang.RuntimeException: Installation Problem??? Couldn‟t load messages: Can‟t find resource for bundle „org.apache.xmlbeans.impl.regex.message_en_US‟, key » 16
  17. 17. Afficher un document Office « xml » - 7 Que peut bien vouloir dire cette erreur? Le fichier message.properties est introuvable ! Il n‟est plus présent dans mon fichier dex! Mais présent dans XmlBeans-1.0.jarLa compilation en fichier APK, c‟est un zip avec  un fichier .dex pour les .class (et uniquement les .class!)  tout le reste (images, xml de layout, fichiers raw) dans des dossiers /res/drawable, /res/layout, /raw…Le fichier .properties n‟est donc pas resté dans le .dex! 17
  18. 18. Afficher un document Office « xml » - 8 On peut tricher…  XmlBeans est OpenSource! public void setLocale(Locale locale) { try {//this.resources = ResourceBundle.getBundle("org.apache.xmlbeans.impl.regex.message", locale); this.resources = new ResourceBundle() { @Override protected Object handleGetObject(String key) { return res.get(key); } @Override public Enumeration<String> getKeys() { return Collections.enumeration(res.keySet()); } }; } catch (MissingResourceException mre) { throw new RuntimeException("Installation Problem??? Couldnt load messages: "+mre.getMessage()); }}static HashMap<String, String> res = new HashMap<String, String>();static{res.put("parser.parse.1", "Wrong character.");} 18
  19. 19. Afficher un document Office « xml » - 9 Cette fois-ci, ça va passer… Toujours pas! org.apache.xmlbeans.SchemaTypeLoaderException: XML-BEANS compiled schema: Could not locate compiled schema resource {…..}/index.xsb Les fichiers .xsb ne sont pas dans les .dex, mais cette fois, on sait pourquoi!package org.apache.xmlbeans.impl.schema;public class ClassLoaderResourceLoader{public InputStream getResourceAsStream(String name) { try { return new FileInputStream("/sdcard/office/xsb/"+name.substring(name.lastIndexOf("/")+1)); } catch (FileNotFoundException e) {e.printStackTrace(); } //_classLoader.getResourceAsStream(resourceName); return null;} 19
  20. 20. Afficher un document Office « xml » - 10 On tient le bout…Maintenant qu‟on accède à toutes les ressources du jar original…ClassNotFoundException: java.awt.Color  POI est censé tourner sous Java 1.5 DEMO  Android ne connait pas les packages java.awt (et quelques autres)Une ultime manipulation:  remplacer tous les java.awt par des and.awt dans les sources de POI http://code.google.com/p/awt-android-compat/Attention, le résultat n‟est pas parfait  pas de gestion des images (pour l‟instant) 20
  21. 21. Afficher un document Office « xml » - 11Une approche plus sexy:- Intégrer les ressources manquantes aux jars- Création d‟un jar simple- « Dexisation » du jar en un fichier classes.dex- Réimportation des ressources dans un nouveau jar créé à la main  NOK!Le dexloader n‟a pas l‟air de gérer les jars et les APK de la même façon- Packaging du classes.dex dans un APK « maison »  OK!- En réutilisant cette technique, on peut donc, en théorie, se passer des étapes précédentes DEMO 21
  22. 22. Afficher un document Office « xml » - 12 Conclusion de la méthode POI Le code complet est disponible ici: https://code.google.com/p/display-msoffice-docs-android-with-apache-poi/Avantages:• Permet une conversion très complète (celle que permet le client POI)• Est très rapide (adaptée aux processeurs « lents » des mobiles d‟aujourd‟hui)• Donne accès à tous les formats (doc/docx, ppt/pptx, xls/xlsx, et même Visio .vsd ou Outlook msg)• Est chargeable dynamiquement en mémoire• Laisse la porte ouverte à un futur « mode édition » 22
  23. 23. Afficher un document Office « xml » - 13Inconvénients:• Utilise énormément de place sur la SDcard (8Mo d‟APK + 15Mo de ressources)• Compliqué à mettre en œuvre• Pour la partie AWT, repose sur le package and.awt  Pas de gestion des java.awt.BufferedImage. Il faudrait les convertir en android.graphics.Bitmap! 23
  24. 24. Afficher un document Office « xml » - 14 L‟alternativeLa transformation XSL basée sur la solution de Julien Chable http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2006/11/21/openxmlandjava.aspx• Un procédé beaucoup plus simple, mais moins efficace.<!-- Body and paragraphs --><xsl:template match="w:body"> <html> <body> <xsl:for-each select="w:p"> <p> <xsl:apply-templates select="w:pPr" /> <xsl:apply-templates select="w:r" /> </p> </xsl:for-each> </body> </html></xsl:template> 24
  25. 25. Afficher un document Office « xml » - 15Avantages:• D‟une légèreté déconcertante: mon APK fait seulement 261k• D‟une simplicité déconcertante: un seul jar à ajouter au Build Path et c‟est fini.• Facilement améliorable: il « suffit » d‟ajouter les balises qu‟on veut gérerInconvénients:• Ne gère que les OfficeOpen XML (donc pas les formats « binaires »)• Il faut trouver (ou écrire soi même?) un XSL vraiment complet pour un résultat parfait.  Les images ne sont pas du tout gérées  Seuls quelques styles sont implémentés, pas de formule, tableaux, wordart… 25
  26. 26. Afficher un document Office « xml » - 16 Structure d‟un fichier docx 26
  27. 27. Afficher un document Office « xml » - 17Utilisation des rID pour retrouver le style ou le nom de fichier pour une image avec le fichier document.xml.relsw:drawing crée une balise <img>avec pour attribut id = rIDOn extrait toutes les images de/word/media vers la SDCard2ème parsing: scan de toutes les balises img et ajout de l‟attribut grâce à la correspondance rID 27
  28. 28. Afficher un document Office « xml » - 18 Malgré cette technique pour afficher les images, cette solution reste imparfaite• Les positions des éléments ne sont pas gérées• Les puces, formules, tableaux ne sont pas gérés• Un exemple existant de traitement XSL de document duquel on pourrait s‟inspirer:  DocBookMon code est disponible ici https://code.google.com/p/display-msoffice-docs-android-without-apache-poi/ DEMO 28
  29. 29. Afficher un PDF -1 Une bonne occasion de voir le NDK• Sous windows, installer Cygwin http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/ (étapes 2 et 3)• Télécharger le projet APV http://code.google.com/p/apv/• Lancer la commande /script/build-native.sh du projet APV• Si tout s‟est bien passé, on peut lancer le projet APV sous Eclipse! 29
  30. 30. Afficher un PDF -2 C‟est très bien mais c‟est pas ce qu‟on veut!On vient de faire l‟équivalent d‟installer l‟appli « Acrobat Reader » Fichier librairie qui permet de parser les PDFs 30
  31. 31. Afficher un PDF -2 Customiser un peu…Extraction de la View PagesView• Par défaut, apv offre une view qui fait de nombreux appels à une activité.Un composant personnalisé<com.oxiane.DisplayPDF android:id="@+id/my_pdf_view" android:layout_width="fill_parent" android:layout_height="fill_parent" app:src="http://monpdf.com" /> 31
  32. 32. Afficher un PDF -3 Inconvénients de la méthode• Pas de gestion des liens HTTP• Encore 1,7Mo à rajouter à l‟APK!• Chargement se fait en rectangles Avantages de la méthode • Ça a le mérite de marcher! 32
  33. 33. Conclusion• Une aventure pionnière!• Un aperçu des possibilités qu‟offre l‟open source Java dans Android• Des ouvertures pour arriver à des résultats plus professionnels 33

×