Android implementation for PDF printing in NativeScript

Viewed 359

In my NativeScript-Vue app i need to print a PDF document to a bluetooth printer and receive a callback whether the print was successful or cancelled. The plugin nativescript-printer handles it flawlessly on iOS, but on Android it doesn't return a callback (the feature is not implemented). The plugin uses the class PrintHelper, which has a callback that gets called both on success and cancellation, without parameters and return.

It seems that the only solutions is to implement printing through the class PrintManager. Some sources:

So this is what I tried. onWrite and onLayout work, but onStart and onFinish (which is my goal) are never called.

import * as application from "tns-core-modules/application";

function printPdf(pdfFilePath) { // path: "/data/user/0/com.myapp.test/cache/pdf/document1.pdf"
    let printManager = application.android.foregroundActivity.getSystemService(android.content.Context.PRINT_SERVICE);
    let jobName = "PrintPdf";
    let PrintPDFAdapter = android.print.PrintDocumentAdapter.extend({
        onStart() {
            console.log("on start);
        },

        onWrite(pages, destination, cancellationSignal, callback) {
            let input;
            let output;
            try {
                input = new java.io.FileInputStream(new java.io.File(pdfFilePath));
                output = new java.io.FileOutputStream(destination.getFileDescriptor());

                let buf = new Array.create("byte", 1024);
                let bytesRead;
                while ((bytesRead = input.read(buf)) > 0) {
                    output.write(buf, 0, bytesRead);
                }

                callback.onWriteFinished(new android.print.PageRange(0, 0));
            } catch (e){
                console.error(e);
            } finally {
                try {
                    input.close();
                    output.close();
                } catch (e) {
                    console.error(e);
                }
            }
        },

        onLayout(oldAttributes, newAttributes, cancellationSignal, callback, extras){
            try {
                if (cancellationSignal.isCanceled()) {
                    callback.onLayoutCancelled();
                    return;
                }

                let pdi = new android.print.PrintDocumentInfo.Builder("print_output.pdf").setContentType(android.print.PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();

                callback.onLayoutFinished(pdi, true);
            } catch (e) {
                console.error(e);
            }
        },

        onFinish() {
            console.log("on finish");
        }
    });

    let pda = new PrintPDFAdapter();

    printManager.print(jobName, pda, null);
}
1 Answers

printManager.print() returns a PrintJob object, which has the current print state exposed. It's not nice, but this is my workaround:

function printPDF(pdfFilePath) {

    // above code

    let printJob = printManager.print(jobName, pda, null);

    let onFinish = function(status) {
        resolve(status);
        clearInterval(interval);
    }
    let interval = setInterval(() => {
        let state = printJob.getInfo().getState();
        console.log(state);
        if (state === 6) onFinish("print failed");
        if (state === 7) onFinish("print cancelled");
        if (state === 5) onFinish("print completed");
    }, 500);
}

I might implement a timeout on the interval in the case the PrintJob state gets stuck on queued or blocked.

Related