Android Webview HTML Loading Javascript Problem - javascript

I've been battling this problem for over 48 hours now and I have been unable to find an answer anywhere on the net. Here's the setup:
My Android application is downloading content during first run (content is over 20MB) and the files are unzipped onto the user's SD card at /mnt/sdcard/{my package}/folder. The content includes HTML files, CSS files, JS files and images. Here's the full structure of what is written to the SD card (where / = /mnt/sdcard/{my package}/folder/):
/content/
a.html
b.html
images/
image1.jpg
/css/
c.css
d.css
/js/
e.js
f.js
Here is my code that loads the html file from the SD card:
webView = (WebView) findViewById(R.id.pageBrowser);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new LinkHandlerInterface(), "Android");
webView.setWebViewClient(new PageWebViewClient());
// contentLocation + url is equal to the full path to the html file
webView.loadUrl("file://" + contentLocation + url);
This code successfully loads the HTML page. No problems yet. Each page has the following head tag:
<link rel="stylesheet" type="text/css" href="../css/screen.css" media="all" />
<link rel="stylesheet" type="text/css" href="../css/inPractice.css" media="all" />
<link rel="stylesheet" type="text/css" href="../css/inPracticeScheme.css" media="all" />
<link rel="stylesheet" type="text/css" href="../css/mobile/iPad.css" media="all" />
<script type="text/javascript" src="../js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="../js/inPractice-utilities.js"></script>
<script type="text/javascript" src="../js/inPractice.js"></script>
<script type="text/javascript" src="../js/mobile/inpractice.ipad.js"></script>
Here is where the problem is. My WebView renders the HTML just fine. It even loads and applies the CSS perfectly. However, it refuses to load and execute the Javascript. If you remember from above, the js folder is, in fact, one leve up from the html file, so it's pointing to the correct place.
Here's a list of what I know:
The CSS I'm using is being applied fine, so I know the issue is not with the file location.
I used this same code before, but was loading the files from my application's assets folder (file:///android_assets/...) and it worked perfectly. Since the content is so large, I can't bundle it with my application, hence the move to the SD card.
If I change the HTML files in such a way that all the Javascript methods are listed inside a script tag, it works fine. I don't have control over the HTML, so I can't apply this change permanently. This tells me that the WebView has no problem executing the Javascript.
Images load fine.
I'm fresh out of ideas now. Does anyone have any clue why my WebView cannot load my Javascript files? Has anyone seen this before?
EDIT: Here are the JS files I'm trying to use can be viewed here:
http://www.automatastudios.com/clients/cco/inpractice/css/inPractice.css
http://www.automatastudios.com/clients/cco/inpractice/css/inPracticeScheme.css
http://www.automatastudios.com/clients/cco/inpractice/css/screen.css
http://www.automatastudios.com/clients/cco/inpractice/css/mobile/iPad.css
NOTE: These CSS files were not authored by me.

Was never able to find a solution to this.
I ended up just editing the HTML files, such that changed the Javascript source files to inline Javascript. That worked (as I expected it would).

The preferred way to to load a html which references js, css is to use
webView.loadDataWithBaseURL()
We need to pass the root directory of the location where the html,js,css are found on the file system as the baseURL. Important thing to note here is that we need to use "file" scheme URL only.
In your case code should be
String html = readFileAsString(
new FileInputStream("file://" + contentLocation + url) );
webView.loadDataWithBaseURL("file://" + contentLocation,html,"text/html","utf-8",null);
public static StringBuffer streamToString(InputStream stream ){
StringBuffer fileContent = new StringBuffer("");
try {
int size = stream.available();
byte[] buffer = new byte[size];
int length;
while ((length = stream.read(buffer)) != -1) {
fileContent.append(new String(buffer));
}
stream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
stream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return fileContent;
}
Hope the answer helps future visitors
PS:
The above code snippet is not compiled

Related

Blazor WebAssembly load different scripts for specific Environment

I'm currently working on a .NET Standard 2.1 Blazor WebAssembly application. I try to include or exclude JavaScript files in my index.html according to an environment variable.
The Blazor WebAssembly App is NOT Asp.NET Core hosted.
In .NET Core there are usually Environment Tag Helpers like in the following example:
<environment include="Development">
<script src="js/app.js"></script>
<script src="js/helpers.js"></script>
</environment>
<environment exclude="Development">
<script src="js/site.min.js"></script>
</environment>
As already discussed in this question Blazor WebAssembly Environment Variables, the Environment Tag Helpers are server side code and thus don't work in Blazor WASm.
Now I try to find a good solution to include/exclude JavaScript files according to the Environment variable in Blazor WebAssembly.
The first idea was, similar like for CSS, to create a component called <Scripts> to load the different script files on the index.html like this:
#using Microsoft.AspNetCore.Components.WebAssembly.Hosting
#inject IWebAssemblyHostEnvironment hostEnv
#*Check the environment value*#
#if (hostEnv.IsDevelopment())
{
<script src="js/app.js"></script>
<script src="js/helpers.js"></script>
}
else
{
<script src="js/site.min.js"></script>
}
#code {}
Unfortunately this doesn't work, because the <script> Element is not allowed to be used in a Blazor component (.razor file).
The following error occurs: The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user. ... Script tags should not be placed inside components because they cannot be updated dynamically. To fix this, move the script tag to the 'index.html' file or another static location. ... https://go.microsoft.com/fwlink/?linkid=872131
How do you load different scripts according to the Environment Variable i.e. Development, Production or Staging in Blazor Webassembly?
Do you know how to solve this problem?
I wanted to add Tailwind CDN script tag just during development. I ended up using the solution below:
index.html
<script src="_framework/blazor.webassembly.js"></script>
<script>
// If localhost, add tailwind CDN (or any other script that you want)
if (window.location.hostname == 'localhost') {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'https://cdn.tailwindcss.com');
document.head.appendChild(customScript);
}
</script>
Simply copy your index.html code in a .cshtml (named BlazorApp.cshtml in the following sample) in your server project and fallback to this page.
public void Configure(IApplicationBuilder app)
{
...
app.UseEndpoints(endpoints =>
{
...
endpoints.MapFallbackToPage("/BlazorApp");
}
}
And update the code with <environment> tags for your conveniance.
Please check the solution in this answer (same question as you linked above) and that seems to work.
Basically the workaround is to use this in a new component called Head.razor as per the solution:
#inject IWebAssemblyHostEnvironment hostEnv
#if (hostEnv.IsDevelopment())
{
<title>BlazorWasmApp - In Debug</title>
<link href="css/debug.css" rel="stylesheet" />
}
else
{
<title>BlazorWasmApp - Not Debug</title>
<link href="css/live.css" rel="stylesheet" />
}
New Head.razor component:
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
//Add the Head to root components
builder.RootComponents.Add<Head>("head");
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}

Oracle Outside In Web View Export JavaScript API loading problem

I've converted a sample PDF file to HTML5 using Oracle's OutSide In Web View Export using the AjaxChunked method, but I cannot get the file to render correctly using the supplied JavaScript API. The file is rendered correctly is browsed to directly.
For example, the incorrect rendering through the JavaScript API:
And how the file looks if browsed to directly:
The source code for the correct rendering is this:
And here is the index.html I've written using the Web View Export JavaScript API:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--<link rel="stylesheet" type="text/css" href="oit.css">-->
<script src="oit.js"></script>
<title>Oracle Web View Export Test</title>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
$(document).ready(function(){
console.log("Document ready");
var viewContainer = document.getElementById("container");
OIT.view.attach(viewContainer);
OIT.view.load("adobe-acrobat.html");
});
OIT.document.addEventListener("load", function (evt) {
console.log("Just loaded: " + evt.detail.url);
});
And here is the code that converts the document (C#):
try
{
OutsideIn.OutsideIn.InstallLocation = new DirectoryInfo(Environment.CurrentDirectory + "\\Resources");
}
catch (Exception uhoh)
{
Console.WriteLine(uhoh.Message);
}
Exporter exporter = OutsideIn.OutsideIn.NewLocalExporter();
try
{
exporter.SetPerformExtendedFI(false);
exporter.SetFontReferenceMethod(Options.FontReferenceMethodValue.ReferenceExported);
/* The FONTDIRECTORY option must be set. */
List<DirectoryInfo> FontDirectories = new List<DirectoryInfo>();
DirectoryInfo SystemFontsDirectory = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
FontDirectories.Add(SystemFontsDirectory);
exporter.SetFontDirectories(FontDirectories);
exporter.SetWebViewStructure(Options.WebViewStructureValue.AjaxStreamed);
//exporter.SetPerformExtendedFI(true);
exporter.SetSourceFile(file);
exporter.SetDestinationFile(newoutputPath + "\\" + Path.GetFileNameWithoutExtension(file) + ".html");
exporter.SetDestinationFormat(FileFormat.FI_HTML5);
}
catch (Exception fail)
{
Console.WriteLine("Fail: " + fail.Message);
Console.ReadLine();
}
Console.WriteLine("Exporting: " + file);
exporter.Export();
I've looked high and low for some idea on what is causing the problem, but I can't seem to find anything. The documentation provided by Oracle isn't great, so I'm at a loss. There is a post on the Oracle support forums from over two years ago with this exact problem, but no solution is provided.
Any ideas or suggestions would be greatly appreciated.
Just in case someone stumbles across this and is having the same issue, it turns out that for whatever reason, the OIT.view.load() method doesn't correctly load the CSS for the page (oit.css), so you have to manually put that into the HTML file you're calling the view.load() from.
In addition to this, the top level DIV created for the document has a height of zero. No idea why, so we fixed this using OIT.view.height(document.height), or alternatively whatever height you want it to be. This seems to have solved the problems, and the document is displayed correctly in the browser.

HTML is not reading external Javascript file

I am trying to write a very simple HTML page that displays a message generated by a JS file. I am somewhat new to HTML / JS and I am certain there is something pretty simple I am missing, but I cannot for the life of me get the page to read the script. When I load the page, it is completely BLANK without any errors in the inspector.
This is the project folder structure:
-Project (folder)
--templates (folder)
----home.html
--src (folder)
----home.js
--styles (folder)
----home.css
Also, I'm pretty sure that my HTML page SEES the script, because when I remove or rename the script, I get an error in the browser's inspector telling me that it cannot find the script. So it SEES the script, it just is not running it for some reason.
Here is the code...
home.html:
<html>
<head>
<link rel="stylesheet" type="text/css" href="../styles/home.css"></link>
<script type="type/javascript" src="../src/home.js"></script>
</head>
<body>
<div id="bodytext"></div>
</body>
</html>
home.js:
(function() {
console.log("I AM READING THE SCRIPT");
document.getElementById('bodytext').innerHTML = "I AM READING THE SCRIPT";
})();
Could some generous soul out there please clue me in to what extremely simple mistake I'm making?
Thank You!
Value for type attribute should be text/javascript as follows:
<script type="text/javascript" src="../src/home.js"></script>
Your script is running before the DOM is completely done loading. If you put your <script> tag right before your closing body tag (</body>), it will run after the DOM is loaded, and you will be able to traverse the DOM like normal.
Value for type attribute should be text/javascript as follows
enter code here
ALong with this you will have to change your java script code as follows, so that script gets executed only when page is completely loaded & document object is availabe.
window.onload = function() {
console.log("I AM READING THE SCRIPT");
document.getElementById('bodytext').innerHTML = "I AM READING THE SCRIPT";
};
What worked for me was adding charset="utf-8" to my css link as well as my javascript script (for me, both did not work). Example:
<link rel="stylesheet" type="text/css" href="css/main.css" charset="utf-8"></link>
<script src="javascript/script.js" charset="utf-8"></script>

Load HTML in WebView with local css and js

I am displaying a webview with a remote html content get as a string from a remote server.
I store the html locally for a no connection use of my application.
Moreover I also store a .js script and a .css style file locally. These files can be updated by the server.
I store all these files at the following paths :
context.getFilesDir()+"content.css"
context.getFilesDir()+"content.js"
In the html string, css and js are referenced like this :
<link rel="stylesheet" href="/content.css" type="text/css" media="screen">
<script src="/content.js"></script>
I load the html using
this.webView.loadDataWithBaseURL(getFilesDir().getAbsolutePath(), html, "text/html", "utf-8", "about:blank");
But the style and the js are not taken into account, so I think something is wrong with the path I use to reference them, or to load the webView. So what is the way to do this ? I found many answers that use the "assets" folder but I do not want to use it since I have to update the css and the js from the server.
Finally I have found the solution :
The css (or js) file is saved in local using this method :
public static void writeToFile(Context context, String content, String title) throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(context.openFileOutput(title,Context.MODE_WORLD_READABLE));
osw.write(content);
osw.close();
}
Then I refer it in the html file using
<link rel="stylesheet" href="content.css" type="text/css" media="screen">
<script src="content.js"></script>
And finally I have opened the webview using :
this.webView = (WebView) findViewById(R.id.webview);
this.webView.getSettings().setJavaScriptEnabled(true);
this.webView.getSettings().setPluginsEnabled(true);
this.webView.setHorizontalScrollBarEnabled(false);
this.webView.setVerticalScrollBarEnabled(true);
this.webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
this.webView.setWebViewClient(this.controller.getWebViewClient());
String basePath = "file://"+getFilesDir().getAbsolutePath()+"/";
this.webView.loadDataWithBaseURL(basePath, data, "text/html", "utf-8", "about:blank");

QWebView doesn't load any external resources if it loads a html-file from qresources

As described in the title my problem is that qwebview doesn't load a html file correctly if it resides in my resources. It loads it perfectly if I load it from outside of the resources as normal local file. But this is not an option for me. I would like to bundle the file with the application.
EDIT: By the way, I'm talkin' about external resources from the web. (e.g. http://host.org/somejavascript.js)
Thanks for any help
Please take a look at the second parameter of
void QWebView::setHtml ( const QString & html, const QUrl & baseUrl = QUrl() )
According to documentation:
External objects such as stylesheets
or images referenced in the HTML
document are located relative to
baseUrl.
Below is code that works for me.
#include <QtCore/QFile>
#include <QtCore/QUrl>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QtWebKit/QWebView>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
QWebView webview(&window);
QFile source(":/google.com.html");
source.open(QIODevice::ReadOnly);
webview.setHtml(QString::fromUtf8(source.readAll().constData()), QUrl("http://google.com"));
window.setCentralWidget(&webview);
window.show();
return app.exec();
}
External URLs must have a schema to make them external, otherwise "external.org/script.js" looks for "script.js" under the "external.org/" sub-path, "http://external.org/script.js" is an absolute URL.
Edit:
Say you have this HTML file as the resource ":/file.html" and it is coppied from "http://example.com/":
<html>
<head>
<title>My HTML</title>
<script type="text/javascript" src="/code.js"></scipt>
</head>
<body>
<img href="/image.jpg" />
</body>
</html>
Then to display this correctly you would need to do the following:
QFile res(":/file.html");
res.open(QIODevice::ReadOnly|QIODevice::Text);
my_webview.setHtml(res.readAll(), QUrl("http://example.com/");
That way, WebKit knows where to fetch "code.js" and "image.jpg" from. Using QWebView::load() will not work, as the root URL will be some internal URL, the one starting with qrc://, and WebKit will look for "code.js" and "image.jpg" in your applications resources. Basically, you can only use load() when all the relative URLs in the document come from the same place as the URL is pointing to. And if you used load(QUrl("qrc:///file.html")); in the case above, the URL (qrc:///file.html) is pointing to your resource system.
If you want to also include your resources in the HTML, you can use the qrc:// URLs in the HTML file.

Categories

Resources