I tried to convert jsp page to save as pdf by using itext.i downloaded itex.jars and included those in to my project.after that what i will do to get result as pdf page?
Check this link..
http://www.pd4ml.com/examples.htm
Example :
public static void main(String[] args) {
try {
PdfViewerStarter jt = new PdfViewerStarter();
jt.doConversion("http://pd4ml.com/sample.htm", "D:/pd4ml.pdf");
} catch (Exception e) {
e.printStackTrace();
}
}
public void doConversion( String url, String outputPath )
throws InvalidParameterException, MalformedURLException, IOException {
File output = new File(outputPath);
java.io.FileOutputStream fos = new java.io.FileOutputStream(output);
PD4ML pd4ml = new PD4ML();
pd4ml.setHtmlWidth(userSpaceWidth);
pd4ml.setPageSize(pd4ml.changePageOrientation(PD4Constants.A4));
pd4ml.setPageInsetsMM(new Insets(topValue, leftValue, bottomValue, rightValue));
pd4ml.useTTF("c:/windows/fonts", true);
pd4ml.render(new URL(url), fos);
fos.close();
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(output);
} else {
System.out.println("Awt Desktop is not supported!");
}
System.out.println( outputPath + "\ndone." );
}
The statement jt.doConversion("http://pd4ml.com/sample.htm", "D:/pd4ml.pdf");
instead of "http://pd4ml.com/sample.htm" i have to pass dynamic page url and if page is converted into pdf format so that pdf file should be in same format.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
public class GenratePdf {
public static void generatePDF(String inputHtmlPath, String outputPdfPath)
{
try {
String url = new File(inputHtmlPath).toURI().toURL().toString();
System.out.println("URL: " + url);
OutputStream out = new FileOutputStream(outputPdfPath);
//Flying Saucer part
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(url);
renderer.layout();
renderer.createPDF(out);
out.close();
}
catch (DocumentException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
String inputFile = "D:\\mailPages\\pdfTest.jsp";
String outputFile = "D:/mailPages/testpdf.pdf";
generatePDF(inputFile, outputFile);
System.out.println("Done!");
}
}
We are using pd4ml for downloading a content of JSP in PDF form. You can get the jars here.
Keep this code in your JSP after all the imports
<pd4ml:transform
inline="false"
fileName="application.pdf"
screenWidth="815"
pageFormat="A4"
pageOrientation="portrait"
pageInsets="10,10,10,10,points">
You need to send the html contents to a Java servlet/controller and save the xHTML to PDF.
You'll need to use HtmlPipelineContext and XMLWorker
Have a look here:
Converting HTML files to PDF
and here:
http://itextpdf.com/examples/iia.php?id=56
Related
I want to retrieve data from a website using Nashorn script engine
I have the java code where I can retrieve data from a sample website template.
Now I want to call that java file from java script file.
following is the code:
JAVA CODE(Nsample.java):
package sample;
import java.net.*;
import java.io.*;
public class Nsample
{
public static void main(String[] args)
{
String output = getUrlContents("https://freewebsitetemplates.com/");
System.out.println(output);
}
public static String getUrlContents(String theUrl)
{
StringBuilder content = new StringBuilder();
try
{
URL url = new URL(theUrl);
URLConnection urlConnection = url.openConnection();
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null)
{
content.append(line + "\n");
}
bufferedReader.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return content.toString();
}
}
JAVASCRIPT code:(sample.js)
var n = Java.type('C.JavaFolder.sample.Nsample');
var result = n.getUrlContents("https://freewebsitetemplates.com/");
print(result);
I'm trying to compile javascript code using command prompt but it is showing CLASSNOTFOUNDEXCEPTION.
The command was jjs sample.js.Im assuming I did some mistake in Java.type() function.
Can anyone solve this?
This line is the problematic line:
var n = Java.type('C.JavaFolder.sample.Nsample');
Java.type accepts fully qualified java type name. Based on your Java code, your package seems to be "sample" and class name is "Nsample". So the fully qualified class name would be "sample.Nsample".
You should compile your Java classes and specify the directory in -classpath option (of jjs tool or your java application if you use javax.script API with nashorn).
Instead of calling Java from JavaScript , I tried to call JavaScript from java and worked well.
I created some functions in JavaScript and invoked those functions from Java code.
Following is the code.Hope this helps.
Test.java:
import javax.script.*;
import java.io.*;
import java.util.*;
public class Test{
public static void main(String[] args) throws Exception{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
engine.eval(new FileReader("test.js"));
Invocable invoke = (Invocable)engine;
Object res = invoke.invokeFunction("httpGet","https://www.javaworld.com");
System.out.println(res);
}
}
test.js:
var httpGet = function(theUrl){
var con = new java.net.URL(theUrl).openConnection();
con.requestMethod = "GET";
return asResponse(con);
}
function asResponse(con){
var d = read(con.inputStream);
return d;
}
function read(inputStream){
var inReader = new java.io.BufferedReader(new
java.io.InputStreamReader(inputStream));
var inputLine;
var response = new java.lang.StringBuffer();
while ((inputLine = inReader.readLine()) != null) {
response.append(inputLine);
}
inReader.close();
return response.toString();
}
I am actually trying to click on a link to download a file from :
http://www.histdata.com/download-free-forex-historical-data/?/metatrader/1-minute-bar-quotes/eurusd/2013
The html code for the line I am trying to download is:
<a id="a_file" title="Download the zip data file" href="javascript:return true;" target="nullDisplay">HISTDATA_COM_MT_EURUSD_M1_2013.zip</a>
And the java code is:
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_38);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
HtmlPage htmlPage=webClient.getPage("http://www.histdata.com/download-free-forex-historical-data/?/metatrader/1-minute-bar-quotes/eurusd/2016/7");
List<HtmlAnchor> anchors=htmlPage.getAnchors();
HtmlAnchor anchor = null;
for (int i = 0; i < anchors.size(); ++i) {
anchor = anchors.get(i);
String sAnchor = anchor.asText();
if (sAnchor.equals("HISTDATA_COM_MT_EURUSD_M1_201607.zip"))
break;
}
Page p = anchor.click();
webClient.waitForBackgroundJavaScript(60000);
InputStream is = p.getWebResponse().getContentAsStream();
int b = 0;
while ((b = is.read()) != -1) {
System.out.print((char)b);
}
The error message i get is:
Jul 12, 2016 1:29:57 PM com.gargoylesoftware.htmlunit.javascript.StrictErrorReporter error
SEVERE: error: message=[invalid return] sourceName=[javascript url] line=[88] lineSource=[return true;] lineOffset=[7]
Exception in thread "main" ======= EXCEPTION START ========
Exception class=[net.sourceforge.htmlunit.corejs.javascript.EvaluatorException]
com.gargoylesoftware.htmlunit.ScriptException: invalid return (javascript url#88)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:904)
at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:628)
at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:515)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.compile(JavaScriptEngine.java:729)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.compile(JavaScriptEngine.java:694)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.execute(JavaScriptEngine.java:746)
at com.gargoylesoftware.htmlunit.html.HtmlPage.executeJavaScriptIfPossible(HtmlPage.java:902)
at com.gargoylesoftware.htmlunit.html.HtmlAnchor.doClickStateUpdate(HtmlAnchor.java:114)
at com.gargoylesoftware.htmlunit.html.HtmlAnchor.doClickStateUpdate(HtmlAnchor.java:179)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:800)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:747)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:694)
at clickPage.main(clickPage.java:38)
Caused by: net.sourceforge.htmlunit.corejs.javascript.EvaluatorException: invalid return (javascript url#88)
at com.gargoylesoftware.htmlunit.javascript.StrictErrorReporter.error(StrictErrorReporter.java:65)
at net.sourceforge.htmlunit.corejs.javascript.Parser.addError(Parser.java:188)
at net.sourceforge.htmlunit.corejs.javascript.Parser.addError(Parser.java:167)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:255)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:244)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:237)
at net.sourceforge.htmlunit.corejs.javascript.Parser.returnOrYield(Parser.java:1632)
at net.sourceforge.htmlunit.corejs.javascript.Parser.statementHelper(Parser.java:1022)
at net.sourceforge.htmlunit.corejs.javascript.Parser.statement(Parser.java:928)
at net.sourceforge.htmlunit.corejs.javascript.Parser.parse(Parser.java:572)
at net.sourceforge.htmlunit.corejs.javascript.Parser.parse(Parser.java:492)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileImpl(Context.java:2660)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileString(Context.java:1623)
at com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory$TimeoutContext.compileString(HtmlUnitContextFactory.java:172)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileString(Context.java:1615)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$2.doRun(JavaScriptEngine.java:720)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:889)
... 12 more
Enclosed exception:
net.sourceforge.htmlunit.corejs.javascript.EvaluatorException: invalid return (javascript url#88)
at com.gargoylesoftware.htmlunit.javascript.StrictErrorReporter.error(StrictErrorReporter.java:65)
at net.sourceforge.htmlunit.corejs.javascript.Parser.addError(Parser.java:188)
at net.sourceforge.htmlunit.corejs.javascript.Parser.addError(Parser.java:167)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:255)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:244)
at net.sourceforge.htmlunit.corejs.javascript.Parser.reportError(Parser.java:237)
at net.sourceforge.htmlunit.corejs.javascript.Parser.returnOrYield(Parser.java:1632)
at net.sourceforge.htmlunit.corejs.javascript.Parser.statementHelper(Parser.java:1022)
at net.sourceforge.htmlunit.corejs.javascript.Parser.statement(Parser.java:928)
at net.sourceforge.htmlunit.corejs.javascript.Parser.parse(Parser.java:572)
at net.sourceforge.htmlunit.corejs.javascript.Parser.parse(Parser.java:492)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileImpl(Context.java:2660)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileString(Context.java:1623)
at com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory$TimeoutContext.compileString(HtmlUnitContextFactory.java:172)
at net.sourceforge.htmlunit.corejs.javascript.Context.compileString(Context.java:1615)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$2.doRun(JavaScriptEngine.java:720)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:889)
at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:628)
at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:515)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.compile(JavaScriptEngine.java:729)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.compile(JavaScriptEngine.java:694)
at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.execute(JavaScriptEngine.java:746)
at com.gargoylesoftware.htmlunit.html.HtmlPage.executeJavaScriptIfPossible(HtmlPage.java:902)
at com.gargoylesoftware.htmlunit.html.HtmlAnchor.doClickStateUpdate(HtmlAnchor.java:114)
at com.gargoylesoftware.htmlunit.html.HtmlAnchor.doClickStateUpdate(HtmlAnchor.java:179)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:800)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:747)
at com.gargoylesoftware.htmlunit.html.DomElement.click(DomElement.java:694)
at clickPage.main(clickPage.java:38)
== CALLING JAVASCRIPT ==
return true;
======= EXCEPTION END ========
Please let me know what is wrong in my code and how to download file from the given link.
//Complete solution
//1. open page
//2. list the urls of that page using xpath
//3. download all file of that url .
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomAttr;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
public class Crawler {
public static void main(String[] args) throws Throwable {
String baseUrl= "Enter base http/https url here";
String url1 = baseUrl+ "add addational url of main page";
String xpathofdownlaodlinks = "xpath of file url or--> html/body/div/div[3]/a/#href";
String pathToSaveFile="d:\\local\\to\\save\\files";
String fileExt = ".txt";
WebClient webclient = new WebClient(BrowserVersion.CHROME);
webclient.getOptions().setJavaScriptEnabled(true);
HtmlPage page = webclient.getPage(url1);
List<DomAttr> links = (List<DomAttr>) page.getByXPath(xpathofdownlaodlinks);
List<HtmlAnchor> anchors=page.getAnchors();
for (DomAttr object : links) {
String link = baseUrl+object.getValue()+"";
Date d=new Date();
downlaodRawFile(link,pathToSaveFile +d.getTime() + fileExt);
}
webclient.close();
}
public static void downlaodRawFile(String link,String fileName) throws IOException, Throwable{
URL url = new URL( link );
HttpURLConnection http = (HttpURLConnection)url.openConnection();
Map< String, List< String >> header = http.getHeaderFields();
while( isRedirected( header )) {
link = header.get( "Location" ).get( 0 );
url = new URL( link );
http = (HttpURLConnection)url.openConnection();
header = http.getHeaderFields();
}
InputStream input = http.getInputStream();
byte[] buffer = new byte[4096];
int n = -1;
OutputStream output = new FileOutputStream( new File( fileName ));
while ((n = input.read(buffer)) != -1) {
output.write( buffer, 0, n );
}
output.close();
}
private static boolean isRedirected( Map<String, List<String>> header ) {
for( String hv : header.get( null )) {
if( hv.contains( " 301 " )
|| hv.contains( " 302 " )) return true;
}
return false;
}
}
Thanks for reporting, the error is now fixed in SVN.
Please use latest build or snapshot.
I'm attempting to create a text (numbers.txt) file where the user indicates that they can save files. I know
File directory = new File("/home/jon/somewhere");
File fullPath = new File(directory, fileName);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
(new FileOutputStream(fullPath), charSet));
try {
writer.write("\n");
writer.write("work");
} finally {
writer.close();
}
needs to be inserted, but I don't know how to make it create the .txt file at that location, which is user defined through the scanner. Here's my code so far, up to the point I'm expecting to input the code above. Using Eclipse IDE, if this is information is needed.
The point of the code is to save the numbers to the txt file and pull them back to read them, so they can be calculated.
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.Scanner;
import java.io.Serializable;
import java.lang.SecurityException;
import java.util.Formatter;
public class StrangeAverage implements Serializable{
/**
* #param args
*/
public static void main(String[] args) throws IOException
{
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int fails = 0;
do {
System.out.printf("Please enter a directory where you can save files, in case of error/shutdown: ");
Path path = Paths.get(input.nextLine());
if (Files.isDirectory(path))
{
System.out.println("Using Directory " +path);
break;
}
else
{
System.out.println("That's not an open directory.");
fails++;
}
}while(fails < 5);
if (fails == 5)
{
System.out.print("Too many failed attempts. Exiting...");
return;
}
if (fails < 5)
{
System.out.println("Valid Directory.");
}
System.out.printf("Please enter ten integers:");
Create a java.io.FileWriter object first, then create a java.io.PrintWriter based on that FileWriter object. Then you can use PrintWriter.print() to add text to the file:
FileWriter fileWriter = new FileWriter("filename.ext", true);
PrintWriter out = new PrintWriter(fileWriter);
out.print("Text to go in the file");
out.println("Text to go in the file");
Note that you'll need to encase this code in a try-catch block to handle IOExceptions:
try {
FileWriter fileWriter = new FileWriter("filename.ext", true);
PrintWriter out = new PrintWriter(fileWriter);
out.print("Text to go in the file");
out.println("Text to go in the file");
} catch (java.io.IOException e) {
//handle
}
out.close(); //Don't forget to close the file when done
Let's assume that you successfully read the file into the String and the numbers into an array of numbers and the path is an absolute path.
String nameOfTheFile = "/absolute/path";
int[] numbersToStore = new int[]{1,2,3,4,5};
then you will create the .txt file on the location like this:
File txtWithNumbers = new File(nameOfTheFile + ".txt");
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(txtWithNumbers), charSet
)
);
try {
for(int i in numbersToStore) {
writer.write(i + "\n");
}
} finally {
writer.close();
}
I have one hi-bride application in which one html page has file picker and i want to load that page in Android webview.
This pickers works well in Device browser but not in webview.
For to support this i am using one hidden method of WebChromeClient which is as below
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){
/**updated, out of the IF **/
mUploadMessage = uploadMsg;
/**updated, out of the IF **/
if(boolFileChooser){ //Take picture from filechooser
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult( Intent.createChooser( i, "Pick File.." ), FILECHOOSER_RESULTCODE );
} else { //Take photo and upload picture
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
photo = new File(Environment.getExternalStorageDirectory(), "Pic.jpg");
if(photo.exists())
photo.delete();
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
mCapturedImageURI = Uri.fromFile(photo);
startActivityForResult(cameraIntent, CAMERAREQUEST_RESULTCODE);
}
}
// Per Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg){
openFileChooser(uploadMsg, "");
}
//Aftre
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, "");
}
It was working fine till 4.3 but from 4.4 this method is not getting called.
And they said https://code.google.com/p/android/issues/detail?id=62220 this has been removed.
Do anyone knows any alternate way. Please let me know your help will greatly appreciated
There are no ways to openFileChooser method after 4.3 as google has removed that and they will come up with other way to handle this file chooser stuff in next version (Confirmed by Google engineer).
I moved to hybrid architecture to and write native function for file picker.
In Android 5.0, they introduced onShowFileChooser(), with which you can use an input form field in the webview and launch a file chooser to select images and files from the device.
Bitmap bitmap;
private static final int READ_REQUEST_CODE = 42;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// Filter to only show results that can be "opened", such as a
// file (as opposed to a list of contacts or timezones)
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Filter to show only images, using the image MIME data type.
// If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
// To search for all documents available via installed storage providers,
// it would be "*/*".
intent.setType("image/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode,
Intent resultData) {
// The ACTION_OPEN_DOCUMENT intent was sent with the request code
// READ_REQUEST_CODE. If the request code seen here doesn't match, it's the
// response to some other intent, and the code below shouldn't run at all.
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter.
// Pull that URI using resultData.getData().
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),uri);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ImageView my_img_view = (ImageView ) findViewById (R.id.uploadlayout2);
my_img_view.setImageBitmap(bitmap);
}
}
}
I've seen this question has been asked a lot of times, but still can't manage to get my code working.
I want my webview to load some URL (say www.google.com) and then apply some javascript stored in assets/jstest.js, which contains the following:
function test(){
document.bgColor="#00FF00"; //turns to green the background color
}
And here's where I try to load the JS:
#Override
public void onPageFinished(WebView view, String url){
view.loadUrl("javascript:(function() { "
+ " document.bgColor='#FF0000';" //turns to red the background color
+ " var script=document.createElement('script'); "
+ " script.setAttribute('type','text/javascript'); "
+ " script.setAttribute('src', 'file:///android_asset/jstest.js'); "
+ " script.onload = function(){ "
+ " test(); "
+ " }; "
+ " document.getElementsByTagName('head')[0].appendChild(script); "
+ "})()");
}
I know the javascript here works because the background color actually turns to red, but for some reason it won't load jstest.js. I think the problem might be in file path (I'm certain every other line of the javascript code is correct), but it looks correct to me. And the file is in the right folder.
What am I missing?
EDIT:
Since WebResourceResponse class is available only with API Level 11, here's what I've figured out in the end.
public void onPageFinished(WebView view, String url){
String jscontent = "";
try{
InputStream is = am.open("jstest.js"); //am = Activity.getAssets()
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while (( line = br.readLine()) != null) {
jscontent += line;
}
is.close();
}
catch(Exception e){}
view.loadUrl("javascript:(" + jscontent + ")()");
}
with the jstest.js simply containing:
function() {
document.bgColor="#00FF00";
}
I tried the same thing, loading a bookmarklet (the javascript code in your loadUrl() call) into a third-party page. My bookmarklet also depends on other assets (javascript and css files) which would not load with a file:///android_asset URL.
That's because the security context of the page is still that of, e.g., http://www.google.com, and that's not allowed access to file: URLs. You should be able to see the errors if you supply/override a WebChromeClient.onConsoleMessage().
I ended up with a kludge where I changed the bookmarklet's asset references to a bogus URL scheme, like:
asset:foo/bar/baz.js
and added a WebViewClient.shouldInterceptRequest() override which looks for those and loads them from assets using AssetManager.open().
One thing I don't like about this kludge is that the asset: scheme is open to any third-party HTML/Javascript on any page my view loads, giving them access to my app's assets.
One alternative, which I didn't try, would be to embed the sub-assets in the bookmarklet using data: URLs, but that can get unwieldy.
I'd much prefer it if there was a way to manipulate the security context of just the JS bookmarklet I'm loading in loadUrl(), but I can't find anything like that.
Here's a snippet:
import android.webkit.WebResourceResponse;
...
private final class FooViewClient extends WebViewClient
{
private final String bookmarklet;
private final String scheme;
private FooViewClient(String bookmarklet, String scheme)
{
this.bookmarklet = bookmarklet;
this.scheme = scheme;
}
#Override
public void onPageFinished(WebView view, String url)
{
view.loadUrl(bookmarklet);
}
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
{
if (url.startsWith(scheme))
try
{
return new WebResourceResponse(url.endsWith("js") ? "text/javascript" : "text/css", "utf-8",
Foo.this.getAssets().open(url.substring(scheme.length())));
}
catch (IOException e)
{
Log.e(getClass().getSimpleName(), e.getMessage(), e);
}
return null;
}
}
I think the iceam cream webview client of cordova does the very thing you want to do.
It would be nice if this was documented somewhere but, as far as I can see, it is not.
Take a look at cordova's android github:
https://github.com/apache/incubator-cordova-android/blob/master/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
Here is how i ended up doing it. I used the Content:// protocol and set up a contentprovider to handle returning a file descriptor to the system
Here is my fileContentProvider:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
public class FileContentProvider extends ContentProvider {
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) {
Log.d("FileContentProvider","fetching: " + uri);
ParcelFileDescriptor parcel = null;
String fileNameRequested = uri.getLastPathSegment();
String[] name=fileNameRequested.split("\\.");
String prefix=name[0];
String suffix=name[1];
// String path = getContext().getFilesDir().getAbsolutePath() + "/" + uri.getPath();
//String path=file:///android_asset/"+Consts.FILE_JAVASCRIPT+"
/*check if this is a javascript file*/
if(suffix.equalsIgnoreCase("js")){
InputStream is = null;
try {
is = getContext().getAssets().open("www/"+Consts.FILE_JAVASCRIPT);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
File file = stream2file(is,prefix,suffix);
try {
parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException e) {
Log.e("FileContentProvider", "uri " + uri.toString(), e);
}
}
return parcel;
}
/*converts an inputstream to a temp file*/
public File stream2file (InputStream in,String prefix,String suffix) {
File tempFile = null;
try {
tempFile = File.createTempFile(prefix, suffix);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tempFile.deleteOnExit();
FileOutputStream out = null;
try {
out = new FileOutputStream(tempFile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
IOUtils.copy(in, out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tempFile;
}
#Override
public boolean onCreate() {
return true;
}
#Override
public int delete(Uri uri, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public Uri insert(Uri uri, ContentValues contentvalues) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
}
in the manifest i defined the provider:
<provider android:name="com.example.mypackage.FileContentProvider"
android:authorities="com.example.fileprovider"
/>
Here is the javascript o inject into the webview:
webView.loadUrl("javascript:(function() { "
+ "var script=document.createElement('script'); "
+ " script.setAttribute('type','text/javascript'); "
+ " script.setAttribute('src', 'content://com.example.fileprovider/myjavascriptfile.js'); "
/* + " script.onload = function(){ "
+ " test(); "
+ " }; "
*/ + "document.body.appendChild(script); "
+ "})();");
and here is the myjavascriptfile.js (as an example):
function changeBackground(color) {
document.body.style.backgroundColor = color;
}
Maybe you could have assets as 'html/javascript templates'. You could combine different of these text sources and string logic to compose your desired html to be loaded into the WebViewer. Then, you use .loadData instead of .loadUrl
I'm using it on my own and it seems to work pretty well.
Hope it helps!
With the following two conditions given:
minSdkVersion 21
targetSdkVersion 28
I am able to successfully load any local asset (js, png, css) via the following Java code
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if (uri.getHost().equals("assets")) {
try {
return new WebResourceResponse(
URLConnection.guessContentTypeFromName(uri.getPath()),
"utf-8",
MainActivity.this.getAssets().open(uri.toString().substring(15)));
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
And in the HTML code I can use
<link rel="stylesheet" href="https://assets/material.min.css">
<script src="https://assets/material.min.js"></script>
<script src="https://assets/moment-with-locales.min.js"></script>
<img src="https://assets/stackoverflow.png">
In Java the following then also works (you'd also need to add a favicon.ico to the assets)
webView.loadUrl("https://assets/example.html");
Using https:// as the scheme allows me to load local assets from a page served via HTTPS without security issues due to mixed-content.
None of these require to be set:
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
webSettings.setDomStorageEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);