Android Example Creating MS Word Docx in Android

This is an incomplete example - only trying to for now create a basic MS Word *.docx in android. Note the following:

1. You need to download "poishadow-all.jar from here 2. It uses @agraham WriteExternalStorage to add the *.docx file to File.DirRootExternal (i am not publishing this on playstore so more than happy to use his class and not broken code as what some would like to comment. There is method in the madness for my usage. It works on android 16).
3. Creating the file (*.docx) with inline java code - will at some time or another convert it to making use of JavaObject
4. The Manifest is for now set to targetSdkVersion=30. When set to 34 it generate an error during compiling and if someone can shed some light on how to solve it, it will be much appreciated. But setting it to 30 works perfectly.

Run the code and then find "johan1.docx" in the the root folder of your device (File.DirRootExternal)
Open it with MS word.

Example project and johan1.docx (zipped) attached

Sample code:
#Region  Project Attributes
    #ApplicationLabel: AndriodWordDocument
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
    #BridgeLogger: true
#End Region

'#AdditionalJar: poi-ooxml-5.0.0.jar
'#AdditionalJar: poi-5.0.0.jar
'#AdditionalJar: commons-collections4-4.4.jar
'#AdditionalJar: xmlbeans-4.0.0.jar
#AdditionalJar: poishadow-all
#MultiDex : True

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Bmp As Bitmap
    Dim device As Phone
    Dim MES As ManageExternalStorage
    Dim nativeMe As JavaObject
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
   
    nativeMe.InitializeContext
   
    If FirstTime Then
        Bmp.Initialize(File.DirAssets, "android48.png")
        MES.Initialize(Me, "MES")  
    End If
   
    ' get the device SDK version
    Dim SdkVersion As Int = device.SdkVersion
   
    ' Choose which permission to request in order to access external storgage
    If SdkVersion < 30 Then
        Log("SDK = " & SdkVersion & " : Requesting WRITE_EXTERNAL_STORAGE permission")
        Dim rp As RuntimePermissions
        rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE) ' Implicit read capability if granted
        Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
        Log($"PERMISSION_WRITE_EXTERNAL_STORAGE = ${Result}"$)
    Else
        Log("SDK = " & SdkVersion & " : Requesting MANAGE_EXTERNAL_STORAGE permission")
        Log("On Entry MANAGE_EXTERNAL_STORAGE = " & MES.HasPermission)
        If Not(MES.HasPermission) Then
            MsgboxAsync("This app requires access to all files, please enable the option", "Manage All Files")
            Wait For Msgbox_Result(Res As Int)
            Log("Getting permission")
            MES.GetPermission
            Wait For MES_StorageAvailable
            Log("RES = " & Res)
        End If
    End If
   
    nativeMe.RunMethod("createDoc1", Array("johan1.docx"))
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
' As analternative to getting permission in Activity_Create you can do it when needed like ExternalStorage
'    If device.SdkVersion >= 30 Then
'        MES.GetPermission
'        Wait For MES_StorageAvailable
'    End If
    Dim fd As FileDialog
    fd.FileFilter = ""
    fd.TextColor = Colors.black
    'fd.FileFilter = ".txt" ' for example or ".jpg,.png" for multiple file types
    fd.FastScroll = True
    fd.FilePath = File.DirRootExternal ' also sets ChosenName to an emtpy string
    Dim fda As Object = fd.ShowAsync("B4A File Dialog", "OK", "Cancel", "", Bmp, False)
    Wait For (fda) Dialog_Result(ret As Int)
    ToastMessageShow(ret & " : Path : " & fd.FilePath & CRLF & "File : " & fd.ChosenName, False)
End Sub


#if Java

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import java.io.File;
import java.io.FileOutputStream;
import android.os.Environment;

import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.io.FileOutputStream;
import java.io.File;
import org.apache.poi.xwpf.model.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;


import java.io.FileOutputStream;
import java.math.BigInteger;


static {
    System.setProperty("org.apache.poi.javax.xml.stream.XMLInputFactory", "com.fasterxml.aalto.stax.InputFactoryImpl");
    System.setProperty("org.apache.poi.javax.xml.stream.XMLOutputFactory", "com.fasterxml.aalto.stax.OutputFactoryImpl");
    System.setProperty("org.apache.poi.javax.xml.stream.XMLEventFactory", "com.fasterxml.aalto.stax.EventFactoryImpl");
}



    public static void createDoc1(String filename) throws Exception {
   
    try {  
       XWPFDocument document = new XWPFDocument();

        // Create header
        XWPFHeaderFooterPolicy policy = document.createHeaderFooterPolicy();
        XWPFHeader header = policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);

        // Create table with 6 rows and 10 columns
        XWPFTable table = header.createTable(6, 10);

        // Set table width to 100% of page
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
        tblWidth.setType(STTblWidth.PCT);
        tblWidth.setW(BigInteger.valueOf(5000)); // 5000 = 100% in WordprocessingML

        // Merge cells (0,0) to (5,7)
        for (int row = 0; row <= 5; row++) {
            for (int col = 0; col <= 9; col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                CTTcPr tcPr = cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();

                // Horizontal merge: only on first row
                //if (row == 0) {
                    CTHMerge hMerge = tcPr.isSetHMerge() ? tcPr.getHMerge() : tcPr.addNewHMerge();
                    if (col == 0) {
                        hMerge.setVal(STMerge.RESTART);
                    } else {
                        hMerge.setVal(STMerge.CONTINUE);
                    }
                //}

                // Vertical merge: only on first column
                //if (col == 0) {
                //    CTVMerge vMerge = tcPr.isSetVMerge() ? tcPr.getVMerge() : tcPr.addNewVMerge();
                //    if (row == 0) {
                //        vMerge.setVal(STMerge.RESTART);
                //    } else {
                //        vMerge.setVal(STMerge.CONTINUE);
                //    }
                //}
            }
        }


        // Style the merged cell (row 0, col 0)
        XWPFTableCell mergedCell = table.getRow(0).getCell(0);
        mergedCell.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para = mergedCell.getParagraphs().get(0);
        para.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run = para.createRun();
        run.setText("Barrier Film Converters (Pty) Ltd");
        run.setBold(true);          // bold text
        run.setColor("000000");     // Red text
       
       
       
        // Style the merged cell (row 1, col 0)
        XWPFTableCell mergedCell1 = table.getRow(1).getCell(0);
        mergedCell1.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para1 = mergedCell1.getParagraphs().get(0);
        para1.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para1.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run1 = para1.createRun();
        run1.setText("Quality and Food Safety Management System");
        run1.setBold(true);          // bold text
        run1.setColor("000000");     // Red text      
       
   

        // Style the merged cell (row 2, col 0)
        XWPFTableCell mergedCell2 = table.getRow(2).getCell(0);
        mergedCell2.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para2 = mergedCell2.getParagraphs().get(0);
        para2.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para2.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run2 = para2.createRun();
        run2.setText("(FSSC 22000 V6)");
        run2.setBold(true);          // bold text
        run2.setColor("000000");     // Red text      
       





        // Style the merged cell (row 3, col 0)
        XWPFTableCell mergedCell3 = table.getRow(3).getCell(0);
        mergedCell3.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para3 = mergedCell3.getParagraphs().get(0);
        para3.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para3.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run3 = para3.createRun();
        run3.setText("Audit Start Date: 2026/03/22");
        run3.setBold(true);          // bold text
        run3.setColor("000000");     // Red text              
       
       
       
       
        // Style the merged cell (row 4, col 0)
        XWPFTableCell mergedCell4 = table.getRow(4).getCell(0);
        mergedCell4.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para4 = mergedCell4.getParagraphs().get(0);
        para4.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para4.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run4 = para4.createRun();
        run4.setText("Audit Start Time: 10:28:34");
        run4.setBold(true);          // bold text
        run4.setColor("000000");     // Red text                  
       
               

        // Style the merged cell (row 5, col 0)
        XWPFTableCell mergedCell5 = table.getRow(5).getCell(0);
        mergedCell5.setColor("5dc9a5"); // Green background

        // Create a paragraph inside the cell
        XWPFParagraph para5 = mergedCell5.getParagraphs().get(0);
        para5.setAlignment(ParagraphAlignment.CENTER); // center horizontally
        para5.setVerticalAlignment(TextAlignment.CENTER); // center vertically

        // Create a run for the text
        XWPFRun run5 = para5.createRun();
        run5.setText("App by Johan Schoeman");
        run5.setBold(true);          // bold text
        run5.setColor("000000");     // Red text          


       
       
        // Save document
        File file = new File(Environment.getExternalStorageDirectory(), filename);
        FileOutputStream out = new FileOutputStream(file);
        document.write(out);
        out.close();
        document.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}
#End If


Any additions will be welcome and appreciated.


This is a pic of the table it creates in the Header of the MS Word document

1774185506614.png
 

Attachments

  • AndroidWordDocument.zip
    15.1 KB · Views: 39
  • johan1.zip
    2.4 KB · Views: 39

PaulMeuris

Well-Known Member
Licensed User
B4J/B4A using Word
When i was exploring the Apache POI library (Apache POI API docs) for use in my Report writer B4J tutorial, i created a small test project. It worked fine but the XLUtils library also contains the functionality to work with Word documents (xlutils-creating-ms-word-documents). So i used that library instead.
With the poishadow-all.jar library for B4A it’s also possible to create Word documents as Johan has demonstrated. In this example i used my test code again. (you can find it in the attachment).
I added some code to save the document in the files folder of the app (b4a.B4Ausingword). The project name remained B4J_using_word but you can open it in the B4A IDE (the zip file contains a B4A folder with the B4A project files).
The document will also be saved in the Download folder using the MediaStore.
Once the document is saved you can tap on the Show button to open the ContentChooser. Go to the Download folder and choose the „testdocument_timeticks.docx“ file. An intent will be started to open the file with the „softmaker.applications.office.textmaker“ app. You can change that to use your specific Word document reader app.
When you start the app the first time the files folder gets created and the app will crash because the image file is not yet in that folder. Copy the image file from the files folder of the project to that files folder of the app on the device. Use an USB cable and Windows explorer to do that (set Transferring files on the device USB settings).
Start the app again and now the image should be in the document.
The source code contains B4J blocks. You can use the B4Jversion zip file to test. Change the path to the image file.
If you have the Textmaker Windows application on your PC then the exact same document can be shown.
B4A_example.PNG
B4J_example.PNG
 

Attachments

  • B4J_using_Word_B4Aversion.zip
    181.7 KB · Views: 5
  • B4J_using_Word_B4Jversion.zip
    6.5 KB · Views: 2

Johan Schoeman

Expert
Licensed User
Longtime User
B4J/B4A using Word
When i was exploring the Apache POI library (Apache POI API docs) for use in my Report writer B4J tutorial, i created a small test project. It worked fine but the XLUtils library also contains the functionality to work with Word documents (xlutils-creating-ms-word-documents). So i used that library instead.
With the poishadow-all.jar library for B4A it’s also possible to create Word documents as Johan has demonstrated. In this example i used my test code again. (you can find it in the attachment).
I added some code to save the document in the files folder of the app (b4a.B4Ausingword). The project name remained B4J_using_word but you can open it in the B4A IDE (the zip file contains a B4A folder with the B4A project files).
The document will also be saved in the Download folder using the MediaStore.
Once the document is saved you can tap on the Show button to open the ContentChooser. Go to the Download folder and choose the „testdocument_timeticks.docx“ file. An intent will be started to open the file with the „softmaker.applications.office.textmaker“ app. You can change that to use your specific Word document reader app.
When you start the app the first time the files folder gets created and the app will crash because the image file is not yet in that folder. Copy the image file from the files folder of the project to that files folder of the app on the device. Use an USB cable and Windows explorer to do that (set Transferring files on the device USB settings).
Start the app again and now the image should be in the document.
The source code contains B4J blocks. You can use the B4Jversion zip file to test. Change the path to the image file.
If you have the Textmaker Windows application on your PC then the exact same document can be shown.
View attachment 170905 View attachment 170906
I am too far "pregnant" with my project using poishadow-all.jar to now "abort" the work done thus far and start from fresh with your approach. I will look into your solution sometime soon. I did ask the question in the forum and response was that XLUTILS for creating MS Word docs were only applicable to B4J. Seems to not be the case from your posting and that it can indeed be used in B4A :mad:
 

Johan Schoeman

Expert
Licensed User
Longtime User
Adding some Java functions calling the POI methods should do the trick...
I will get back to you later...
My code is mostly inline Java to do headers/footers/body. Passing applicable values from b4a code via JavaObject. My project is working and need to integrate it into about 65 apps.

The only disadvantage - the APK footprint for each app is like 16MB when using the poishadow-all.jar.
 

PaulMeuris

Well-Known Member
Licensed User
In the attachments you can find the versions with a header and a footer.
The header contains a text and a table, the footer contains a table.
In the B4A version only 1 jar file is used (the rest is commented out)
B4X:
'    #AdditionalJar: commons-codec-1.15
'    #AdditionalJar: commons-collections4-4.4
'    #AdditionalJar: commons-compress-1.20
'    #AdditionalJar: commons-math3-3.6.1
'    #AdditionalJar: poi-5.0.0
'    #AdditionalJar: poi-ooxml-5.0.0
'    #AdditionalJar: poi-ooxml-full-5.0.0
'    #AdditionalJar: poi-ooxml-lite-5.0.0
'    #AdditionalJar: SparseBitSet-1.2
'    #AdditionalJar: xmlbeans-4.0.0
    #AdditionalJar: poishadow-all.jar
In the B4J version some jar files are still used:
B4X:
'    #AdditionalJar: commons-codec-1.15
'    #AdditionalJar: commons-collections4-4.4
'    #AdditionalJar: commons-compress-1.20
'    #AdditionalJar: commons-math3-3.6.1
    #AdditionalJar: poi-5.0.0
    #AdditionalJar: poi-ooxml-5.0.0
    #AdditionalJar: poi-ooxml-full-5.0.0
    #AdditionalJar: poi-ooxml-lite-5.0.0
    #AdditionalJar: SparseBitSet-1.2
    #AdditionalJar: xmlbeans-4.0.0
    #AdditionalJar: poishadow-all.jar
1774852484429.png

1774852516643.png

The code in the B4J version did not need any changes.
 

Attachments

  • B4J_using_Word_B4Aversion_header_footer.zip
    182.1 KB · Views: 3
  • B4J_using_Word_B4Jversion_header_footer.zip
    7 KB · Views: 2
Top