Comments (32)
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.
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.
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.
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.
Do you got any luck?
from pdf-generator.
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:
- PDFGenerator class (custom)
- creates an android webview offscreen
- renders (string || webpage) to offscreen webview
- sends offscreen webview content to the PDFPrinterWebView (custom)
- PDFPrinterWebView (custom)
- sends content to the PDFPrinter(custom)
- 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.
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.
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.
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.
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.
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.
:) 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.
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.
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.
@AlexChesser Sounds great!
from pdf-generator.
Learning how to read the JSONArray args now. Will be back at it tomorrow.
from pdf-generator.
I've put together a commit which will achieve successful HTML to Base64 printing
#31
from pdf-generator.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
@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.
@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.
@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?
from pdf-generator.
@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.
@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)
- Application crashes on iOS when use fromData
- lock pdf from editing
- Blank PDF file is generated when called first time HOT 1
- Error on `cordova plugin add cordova-pdf-generator` HOT 1
- PDF Generator not working on android 10 !!! HOT 2
- How can we generate a pdf with password using this plugin ?
- Crash on Android 10
- Css and html tags are not implemented on pdf generated in vue ionic HOT 2
- PDF font changes with Mobile font size
- How to show paginations on the PDF generated? HOT 1
- convert to pdf/a
- Unable to add local images after upgrading to Android API 30 HOT 1
- Webpage not available net:ERR_CONNECTION_REFUSED
- Loading an internal CSS not working for iOS Capacitor
- Table Border not visible HOT 1
- PDF preview doesn't appear in Android, it is continue spinning
- How to use with ionic webview
- iOS 17 crash
- It doesn't work on iOS. HOT 1
- Images not shown
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pdf-generator.