Giter VIP home page Giter VIP logo

Comments (32)

AlexChesser avatar AlexChesser commented on August 23, 2024 3

More great news! I just had the breakthrough that officially puts this on the home stretch.
Still handling the 'finesse' portion but I am now certain we got this.

It was a few good hours trying to figure out why it wasn't working when I decided I needed to inspect a few variables at a certain breakpoint... so I changed this:

        byte[] bytes = new byte[(int)file.length()];

into this:

        int len = (int)file.length();
        byte[] bytes = new byte[len];

and suddenly everything was working.

Home run fellas!

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024 1

Hey @jonneroelofs I'm almost there. Probably a couple more days work. If everything goes well, I can finish up "proof of concept" with temp files (thanks for the link Cesar) and get Base64 output by tomorrow EoD ... assuming other urgent work doesn't get in the way.

At the moment I'm successfully writing the file, but when I try to read it, it is coming back as Zero bytes. Though on-disk it clearly is NOT zero bytes.

From there I'd also need a couple days to finesse the solution. Specifically I'll need to wrap my version of the code in all the logical control structures which ensure the behaviour is consistent in iOS and android.

Essentially if the user doesn't specificy type=base64 in the JavaScript it doesn't do this. I also want to try working this as a memory-stream-only operation, but that isn't critical functionality for me. That one is just pride. I'm normally a C# developer so all this Java stuff feels a lot like trying to play a piano with oven mitts on: I know all the things that I want to do, I'm just having trouble hitting the right keys.

I imagine that by late next week I might have a pull request together.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024 1

Hi @AlexChesser that's great news , sorry for late response I'm traveling with limited connectivity, I will push the code as later this day.

from pdf-generator.

cabaird avatar cabaird commented on August 23, 2024

I also have a need for this issue to be fixed. I need to generate the PDF, and add it to an array of files that I am attaching to an email. I am currently able to do this in iOS, but not in android because the service is returning the string "Success" rather than the base64 value that is expected.

Thank you,

Christian

from pdf-generator.

MikeMadez avatar MikeMadez commented on August 23, 2024

Do you got any luck?

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Also throwing my +1 on this. Any idea about what might be required to patch this in?

Edit/Update - so my initial theory here is that the https://github.com/cesarvr/pdf-generator/blob/master/src/android/PDFPrinter.java is what is creating the PDF-print-view. (super early initial research, I'm not sure I 100% get it yet)
From that point of view, it looks like the web-page we're sending to the pdf-generator gets rendered in a temporary webview and then automatically sent to a print command with the 'print-to-pdf' option enabled.

https://developer.android.com/reference/android/print/PrintDocumentAdapter.html is the class we're extending.

The question I THINK then becomes - is there any option we have which will get the Base64 result of a printdopcumentadapter. I'm reading the docs now.

@cesarvr please feel free to kick in if you've already followed this line of thought and have found that it won't work or have any additional guidance or suggestions of where I might look. This is the first I'm seeing this code.

update2:
looking at https://developer.android.com/reference/android/graphics/pdf/PdfDocument.html right now. android.graphics.pdf looks like it has a writeStream method - which I assume means we could send that to something within android which converts a memory-stream to Base64. The question becomes - is there any way to convert a webview into a PDFDocument, or to GET the webview out of the createPrintDocumentAdapter call.

update3:

Current android workflow:

  1. PDFGenerator class (custom)
    • creates an android webview offscreen
    • renders (string || webpage) to offscreen webview
    • sends offscreen webview content to the PDFPrinterWebView (custom)
  2. PDFPrinterWebView (custom)
    • sends content to the PDFPrinter(custom)
  3. PDFPrinter (custom) extends PrintDocumentAdapter (native)
    • throws webview content into android native print-as-pdf functionality

The proposal:
find a way to get the BYTES from an android native PrintDocumentAdapter and
return them as BASE64 if b64 flag is set in initial call to PDFGenerator

Based on the documentation for
https://developer.android.com/reference/android/print/PrintDocumentAdapter.html

I suspect the lifecycle of this object goes
1. onStart
3. onLayout - (PrintAttributes oldAttributes,
PrintAttributes newAttributes,
CancellationSignal cancellationSignal,
PrintDocumentAdapter.LayoutResultCallback callback,
Bundle extras)
2. onWrite -
4. onfinished

It also seems that we might be able to access the PDF Bytes from within
https://developer.android.com/reference/android/print/PrintDocumentAdapter.LayoutResultCallback.html
during the onLayoutFinished method

Print document info is one of the params of this function.
https://developer.android.com/reference/android/print/PrintDocumentInfo.html

PrintDocumentInfo has a method writeToParcel which appears to function as a stream
https://developer.android.com/reference/android/os/Parcel.html

Parcel has a method readByteArray which will get the bytes of the PrintDocumentInfo
which we can convert into BASE64 using this one liner from stack overflow.
http://stackoverflow.com/questions/2418485/how-do-i-convert-a-byte-array-to-base64-in-java

There are a few unknowns in this ... like if the PrintDocumentInfo is actually just the raw PDF file
and if every step of this chain will work without trouble. I've not got a lot of experience with java/android
so I'd love a bit of advice if there is any to be had.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @AlexChesser, very happy that you want to contribute with this feature.

Here is some info you may find useful:

How it works

We have a Webview that basically renders the content HTML/CSS, this class expose the rendered content trough an adapter method called createDocumentAdapter this basically make the Webview content readable by the PrintManager class that take care of printing the content.

Approaches

  • I think you are in the right direction but I think PrintDocumentInfo is just a class that handle document metadata, I doubt it would be useful for what you try to achieve.

  • Another alternative could be to try read the contents PrintDocumentAdapter by calling (onStart, onWrite, ...etc) saving that and transforming it into a base64. The documentation of webview.create PrintDocumentAdapter make this look promising:

Creates a PrintDocumentAdapter that provides the content of this WebView for printing. The adapter works by converting the WebView contents to a PDF stream. The WebView cannot be drawn during the conversion process - any such draws are undefined. It is recommended to use a dedicated off screen WebView for the printing. If necessary, an application may temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance wrapped around the object returned and observing the onStart and onFinish methods. See PrintDocumentAdapter for more information.

You can use this project to test the cordova plugin.

Hope this helps, If you need more info let me know.

from pdf-generator.

gameboy9 avatar gameboy9 commented on August 23, 2024

I'm also interested in a fix for this issue. I found this, but I couldn't get it to work for the life of me: http://www.annalytics.co.uk/android/pdf/2017/04/06/Save-PDF-From-An-Android-WebView/

I don't think this converts it to a base64, but it does output a file. Do you think this helps at all?

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @gameboy9, if what the blog said is correct, I think you will be able to get a file descriptor back and you can later transform the content of the file to a base64, so i think it worth to give try. If you run the plugin using Android Studio debugging mode you can see how PrintManager interact with PrintAdapter by settings breakpoints in PDFPrint class that would give idea of what missing.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Hey Guys - I've put a day into this so far and am about to put this down for a bit.
I've gotten the blog post from Patrick (@gameboy9) implemented here: https://github.com/AlexChesser/pdf-generator/tree/android-base64

I've been running it in a debugger in VSCODE and there are some additional things I have to try.

  • get it to save the file correctly: suspect storage permissions required on the APP, I suspect this will actually work
  • rewrite the PRINT-TO-FILE handler to use a MEMORYFILE object
  • convert the bytes of a MEMORYFILE to BASE64
  • return the base-64 data to the APP
  • CLEAN UP the call so it correctly handles the "type" parameter (eg only returns BASE-64 when it is requested via the javascript call)

If the storage-access-permissions setting works for the file creation, I think we're really off to the races

This is absolutely work-in-progress and I am very inexperienced in the android-native space so there may be some ugly stuff going on in here. I do, however, think today's shown some good progress.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @AlexChesser , I will give it a look at your code changes as soon as I have some free time, but sound like a great news 👍 .

cheers.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

:) it is NOT for merging yet. A long way from it in fact. I might be able to pick up on round two tomorrow or next week.

UPDATE:

OK further progress made today. In the code I'm as far as successfully saving the PDF file to SDCARD.
At the moment I'm not able to successfully READ the bytes of the file on the SDCARD (elementary stuff I'm sure, but I'm not really a strong android/java developer)

There's a built in library for converting Bytes to Base64 in android.util.Base64 this should not be confused with java.util.Base64 as cordova devaults its compilation to Java version 1.6 (there were a LOT of hours burned there)

Anyways - if I can figure out how to read the bytes of the saved file then this would actually be working.

Do any android experts know if there is a way of saving files somewhere that does not require STORAGE permissions?

from pdf-generator.

jonneroelofs avatar jonneroelofs commented on August 23, 2024

Hi @AlexChesser , are you able to get the pdf returned as a base64 string on android in the success callback function? That is exactly what we need. With regard to the storage, I figured you could use the cordova file plugin to write the base64 string to a file. I think the file would then be saved in the App sandbox storage on the local file system.

Cheers,

Jonne

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @AlexChesser , here are some suggestions:

to save the file you save it you can use a temporary location:
temporary file in Android

If i'm not mistaken this actually don't require user permissions.

To read the files and save it into a byte array you can use this:
File to byte[]

Later you can transform this bytes to base64 to do this you can use this guide.

If you see the last two example I think you can maybe use ByteArrayOutputStream to get the data and transform it to base64 without allocating the byte array.

This should help you start.
Cheers.

from pdf-generator.

jonneroelofs avatar jonneroelofs commented on August 23, 2024

@AlexChesser Sounds great!

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Learning how to read the JSONArray args now. Will be back at it tomorrow.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

I've put together a commit which will achieve successful HTML to Base64 printing
#31

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @AlexChesser looks great, I just found a small detail the base64 feature is returning an empty string
I created this example project , to test the features of the plugin, you can use it to debug this issue, but looks very promising.

Thanks.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Interesting. I had it working in the sample project. I wonder if I had some lingering permissions installed on the device I was using.

Will dig into it tomorrow. Will test end to end from scratch and see.

I definitely had it working and returning the full string on Friday so I'm sure it's a small thing.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

EDIT: ok - I'm able to replicate your issue with a fresh build. Investigating.
Hmm... I can get it to work intermittently. This is really odd.

OKAY! more progress on tracking down the error. If I don't delete the file. the BASE64 shows up on the second run. So the problem is related to something to do with correctly accessing the file within the life-cycle.

So... I'm a bit fuddled for today. Will keep going tomorrow.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

I was trying the code in local, I wrote a some temporary file mechanism (no permission required) and I was able to create a file only problem is when I open the file was filled with zeros. In your sucessful attempt, did you test transforming the base64 back to binary ?

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

So far I've found that the file I am saving to disk in external storage IS correct. I'll spend a few hours today testing that the BASE64 I am getting matches this. I've been meaning to use the B64 as an email attachment so that's a step I need to take anyways.

Do you have that temporary file mechanism code in a branch somewhere that I could look at?

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

UPDATE - I can confirm that the Base64 I am getting out of my version IS the expected PDF (non zero byte filled)

I've pushed the changes to your testing app which has the "email testing" sample https://github.com/AlexChesser/pdf-generator-example/tree/android/base-64

Will continue to see if I can get the PDF to be generated correctly the first time. Would love to see the working tempfile code you've got.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Bit more progress on the file coming back as zeroes issue:
I started looking at some logging.

Turns out we have a race-condition going on.

    06-13 13:30:01.323 27034 27034 D PDFtoBase64: onLayoutFinished
    06-13 13:30:01.333 27034 27034 D PDFtoBase64: getAsBase64
    06-13 13:30:01.963 27034 27034 D PDFtoBase64: onWriteFinished

I have to figure out how to ensure the cordova success callback doesn't get executed before the file has finished writing.

UPDATE OK! looks like changing the order of operations has given me an edge here. I think I might have it. Will update the PR with the latest code later today.

UPDATE 2 OK - pull request is updated with code which correctly handles the race condition.
d4801e2

Stil love to see your code on the temp file though! I suspect yours is better since I'm really not an android developer by default.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi @AlexChesser , I just pushed the branch with the code doing the temporary folder is inside a class called Utilities , also I have moved some string literals to constants and add passing the CordovaCallback to the constructor of the class PDFtoBase64.

Also added logging methods in the try catch, so if is easy for us to track an app crash, etc.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

Thanks! I've incorporated your style tips into my working code and squelched them all into a single commmit: #31 same pull request.

I didn't use the utilities class - but did use that method of creating a temp file. I love the choice of putting the cordova callback into the constructor. In hindsight, I should have seen that myself, but I was mentally stuck with the pattern of returning a string from getAsBase64

I've tested locally on an android device and it seems to work for me. Think we're probably good to merge after your approval & testing cycle.

from pdf-generator.

cesarvr avatar cesarvr commented on August 23, 2024

Hi All, I have released a new version of the pdf-generator-plugin now supports Android base64 thanks to @AlexChesser , is a beta functionality by now, so I think we can close this issue.

from pdf-generator.

jonneroelofs avatar jonneroelofs commented on August 23, 2024

@AlexChesser do you have a working example somewhere I could give a try? I cannot get it to work in my project. If I set type to base64 nothing seems to happen. I am not receiving anything in either the success or failure callback.

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

@jonneroelofs yup, this is what I was testing with https://github.com/AlexChesser/pdf-generator-example/tree/android/base-64 (note that I had to install the spinner plugin manually).

from pdf-generator.

jonneroelofs avatar jonneroelofs commented on August 23, 2024

@AlexChesser
For some weird reason its working on every emulator and phone I have tested with except my own ... I have a Oneplus X . A colleague of mine has the same phone with an identical os and its even working on his phone. I was able to track down the problem to the onWriteFailed event. However the error the event provides is NULL, which is not very helpful. Do you have any idea what could be going on?

Ref: https://developer.android.com/reference/android/print/PrintDocumentAdapter.WriteResultCallback.html#onWriteFailed(java.lang.CharSequence)

image

from pdf-generator.

AlexChesser avatar AlexChesser commented on August 23, 2024

@jonneroelofs If we're talking about one specific device, the only thought I have is that one of the system modules is not up to date on that particular unit.

Is the android system version up to date? (6.0.1)?
What about the android system webview APP? (58.0.3029.83)?

I don't have access to any Oneplus devices to see for myself.

from pdf-generator.

jonneroelofs avatar jonneroelofs commented on August 23, 2024

@AlexChesser
Thanks! The android system webview App is the problem. After I deleted it, everything started to work on my phone as well.

Cheers,

Jonne

from pdf-generator.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.