Printing With Enterprise Browser

Enterprise Browser 3.0

Overview

Enterprise Browser permits printing via Bluetooth, USB and Wi-Fi from mobile devices running Android and Windows Mobile/CE. Printing via USB requires EB 1.3 or higher. This guide describes the steps necessary to enable printing in an Enterprise Browser application. Where appropriate, it contains links to details for the function calls, methods, parameters, constants and other specifics necessary to build an application using JavaScript and the Zebra printing APIs. See the Printing on Windows Mobile/CE section (below) for important notes, and the Printing Tutorial for a walk-though of EB printing setup.

All code samples are JavaScript.

Printing on Windows Mobile/CE

Windows Mobile and Windows CE require that the PrintingService application is installed and always running whenever the Printing and PrintingZebra APIs are to be used. This service (PrintingService.cab) is included with the Enterprise Browser installation, but requires the following Microsoft software to be on the device before the service can be deployed:

PrintingService App Installation

  1. For Windows Mobile/CE devices, the .NET Compact Framework must be present before installing the PrintingService app. Before downloading .NET CF, it might already be present on the build machine in C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\NETCFv35.wm.armv4i.cab.
  2. Windows CE devices also require the messaging framework, which can be found on the build machine in C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics\NETCFv35.Messages.EN.cab.
  3. The PrintingService installer (.cab) file can now be installed. It's found in C:\<path to Enterprise Browser>\Printing-Service\PrintingService.cab.

Limitations

About USB Printing

The ability to print via USB was introduced in Enterprise Browser 1.3, and uses the CONNECTION_TYPE_USB parameter available in that and higher versions only. USB printing requires a USB "On-The-Go" (OTG) cable or adapter and one of Zebra's printers with USB printing support or a compatible third-party printer.

Android and Windows Mobile/CE printing is supported via direct USB OTG connection or through a cradle with OTG adapter. Windows Mobile/CE devices also must be in "Host Mode," which is enabled under USB Config in the Settings panel. Connecting an OTG cable to an Android device invokes host mode automatically.

USB Compatibility Notes

  • A USB On-the-Go (OTG) cable or adapter permits a mobile device to act as "host" to client peripherals such as flash drives, keyboards and printers.
  • On Android devices, connecting an OTG cable invokes host mode automatically.
  • On Windows Mobile/CE devices "Host Mode" must be invoked manually (under USB Config in the Settings panel).
  • Some Zebra TC7X single/dual slot cradles present a USB micro "AB" receptacle that allows the TC7X to act as host or client, depending on the cable.
  • The Zebra OTG implementation lacks Session Request Protocol (SRP) and Host Negotiation Protocol (HNP), portions of the spec that allow connected devices to control power consumption and switch dynamically between host and client modes.
  • Printing via USB from a cradled device is possible by inserting an OTG Micro Type A connector to the cradle and connecting the USB-B (or Mini-B) end to the printer.
  • OTG supports direct USB connections only; the use of USB hubs is not supported by the OTG spec.

1- Enable Print APIs

Enterprise Browser provides two APIs for printing. The Printer API is a parent class that defines common class attributes that specific printer-type APIs will inherit. The PrinterZebra API is the printer-type API for Zebra printers.

There are two methods of enabling the Printer API:

  • Include all "ebapi" modules
  • Include only the required API modules

Both methods are explained below.

Either way, the included files can be found in: /Enterprise Browser/JavaScript Files/Enterprise Browser, a directory on the computer that contains the Enterprise Browser installation.

Include all JS API modules

To include all JavaScript APIs, copy the ebapi-modules.js file to a location accessible by an app's files and include the JavaScript modules file in the app. For example, to include the modules file in index.html, copy the file to the same directory as index.html and add the following line to the HEAD section of that index.html file:


<script type="text/javascript" charset="utf-8" src="ebapi-modules.js"></script>

This will define the EB class within the page. Note that the path for this file is relative to the current page (index.html). Any page from which the API modules are accessed must include a reference to the .js file(s) in this way.

Include only the required modules

To include individual APIs, first include the ebapi.js in the HTML, and then the additional required API file(s). For example, to use the Printer API, add the code below to the HTML file(s). Again, this assumes that the relevant API files have been copied to the same directory as the HTML.


<script type="text/javascript" charset="utf-8" src="ebapi.js"></script>
<script type="text/javascript" charset="utf-8" src="eb.printer.js"></script>

In the code lines above, notice that ebapi.js is included first, followed by eb.printer.js, which is the Printer API for Enterprise Browser. This coding must be included on any HTML page that will call an individual API.

2- Find a Printer

Before an app can print, it must discover and connect to a printer. There are a few ways to discover printers, but all use the searchPrinters method.

Finding via Bluetooth

Printing via Bluetooth is supported for Android and Windows Mobile/CE apps. During Bluetooth discovery, the printer must be in "discoverable" mode.

Look for any "discoverable" Zebra printer via Bluetooth by specifying the connectionType and printerType in the options parameter:


var printers = [];

EB.Printer.searchPrinters({ 
    connectionType:EB.Printer.CONNECTION_TYPE_BLUETOOTH,  
    printerType: EB.Printer.PRINTER_TYPE_ZEBRA
     }, function (cb){
        if(cb.status == 'PRINTER_STATUS_SUCCESS')
        {
            if (typeof cb.printerID != "undefined")
            {
                console.log('Found: ' + cb.printerID)
                // > Found ZEBRA_PRINTER_1

                printers.push(cb.printerID);
            }
            else
            {
                console.log('Done Searching');
            }
        }
        else
        {
            console.log(cb.status);
        }
    });

TIP: To minimize search time, code should provide as many search parameters as possible.

The Bluetooth MAC address consists of six pairs of hexadecimal digits separated by colons.

Specify the Bluetooth MAC address (if known) as a deviceAddress using the options parameter:


EB.PrinterZebra.searchPrinters({ 
    connectionType:EB.Printer.CONNECTION_TYPE_BLUETOOTH,  
    deviceAddress: '00:03:7A:4C:F2:DB'
    ... 

NOTE: When pairing with a Bluetooth device for the first time, a prompt might appear for a pairing PIN. Commonly used PINs: 0000, 1111 and 1234. Check the printer manufacturer's specifications.

Finding via Wi-Fi

Quickly identify known Wi-Fi printers, search using the deviceAddress and devicePort parameters:


EB.Printer.searchPrinters({ 
    connectionType:EB.Printer.CONNECTION_TYPE_TCP,  
    deviceAddress: '192.168.1.121',
    devicePort: 6101
    ...

NOTE: When attepting to connect via Bluetooth or Wi-Fi, be sure the device's corresponding radio is turned on. If using Bluetooth, the printer should be in "discoverable" mode.

Finding via USB

Printing via USB is supported from Zebra enterprise mobile computers only to Zebra's supported printers, which must be connected using an OTG cable or adapter. Windows Mobile/CE devices also must be in "Host Mode," which is found under USB Config in the Settings panel.

Use the search.Printers method and the CONNECTION_TYPE_USB parameter to search for printer(s) connected to the mobile device's USB port:


var printers = [];

EB.Printer.searchPrinters({ 
    connectionType:EB.Printer.CONNECTION_TYPE_USB,  
    printerType: EB.Printer.PRINTER_TYPE_ZEBRA
     }, function (cb){
        if(cb.status == 'PRINTER_STATUS_SUCCESS')
        {
            if (typeof cb.printerID != "undefined")
            {
                console.log('Found: ' + cb.printerID)
                // > Found ZEBRA_PRINTER_1

                printers.push(cb.printerID);
            }
            else
            {
                console.log('Done Searching');
            }
        }
        else
        {
            console.log(cb.status);
        }
    });

For more information about USB connections, please refer to the Platform Notes section later in this guide.

3- Connect to a Printer

The script in STEP 2 executes the callback function of the searchPrinters method, which returns a unique printerID property for each printer found and places them in the printers array variable. These IDs will be used to establish a connection with the desired printer. After the last printer is found, an additional callback will be triggered that contains no printerID, signaling that the app has found all available printers and can begin the selection process.

NOTE: This printerID is a unique identifier that is tracked by the Enterprise Browser framework. It has no relation to ID numbers that a printer manufacturer might be using.

Select a printerID value from the printers array variable by creating an instance of the Printer class. Then call the getPrinterByID method and pass the printerID as a string to the vairable myPrinter:


// Ex: printers[0] = 'ZEBRA_PRINTER_1'

var myPrinter = EB.Printer.getPrinterByID(printers[0]);

// myPrinter is now an instance class of Printer
// and can use the Instance Methods and properties 
// associated with that class

Next, connect to the instantiated printer using the connect method:


myPrinter.connect(function (cb){

    console.log(cb);
    // > PRINTER_STATUS_SUCCESS
    //cb = PRINTER_STATUS... constant

    console.log(myPrinter.deviceName);
    // > 'XXXX09-10-5799'
    // deviceName will be Zebra's 'Friendly Name'

    console.log(myPrinter.deviceAddress);
    // > '00:03:7A:4C:F2:DB'
    // deviceAddress will equal the Bluetooth Address

});

The callback object in the connect method will be a string containing a PRINTER_STATUS... constant such as:

  • PRINTER_STATUS_SUCCESS
  • PRINTER_STATUS_ERR_NETWORK
  • PRINTER_STATUS_ERR_TIMEOUT

4- Retrieve Printer State

The first parameter of the requestState method is an array that lists the items available to find.

Use the requestState method to check the printer state:


// Assumes an instance of "myPrinter" has been
// created using methods described above

myPrinter.requestState(['PRINTER_STATE_IS_READY_TO_PRINT',
'PRINTER_STATE_IS_PAPER_OUT'],function (cb){
    console.log(cb.status);
    console.log(cb.PRINTER_STATE_IS_PAPER_OUT);
    console.log(cb.PRINTER_STATE_IS_READY_TO_PRINT);

    });

The returned PRINTER_STATE... callback objects are constants such as:

  • PRINTER_STATE_IS_COVER_OPENED
  • PRINTER_STATE_IS_DRAWER_OPENED
  • PRINTER_STATE_IS_PAPER_OUT

5- Retrieve Supported Printer Languages

The printer languages supported by the printer must be known before sending commands. Languages supported by Zebra printers include ZPL, CPCL and EPS.

To retrieve a list of supported languages, use the enumerateSupportedControlLanguages method:

    
//assumes a printer instance from previous instructions:

myPrinter.enumerateSupportedControlLanguages(function(cb){

    // cb = Array of strings 
    // PRINTER_LANGUAGE_ZPL
    // PRINTER_LANGUAGE_CPCL
    // PRINTER_LANGUAGE_EPS
});

The callback will be an array of PRINTER_LANGUAGE... constants such as:

  • PRINTER_LANGUAGE_ZPL
  • PRINTER_LANGUAGE_CPCL
  • PRINTER_LANGUAGE_EPS

6- Send Printer Commands

Once the app finds and connects to a printer, it can begin sending commands. Printer behavior will vary depending on printer make, model and current state. Consult the printer's technical documentation for printer-specific commands and syntax.

In general, there are two fundamental ways to send commands:

  • In a string that includes raw printer commands
  • In a series of commands stored in a file (i.e. ZPL, CPCL)

Sending a Raw String

To send a string to the printer, use the printRawString method:


// If printer is in line mode, this text would be printed:

myPrinter.printRawString('This is a test print');

// To sendi a Zebra CPCL command 
// and change from line mode to ZPL mode:

myPrinter.printRawString('! U1 setvar "device.languages" "ZPL"\r\n');

Sending a Series of Commands

When a series of commands is used repeatedly by an app--for example, to print an address label--the commands can be stored in a file (i.e. ZPL, CPCL) and called and/or modified programatically to perform the task. Command files can be generated manually or made using a tool provided by Zebra. They can be created in advance and delivered with the application.

For example, if a file called address.cpcl is stored in the application's public folder and contains some CPCL commands that are used to print an address, such a file might look like the one below, which is a sample terminal script file with embedded CPCL commands:


! U1 SETLP 5 2 46
AURORA'S FABRIC SHOP
! U1 SETLP 7 0 24
123 Castle Drive, Kingston, RI 02881
(401) 555-4CUT

To access the address.cpcl file, use the RhoFile.join helper function and the Application.publicFolder property to create a fully qualified path to the file.

Pass the fully qualified path created above to the sendFileContents method:


var addressFile = EB.RhoFile.join(EB.Application.publicFolder, 'address.cpcl');

//assuming an instance was created and connected 
//per the previous instructions

myPrinter.sendFileContents(addressFile,function(e){
    console.log(e);

    // Will return a PRINTER_STATUS... CONSTANT String

    });

7- Disconnect

Whenever an app is finished printing, it's important to disconnect from the printer. This is especially important for Bluetooth connections.

To disconnect, use the disconnect method:


//assumes an instance object was created from previous instructions

myPrinter.disconnect();

Using Files Stored On The Printer

Some printers have the ability to store command-file templates or other files useful for performaing print operations.

Retrieve a list of files that exist on the printer using the retrieveFileNames method:


myPrinter.retrieveFileNames(function (e){

    // e.status : PRINTER_STATUS_SUCCESS, PRINTER_STATUS_ERROR
    // e.fileNames : ARRAY of file names

});

Once the file names are known, the app can print with them, passing variables as specified within the ZPL or CPCL files themselves. This is done using either the printStoredFormatWithArray method or the printStoredFormatWithHash method.

Both methods above include the three parameters below.

Parameter 1- formatPathOnPrinter

This will be 'E:<filename>' where 'filename' is the name of one of the files found using the steps above or another file on the device (assuming the file is stored in the printer's "E" partition).

Parameter 2- vars

This represents the data to be passed to the label, and uses printStoredFormatWithArray, an array of strings representing the data to fill into the format. For ZPL formats, index 0 of the array corresponds to field number 2 (^FN2). For CPCL, the variables are passed in the order that they are found in the format.

Pass some address data to the array:


myPrinter.printStoredFormatWithArray('E:LABEL.ZPL',['John Doe','123 East Main St','Smalltown, NY 11766'],function (e){

        // Will return a PRINTER_STATUS... CONSTANT String
    });

Supported by ZPL only is printStoredFormatWithHash, a hash that contains the key/value pairs for the stored format. For ZPL formats, the key number should correspond directly to the number of the field in the format. Number keys should be passed as strings (i.e.'1':'field1', '2':'field2', etc).

Pass some address data to the hash:


myPrinter.printStoredFormatWithHash('E:LABEL.ZPL',{ '1':'John Doe','2': '123 East Main St','3': Smalltown, NY 11766'},function (e){

    // e = PRINTER_STATUS... CONSTANT String

    if(e == 'PRINTER_STATUS_SUCCESS')
        {

        }
    });

Parameter 3- callback

This parameter will return a PRINTER_STATUS... constant as a string.

Printing Images

For printers with graphics support, images are printed using the printImageFromFile method. For example, an image called myImage.jpg in the application's public folder could use the same RhoFile.join helper function and Application.publicFolder property described above to create a fully qualified path to the myImage.jpg file.

After creating the fully qualified path, pass the file to the printImageFromFile method**:


var imagefile = EB.RhoFile.join(EB.Application.publicFolder, 'myImage.jpg');

//assuming an instance was created and connected 
//per the previous instructions

myPrinter.printImageFromFile(imagefile,0,0,{},function(e){

    // e = PRINTER_STATUS... CONSTANT String

    if(e == 'PRINTER_STATUS_SUCCESS')
        {

        }
    });

A callback for the PRINTER_STATUS constant would return a string indicating whether the operation was successful.

NOTE: Images larger than 1024x768 might take a long time or print incorrectly. Consult the printer manufacturer's documentation for image printing parameters.

Storing Images

For Zebra printers that support the storage of images, this can be done by creating a ZPL or CPL command set or by using the storeImage method.

To store an image on the printer using the storeImage method:


//location of image on device:

var imagefile = EB.RhoFile.join(EB.Application.publicFolder, 'myImage.jpg');

//destination of image on the printer. Must have partion specified:

var destination = "E:LOGO.GRF"

//assumin an instance was created and connected 
//per the previous instructions:

myPrinter.storeImageFromFile(destination,imagefile,0,0,{},function(e){

    // e = PRINTER_STATUS... CONSTANT String
    if(e == 'PRINTER_STATUS_SUCCESS')
        {

        }
    });