PDF file download not working only for iPad specific browsers - ipad

A PDF file is generated on server side and pushed to client end for download. While the download works in all browsers on windows , fails on IPAD.
Please advise.
Specification : OS 6, Safari 6.1 , Chrome 23.0.1271.100
Please note: In this application pdf is not downloaded on to a new url (NO REDIRECTION).
General behavior: IPad browser (safari / chrome) does not support the download window, hence its expected to open the pdf and provides option to view in pdf compatible apps. Which is not currently happening.
When i debug the below servlet action code for download, the pdf file is successfully generated on server but browser on Ipad does not show :-(
Code sample :
/** Setting response Header **/
response.setHeader("Content-Type", "application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=sample.pdf");
response.setHeader("Connection", "close");
response.setHeader("Cache-Control","cache");
response.setHeader("Pragma","cache");
response.setDateHeader ("Expires", dt.getTime() + 100000);
/** Writing to output **/
InputStream stream = info.getInputStream();
OutputStream os = response.getOutputStream();
try {
response.setContentType(contentType);
copy(stream, response.getOutputStream());
}
finally {
if (stream != null) {
stream.close();
}
}

After testing, the download action code pasted above appeared to be working fine as the issue was BROWSER specific.
Andriod Tablet - Firefox browser downloads the pdf onto pop up window.
IPad : Safari - FIX: Forced the content to open up in a new tab, something like this :
window.open(print_url);
where print_url is the baseurl+action.do+additional_parameter.

To display a pdf instead of asking the browser to save it, use "inline" instead of "attachment".
response.setHeader("Content-Disposition", "inline;filename=sample.pdf");
Also, you're setting content type twice, once in the header and once using setContentType().
I'm not sure if those two headers interact or cancel each other out, so can't say for sure that it's a source of error, but it seems like something to consider changing.

Related

How to copy from Storage to FileSystemStorage in Codenameone and display in BrowserComponent

I've been reading a lot of StackOverflow posts that discuss copying data from FileSystemStorage to Storage in CodenameOne, such as described in this answer from Shai, as seen below:
InputStream stream =
FileSystemStorage.getInstance().openInputStream(i);
OutputStream out =
Storage.getInstance().createOutputStream("MyImage");
Util.copy(stream, out);
Util.cleanup(stream);
Util.cleanup(out);`
I've been trying to do the reverse: save from Storage to FileSystemStorage in order to show a PDF in the BrowserComponent (while using iOS), but have not been able to do so. I need to show the PDF within the app (so I don't want to use Display.getInstance().execute()).
Basically, I'm trying to dynamically populate a Container with whatever files the user selects-- I am using the FileChooser library for CN1 from Steve Hannah. (Disclaimer: I have made slight modifications to this library as it used in the app I'm working on-- HOWEVER, when I choose images with this library and pull them from Storage to an Image via InputStream, they display perfectly in an ImageViewer so I know that all files are being saved correctly in Storage.)
Here is my code (with help from Steve Hannah's comment on GitHub):
//fileLocation and fileName are slightly different but both end with file extension
File file = new File(fileToUpload.getFileName());
FileSystemStorage fss = FileSystemStorage.getInstance();
InputStream is = Storage.getInstance().createInputStream(fileToUpload.getLocation());
OutputStream os = fss.openOutputStream(file.getAbsolutePath());
Util.copy(is, os);
ToastBar.Status status = ToastBar.getInstance().createStatus();
String message = file.exists() + " " + file.isFile() + file.getAbsolutePath();
status.setMessage(message);
status.setExpires(3000);
status.show();
NativeLogs.getNativeLogs();
if (Display.getInstance().getPlatformName().equals("ios")) {
//Log.p("in ios !!!!");
BrowserComponent browserComponent = new BrowserComponent();
browserComponent.setURL(file.getPath());
horizontalContainer.add(browserComponent);
}
The ToastBar displays true and true for file.exists() and file.isFile().
I stipulate iOS because as far as I've seen while researching previewing PDFs within an app, I've seen that Android needs to have a different implementation, like adding a NativeInterface with an Android library. I also saw in different answers on the Google Group that this functionality (using browserComponent to view PDFs) is only available for iOS and not on the simulator. In the simulator, I see a blank space. My iPhone just freezes and/or crashes after displaying the ToastBar (and I work on a Windows machine, so not much ability to see native logs....)
What can I do to access the file and show it in the BrowserComponent?
Thank you!
Simple solution -- the file had a space in it (eg. "Test page.pdf") and didn't show! When I used files that didn't have spaces this worked and after removing spaces in the file names, thankfully everything worked. I'll have to add code to handle this scenario.
Thanks for your help!

Android webview jwplayer7 cannot read property 'jwplayer.volume' of null

I have an app that is using a webview to launch an html that loads JWP7 and throws an error Uncaught TypeError :cannot read property 'jwplayer.volume' of null
The same page is loading perfectly on mobile and desktop browsers.
I tried to add in the javascript of the html after the jwplayer.js is being called and before the setup, the following code:
if (typeof jwplayer.volume == "undefined" || typeof jwplayer.volume == null )
jwplayer.volume = 10;
I do see the new volume property using a desktop/mobile browser but it doesn't changes the TypeError in the webview, probably because the TypeError is thrown while running the jwplayer.js script, before it reaches my javascript check.
When i'm Using the JWP6 everything is working perfectly.
Any suggestions on how to fix it?
I inspected the jwplayer.js code.
And saw that it reads the last settings of Volume (jwplayer.volume) and Mute (jwplayer.mute) from the LocalStorage; instead of from cookie.
(Probably JWPlayer 6 was using cookies.)
So, you need to enable LocalStorage access in your WebView; like you do for JavaScript.
Sample code below.
WebView webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true); // This will allow access
webView.setWebViewClient(new WebViewClient());
/* WebView.setWebContentsDebuggingEnabled(true); // This is to inspect your WebView from desktop Chrome. (>= API 19) You may not want to include this in production. */
webView.loadUrl(url);
JW Player doesn't support using the web player in Android or iOS webview; however, there are native mobile SDKs available to support in-app video: developer.jwplayer.com/android-sdk

iOS Safari issue with Audio from Server

So currently working on a project and experiencing a strange issue with the ios version of Safari involving the playback of an audio file from a server.
I'm currently facing the following issue:
Person comes onto the page which has a standard html5 audio tag, and a direct link to the audio file for downloading purposes.
Person tries to listen to audio from audio tag, content plays for x number of minutes, cuts off then repeats (the x number of minutes is NOT the length of the recording, and is not consistent).
Person tries direct link of recording, rather then downloading the recording, Safari appears to go to a new page and wraps the download url in a video element, and the same issue as step 2 occurs.
Now the audio file is served up via a java scriptlet, which serves the file with the following code snippet:
String fn = saveTo + file_name;
f = new File(fn);
String fname = f.getName();
String contentType = "audio/wav";
if(fname.endsWith("mp3")){
contentType = "audio/mp3";
}
response.setContentType(contentType);
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-disposition", "attachment;filename="+f.getName());
response.setHeader("Content-Length", ""+f.length());
FileInputStream fin = null;
try{
fin = new FileInputStream(f.getCanonicalFile());
byte[] data = new byte[1024];
int x = 0;
while((x = fin.read(data, 0, 1024))>=0){
response.getOutputStream().write(data, 0, x);
Thread.sleep(1);
}
} finally {
if(fin != null) {
try{
fin.close();
}catch(Exception ex){}
}
}
Now I know the code isn't the best by any measure, it isn't my code, and we're obviously working on the assumption that the file is found.
I'm finding when debugging on the iPhone with debug mode on a mac, it doesn't seem to show a return status code. It shows no response headers but it obviously must be receiving something. The server log seems to think its returning a status 200, this showing in Chrome and Firefox.
The code above appears to work fine with Chrome, and Firefox, but not Safari.
The only thing I am guessing is it has something to do with how the file is being pushed to the output stream that Safari isn't liking, or maybe its getting confused and should have a different status code. I've been banging my head against this for a good few days, and reading as much as I can about Safari, though most of the documentation I'm finding is on its "unique" implementation of web audio, and the use of a single channel which seems to be irrelevant to this.
Any Help would be appreciated.
I experienced the same issue with Safari on iOS, and after a lot of debugging, I found the issue was related to the combination of headers applied to the response.
My application is C#-based, but this solution should be platform independent (because as previously stated, it is a response header issue).
Necessary Headers:
Content-Range: bytes 0-[content length]/[content length]
Content-Transfer-Encoding: binary
Content-Length: [content length]
Accept-Ranges: bytes
I devised this after inspecting a response from MP3s delivered via Akamai's content delivery service.

Adobe air on iOS - FileReference Download Error

When I use the Download method of the FileReference class, everything works fine on Desktop and Android, but I get an error on iOS.
This is the code:
var req = new URLRequest(url);
var localRef:FileReference = new FileReference();
localRef.download(req);
On iOS I'm getting an Alert:
Download Error
File downloads not supported.
I already tried to NavigateToUrl() and it asks save the file in Dropbox or another App.
How can I fix this error?
You shouldn't use FileReference on mobile (or AIR, in general, though it does open the Load/Save dialog on desktop so there can be some use there). You should instead use File and FileStream, which give you far more control over the file system.
In this case, you could try to use File.download() and save it to File.applicationStorageDirectory, but I don't know if it will have any difference since it extends FileReference.
What I generally do is use URLStream instead of URLLoader. It gives you access to the raw bytes of the file you are downloading and then use File and FileStream
So something like (and this is untested off the top of my head, though I have used similar in the past):
var urlStream:URLStream = new URLStream();
urlStream.addEventListener(Event.COMPLETE, completeHandler);
urlStream.load(new URLLoader('url');
function completeHandler(e:Event):void {
var bytes:ByteArray = new ByteArray();
urlStream.readBytes(bytes);
var f:File = File.applicationStorageDirectory.resolvePath('filename');
var fs:FileStream = new FileStream();
fs.open(f, FileMode.WRITE);
fs.writeBytes(bytes);
fs.close();
}
Now, obviously, there is a lot more you want to account for (errors, progress, etc). That should be enough to point you in the right direction, however.
It's possible to create a full download manager using this method (something I did for an iOS project two years ago), since you can save as-you-go to the file system rather than waiting until Event.COMPLETE fires (using the ProgressEvent.PROGRESS event). That allows you to avoid having a 500MB file in memory, something most devices can't handle.

iOS - Check if webView is loaded with PDF content on non-'pdf' file extension

I would like to Check (boolean value) if PDF content is loaded in the UIWebView. This question already exists, but not this case.
It's not as simple as just checking the path extension of the webView Url because this PDF content is generated via ASPX. The extension will return 'aspx'. Also not just looking in the url, the string 'pdf' will always be found in the url since I requesting a PDF file. I need to check if the server really returns a PDF file as it should.
Ok, The webView is loaded with PDF content but not to a specific pdf file on the server. (maybe apache redirect,aspx pdf generation or just something else)
If this url is loaded in the Safari Application (to the aspx file), it will detect this PDF content (even if aspx file). It says "open in..." and so on.
How to detect if the UIWebView is loaded with PDF content on non-pdf extention file?
Jonathan
I solved it using this:
Thanks #Guilherme
-(bool)isPDFContentLoadedInWebView:(UIWebView *)webView {
NSString *mime =[[NSURLCache sharedURLCache] cachedResponseForRequest:webView.request].response.MIMEType;
if (!([mime rangeOfString:#"pdf"].location == 0)) {
return YES;
} else {
return NO;
}
return NO;
}

Resources