I am injecting a javascript file to the WebView and that javascript file needs to load more files from the app assets folder.
i used to load the files from remote server, but now i need to load them locally.
I am getting "not allowed to load local resource".
is this even possible? i can't find any solution here or using google.
example:
...
webView.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
"script.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(script)" +
"})()");
this injects a "script.js" file into the webview.
inside the script.js file i want to inject css background image that is located inside the app assets folder. when im trying to access "file:///android_asset" i get the "not allowed to load local resource" error.
if you want load your local html page and resources to the web view you should use webView.loadDataWithBaseURL
public void loadLocalHtmlToWebView() throws IOException {
WebView mWebView = findViewById(R.id.my_webview);
File publicDir = new File(getCacheDir(), "public");
if (publicDir.exists() == false) {
publicDir.mkdirs();
String[] ls = getAssets().list("public");
for (int i = 0; i < ls.length; i++) {
InputStream inputStream = getAssets().open("public/" + ls[i]);
File outFileLocation = new File(publicDir, ls[i]);
outFileLocation.createNewFile();
Log.e("AMIR", "Wrinting to : " + outFileLocation.getPath());
FileOutputStream fileOutputStream = new FileOutputStream(outFileLocation);
byte[] buffer = new byte[1024];
while (inputStream.read(buffer) != -1) {
fileOutputStream.write(buffer);
}
fileOutputStream.flush();
fileOutputStream.close();
inputStream.close();
}
}
String indexHtml="";
BufferedReader bufferedReader=new BufferedReader(new FileReader(new File(publicDir,"index.html")));
String ln="";
while((ln=bufferedReader.readLine())!=null){
indexHtml+=ln;
}
bufferedReader.close();
Log.e("AMIR","Html : "+indexHtml);
String baseUrl = "file://" + publicDir.getPath() + "/";
mWebView.loadDataWithBaseURL(baseUrl, indexHtml, "text/html", "UTF-8", null);
}
Assets folder :
my index.html code :
<html>
<head>
<title>Hello</title>
<head>
<body>
Hello
<img src="./img.jpg"/>
<body>
</html>
and this is a good and well explained tutorial for webView :
http://tutorials.jenkov.com/android/android-web-apps-using-android-webview.html
Related
I found interesting code on stack overflow, but the only thing I don't like about it is that it uses JQuery that is imported via the Internet, and I need it all to work without connecting to the Internet. Can you please tell me how this can be changed?
Code:
void handleRoot() {
snprintf ( htmlResponse, 3000,
"<!DOCTYPE html>\
<html lang=\"en\">\
<head>\
<meta charset=\"utf-8\">\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\
</head>\
<body>\
<h1>Time</h1>\
<input type='text' name='date_hh' id='date_hh' size=2 autofocus> hh \
<div>\
<br><button id=\"save_button\">Save</button>\
</div>\
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js\"></script>\
<script>\
var hh;\
$('#save_button').click(function(e){\
e.preventDefault();\
hh = $('#date_hh').val();\
$.get('/save?hh=' + hh , function(data){\
console.log(data);\
});\
});\
</script>\
</body>\
</html>");
server.send ( 200, "text/html", htmlResponse );
}
void handleSave() {
if (server.arg("hh")!= ""){
Serial.println("Hours: " + server.arg("hh"));
}
}
void setup() {
// Start serial
Serial.begin(115200);
delay(10);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
server.on ( "/", handleRoot );
server.on ("/save", handleSave);
server.begin();
}
void loop() {
server.handleClient();
}
The minified jquery javascript can be stored on the ESP and served up by the module when the browser requests it.
One easy way to do this is to use the SPI Flash File System to serve up the HTML as well as the JQuery javascript.
This means creating an index.html in a data sub-directory in the sketch. Add the HTML in the original sketch into the file. Also change the script source in this file to a relative path:
<script src="jquery.min.js"></script>
Then download jquery.min.js and copy this into the data sub-directory as well.
The example code at https://tttapa.github.io/ESP8266/Chap11%20-%20SPIFFS.html can be used as a starting point for the rest of the code. The main parts of this involve initializing SPIFFS and setting up the handler for the file request:
SPIFFS.begin();
server.onNotFound([]() {
if (!handleFileRead(server.uri()))
server.send(404, "text/plain", "404: Not Found");
});
// retain the save endpoint
server.on("/save", handleSave);
server.begin();
Then implement the file handler and its content type handler:
String getContentType(String filename)
{
if (filename.endsWith(".html")) return "text/html";
else if (filename.endsWith(".css")) return "text/css";
else if (filename.endsWith(".js")) return "application/javascript";
else if (filename.endsWith(".ico")) return "image/x-icon";
return "text/plain";
}
bool handleFileRead(String path) {
Serial.println("handleFileRead: " + path);
if (path.endsWith("/"))
{
path += "index.html";
}
String contentType = getContentType(path);
if (SPIFFS.exists(path))
{
File file = SPIFFS.open(path, "r");
size_t sent = server.streamFile(file, contentType);
file.close();
return true;
}
Serial.println("\tFile Not Found");
return false;
}
Alternate Approach: Remove the JQuery dependency
An alternative approach is to rewrite the javascript so that JQuery is not required.
This involves registering an onclick handler on the button (https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers), getting the value from the input field (https://stackoverflow.com/a/11563667/1373856) and sending a GET request (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send)
You just has to include it as script-tag with the local path on your machine.
<script src="path-to-jquery/jquery.min.js" type="text/javascript"></script>
Edit: First you have to download the needed jquery file and store it in your local path. The needed path-to-jquery should than be a relative path from the html-file to the jquery.
The following code works fine with no error I am able to download file with the name as specified in code but the issue is there is no content printed to it and when I open the file I get error saying file is damaged. While I just save the file somewhere I get proper file with contents.
From UI:
var jsonStrToSend = JSON.stringify( jsonObjToSend );
jsonStrToSend = jsonStrToSend.replace(/"/g, """);
var url = '/'+appPath+'/reportgeneration' ;
var $form = $('<form enctype=\'application/json\' action="' + url + '" method="post">').append($('<input type="hidden" name="data" id="data" value="' + jsonStrToSend + '" />'));
$form.appendTo("body").submit();
In Controller:
#RequestMapping(value = "/reportgeneration", method = RequestMethod.POST)
public #ResponseBody void reportgeneration(HttpServletRequest request,
HttpServletResponse response){
Map returnMapMessage = new HashMap();
int resultData =0;
HttpSession httpsessionObj = request.getSession(false);
try{
PDDocument doc = new PDDocument();
PDPage intro_page = new PDPage();
doc.addPage( intro_page );
PDPageContentStream contentStream_itro =
new PDPageContentStream(doc, intro_page);
//Some stuff.......
String fileName = reportName+"_"+tempDate.getDate()+"-"+tempDate.getMonth()+"-"+tempDate.getYear()+" "+tempDate.getHours()+tempDate.getMinutes()+".pdf";
//doc.save("/test/webapp/reports/"+fileName);
response.setContentType("application/pdf");
PDStream ps=new PDStream(doc);
InputStream is=ps.createInputStream();
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", fileName);
response.setHeader("Expires:", "0"); // eliminates browser caching
response.setHeader(headerKey, headerValue);
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
is.close();
doc.close();
I was missing out doc.save() as I felt it not necessary as I was not storing file anywhere in the drive. But below code just works fine.
ByteArrayOutputStream output = new ByteArrayOutputStream();
doc.save(output);
doc.close();
response.addHeader("Content-Type", "application/force-download");
response.addHeader("Content-Disposition", "attachment; filename=\""+fileName+"\"");
response.getOutputStream().write(output.toByteArray());
I have an application which is basically a webview app. The website is based on angular js. Problem is the website takes a lot of time to start rendering. So I tried loading js from the asset folder. I used WebResourceResponse in my webviewclient
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if(url.startsWith("https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.min.js")){
return loadFromAssets(url, "angular.min.js", "application/javascript", "");
}
return null;
}
private WebResourceResponse loadFromAssets( String url,
String assetPath, String mimeType, String encoding){
AssetManager assetManager = this.activity.getAssets();
InputStream input = null;
try {
Log.d(LOG_TAG, "Loading from assets: " + assetPath);
input = assetManager.open("/" + assetPath);
WebResourceResponse response =
new WebResourceResponse(mimeType, encoding, input);
return response;
} catch (IOException e) {
Log.e("WEB-APP", "Error loading " + assetPath + " from assets: " +
e.getMessage(), e);
}
return null;
}
But I keep getting the filenotfound exception
07-26 17:19:21.662 20883-21536/com.exun.brinjal D/﹕ Loading from assets: angular.min.js
07-26 17:19:21.663 20883-21536/com.exun.brinjal E/WEB-APP﹕ Error loading angular.min.js from assets: /angular.min.js
java.io.FileNotFoundException: /angular.min.js
at android.content.res.AssetManager.openAsset(Native Method)
at android.content.res.AssetManager.open(AssetManager.java:335)
at android.content.res.AssetManager.open(AssetManager.java:309)
at com.exun.brinjal.HelloWebViewClient.loadFromAssets(HelloWebViewClient.java:85)
at com.exun.brinjal.HelloWebViewClient.shouldInterceptRequest(HelloWebViewClient.java:37)
at com.android.webview.chromium.WebViewContentsClientAdapter.shouldInterceptRequest(WebViewContentsClientAdapter.java:283)
at com.android.org.chromium.android_webview.AwContents$IoThreadClientImpl.shouldInterceptRequest(AwContents.java:244)
at dalvik.system.NativeStart.run(Native Method)
07-26 17:19:21.666 20883-21536/com.exun.brinjal D/﹕ Loading from assets: angular-route.min.js
07-26 17:19:21.669 20883-21536/com.exun.brinjal E/WEB-APP﹕ Error loading angular-route.min.js from assets: /angular-route.min.js
java.io.FileNotFoundException: /angular-route.min.js
at android.content.res.AssetManager.openAsset(Native Method)
at android.content.res.AssetManager.open(AssetManager.java:335)
at android.content.res.AssetManager.open(AssetManager.java:309)
at com.exun.brinjal.HelloWebViewClient.loadFromAssets(HelloWebViewClient.java:85)
at com.exun.brinjal.HelloWebViewClient.shouldInterceptRequest(HelloWebViewClient.java:40)
at com.android.webview.chromium.WebViewContentsClientAdapter.shouldInterceptRequest(WebViewContentsClientAdapter.java:283)
at com.android.org.chromium.android_webview.AwContents$IoThreadClientImpl.shouldInterceptRequest(AwContents.java:244)
at dalvik.system.NativeStart.run(Native Method)
I have tried to change assetManager.open("/" + assetPath); to file:/// and /assets but it doesn't help. All the js and css files I need are in the assets folder. I also want to know how will I get to load all those files also.
After some brainstorming, the answer was to remove "/" from assetManager.open("/" + assetPath);
So finally just put assetManager.open(assetPath); in the code and voila!
I am trying to load a page into webview. Normally, when i call
webview.loadUrl(url);
it works fine. The url has a javascript code that redirects the page. Here is the jacascript code:
<script type="text/javascript">
if (!document.cookie || document.cookie.indexOf('AVPDCAP=') == -1)
{ document.write('<scr'+'ipt src="http://some_link_here+Math.floor(89999999*Math.random()+10000000)+'&millis='+new Date().getTime()+'&referrer='+encodeURIComponent(document.location)+'" type="text/javascript"></scr'+'ipt>'); }
</script>
When i try to load that javascript code into my webview like the following:
String data = javascript_code_above;
topBannerWV.loadDataWithBaseURL("", data, "text/html", "UTF-8", null);
where data is this javascript code, it does not load the page. I also tried following:
topBannerWV.loadDataWithBaseURL("", data, "text/javascript", "UTF-8", null);
but this time that text is loaded into webview. Can anyone help me with this?
Thanks.
I am doing something like this and it works perfectly:
webView.loadUrl("file:///android_asset/html.html");
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
try {
webView.loadUrl("javascript:init('" + some parameter + "')");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
script in html file is:
<script type="text/javascript">
function init(val){
document.getElementById('content').innerHTML=val;
}
window.addEventListener('load',function(){
console.log("Window Loader");
init();
});
</script>
I found the solution.
Instead of directly giving the string to webview to load, i first wrote it into a file and then gave that file to webview to load.
getContext().getApplicationContext().deleteFile("data.html");
Writer output = null;
File dir = getContext().getApplicationContext().getFilesDir();
File file = new File(dir.getAbsolutePath() + File.separator + "data.html");
file.createNewFile();
output = new BufferedWriter(new FileWriter(file));
output.write(WVdata);
output.close();
topBannerWV.loadUrl("file:///" + getContext().getApplicationContext().getFilesDir() + "/data.html");
I do not know why this happens, actually i do not change the data string, just put it into a file.
What I'd like to do is
get the URI of a video file on the device via cordovas javascript API
set the URI as value of a HTML5 video tag's src attribute.
The second part shouldn’t be a problem.
Concerning the first task, there are a lot of good structured tutorials like Raymond Camden's demonstrating how to get local files through javascript in an cordova environment.
However, with the newest version of cordova, I could not get it to work.
The video file
The video is located either in assets/www/videos/testvid.webm or res/raw/testvid.webm in the built apk file. Both variations did not work.
The javascript
myPath = cordova.file.applicationDirectory; // -> file:///android_asset/
//myPath += "www/videos/testvid.webm";
respectively
myPath = cordova.file.applicationStorageDirectory; // -> file:///data/data/com.example.MyPackage/
//myPath += "raw/testvid.webm";
Then:
window.resolveLocalFileSystemURL(myPath, gotFile, fail);
function gotFile(entry){
if(entry.isDirectory)
alert JSON.stringify(entry.getFile("testvid.webm"));
}
The permissions
In res/xml/config.xml access permissions are added
<preference name="AndroidExtraFilesystems" value="files,files-external,documents,sdcard,cache,cache-external,root" />
The error is {code:1} -> NOT_FOUND_ERR
What am I doing wrong? How to navigate to the file, or where can one put it to be found?
I figured it out!
There is a bug in the android version of the cordova file plugin.
A workaround is transferring the file(s) from the assets directory of the app itself file:///android_asset/ (cordova.file.applicationDirectory) to a working directory on the phone like file:///data/data/com.example.MyPackage/files (cordova.file.dataDirectory). Then set the video's source URL to this new file.
XMLHttpRequest as well as FileTransfer will do the trick.
var myFilename = "testvid.webm";
var myUrl = cordova.file.applicationDirectory + "www/videos/" + myFilename;
var fileTransfer = new FileTransfer();
var filePath = cordova.file.dataDirectory + myFilename;
fileTransfer.download(encodeURI(myUrl), filePath, (function(entry) {
/*
res = "download complete:\n"
res += "fullPath: " + entry.fullPath + "\n"
res += "localURL: " + entry.localURL + "\n"
alert(res += "nativeURL: " + entry.nativeURL + "\n")
*/
var vid = document.getElementById("someID");
vid.src = entry.nativeURL;
vid.loop = true;
}), (function(error) {
alert("Video download error: source " + error.source);
alert("Video download error: target " + error.target);
}), true, {
headers: {
Authorization: "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
}
});