JQuery doesn't work on WebView - android

I tried to include JQuery files in assets/scripts and on Internet, but the alert dialog doesn't show. I got the log output and make it output.html, it works in Windows (so strange!).
What's the problem with WebView?
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView) findViewById(R.id.webView);
final String s = "<html><head>" +
"<link href=\"css/my.css\" type=\"text/css\" rel=\"stylesheet\" />" +
"<script src=\"scripts/jquery-1.6.2.min.js\" rel=\"stylesheet\" type=\"text/javascript\"></script>" +
"<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js\" type=\"text/javascript\"></script>" +
"<script>" +
"$(document).ready(function(){ alert('hello'); });" +
"</script>" +
"</head><body><div>All I hear is raindrops." +
"Falling on the rooftop. Oh baby tell me why you have to go. " +
"Cause this pain I feel you won't go away. And today, " +
"I'm officially missing you.</div></body></html>";
webView.getSettings().setJavaScriptEnabled(true);
Log.d("Something", s);
webView.loadDataWithBaseURL("file:///android_asset/", s, "text/html", "utf-8", null);
}
This is the log output after adding extension ".html". It works on Firefox but does not on WebView. :(
<html>
<head>
<link href="css/my.css" type="text/css" rel="stylesheet" />
<script src="scripts/jquery-1.6.2.min.js" rel="stylesheet" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js" type="text/javascript"></script>
<script>$(document).ready(function(){ alert('hello'); });</script>
</head>
<body>
<div>
All I hear is raindrops.Falling on the rooftop. Oh baby tell me why you have to go. Cause this pain I feel you won't go away. And today, I'm officially missing you.
</div>
</body>
</html>

webView.loadDataWithBaseURL("file:///android_asset/", s, "text/html", "utf-8", null);
be change to
webView.loadDataWithBaseURL(getAssets(), s, "text/html", "utf-8", null);
to get asset file, you will need to access app's asset path. An app is an user on Android, so cannot access path begin with "file://" directory.

You will need to have the jquery.js file in your assets/scripts folder for this to work.
scripts/jquery-1.6.2.min.js
That should work.

As already mentioned on Android WebView doesn't load jQuery:
Where is your scripts/jquery-1.6.2.min.js script located? If it is located in your assets directory, then you should initialize the webView giving it the assets directory as baseUrl:
webView.loadDataWithBaseURL("file:///android_asset/", data, "text/html", "UTF-8", null);
or
webView.loadUrl("file:///android_asset/file.html");
You could try to create a simple .js file with a simple function like
function dummy(document) { document.write("Hooray it works"); }
and try to access the dummy function in your html to test if the .js file is included.

setPluginsEnabled in WebView settings to true.

I Guess, some javascript functions like prompt and alert (System popups), should be implemented by your code.
A simple guide..,
1. Create a class Jscalls.java
public class Jscalls {
Context mContext;
Jscalls(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public void alert(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
2. In your program add, webView.addJavascriptInterface(new Jscalls(this), "Android");
3. In html pages, instead of alert("hello"), use Android.alert("hello")
Hope it works :)

You should give full path to load javascript and css for example
<link href="http://yourdomain.com/css/my.css" type="text/css" rel="stylesheet" />

Related

Is it possible to add custom CSS to a WebView in Xamarin using ONLY ONE stylesheet in my Assets folder?

I've seen multiple tutorials adding a GetBaseUrl separately for IOS and Android, but they don't answer my question. I was wondering if there is no other way to add custom CSS to a webview and only use 1 stylesheet (default.css). The reason why I want to do this is because my stylesheet is identical for both IOS and Android and contains little styling.
This is what I've tried:
I have a WebView:
<WebView.Source >
<HtmlWebViewSource Html="{Binding Data.Content}" />
</WebView.Source>
The Source of this WebView is a string that looks like this:
string contentString = #"<html>
<head>" +
"<link rel='stylesheet' href='default.css'"
"</head>" +
"<body style='text-align:left;background-color:white;font-size:16px;margin:0;'>" +
value +
"</body>" +
"</html>";
The default.css file mentioned above is in my Assets folder and has Build Action EmbeddedResource, located in the root directory of my project:
Can anyone help? Thanks in advance.
There are some ways to do this, one is to use HtmlWebViewSource, the html is like this:
htmlSource.Html = #"<html>
<head>
<link rel=""stylesheet"" href=""default.css"">
</head>
<body>
<h1>Xamarin.Forms</h1>
<p>The CSS and image are loaded from local files!</p>
<img src='XamarinLogo.png'/>
<p>next page</p>
</body>
</html>";
Another way is to use WebView.loadDataWithBaseURL, there is the same thread that you can take a look:
Rendering HTML in a WebView with custom CSS
The easiest way is to wrap your HTML with CSS (or replace link tags with its resulting content)
var html = AddHtmlAndCssTags("<div>my html</div>", ReadCss());
protected string ReadCss()
{
var resourceName = $"MyProj.Resources.Css.article.css";
var isExists = ResourceLoader.IsEmbeddedResourceExists(Assembly.GetAssembly(typeof(ResourceLoader)), resourceName);
if (isExists)
{
return ResourceLoader.GetEmbeddedResourceString(Assembly.GetAssembly(typeof(ResourceLoader)), resourceName);
}
return string.Empty;
}
protected string AddHtmlAndCssTags(string html, string css)
{
var cssTag = string.IsNullOrEmpty(css) ? string.Empty : $"<style>{css}</style>";
return $"<html><head>{cssTag}</head><body>{html}<body></html>";
}

Load CSS JS from Assets folder

I've been searching for hours for a solution; and although there are similar situations, mine I think is a bit different.
I have a website that I'm loading into webview
setContentView(R.layout.activity_main);
WebView myWebView = (WebView) findViewById(webview);
myWebView.loadUrl("http://my-website.com/index.php");
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.toString());
return true;
}
}); }
It's loading the website fine. No issues. What I'm trying to do (because there are alot of CSS & JS files) is load these files from the assets folder of the Android App - I'm trying to make the page load faster.
<link href="file:///android_asset/css/keyframes.css" rel="stylesheet" type="text/css">
<link href="file:///android_asset/css/materialize.min.css" rel="stylesheet" type="text/css">
<link href="file:///android_asset/css/swiper.css" rel="stylesheet" type="text/css">
<link href="file:///android_asset/css/swipebox.min.css" rel="stylesheet" type="text/css">
<link href="file:///android_asset/css/style.css" rel="stylesheet" type="text/css">
It is currently not loading any of my CSS files which are called this way.
I really don't mean to pester anybody with a simple problem, It's just been bothering me and I'm not good with Java.
Also, this is NOT a local HTML page. This is a PHP page loaded from a remote server.
I am not a mobile developer, but I am a web developer that did write some webview pages for my mobile developer colleagues.
As far as I know, you are not able to access file system in webview. However, you can let your app cache the css / js files.
viewer.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT)
(This is from an answer here on stackoverflow) (and here is the document on cache settings)
By using the default cache settings, the CSS / JS files will be cached after downloaded in the first time, as it was cached in normal browser. So you can simply use
<link href="https://your.domain/css/style.css" rel="stylesheet" type="text/css">
to achieve the faster page load you want.
If you want to load css and js from local asset folder then first you need to download your webpage and then after you need to pass in web browser like following way,
Download Data Like using this :
public String getHtmlContent(String urlToLoad) {
String outputStr = "";
BufferedReader inputString = null;
try {
URL urlLoad = new URL(urlToLoad);
inputString = new BufferedReader(new InputStreamReader(urlLoad.openStream()));
String str;
while ((str = inputString.readLine()) != null) {
outputStr += str;
}
} catch (MalformedURLException e) {
} catch (IOException e) {
} finally {
if (inputString != null) {
try {
inputString.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return outputStr;
}
Then after you need to put your js and css file inside of asset folder and then need to define a url in web page like following
<script src="file:///android_asset/jquery.min.js" type="text/javascript"></script>
You need set all the url using like file:///android_asset/ then after your css or js name,
After all thing finish you need to set your webpage content with webview like following
String webData = getHtmlContent("http://webisteaddress.com/index.html");
mWebView.loadDataWithBaseURL("file:///android_asset/", webData, "text/html", "utf-8", "");
Use this function to load CSS & JavaScript inside your WebView:
inject both CSS & JavaScript inside onCreate() on WebViewClient:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url)
{
injectJavaScript(view);
injectCSS();
}
Create two methods to inject JavaScript & CSS(from res/raw):
private boolean injectJavaScript(WebView view){
view.loadUrl("javascript:(function() { " +
"var head = document.getElementsByTagName('header')[0];"
+ "head.parentNode.removeChild(head);" + "console.log('true');"+
"})()");
view.loadUrl("javascript:(function() { " +
"var footer = document.getElementsByTagName('footer')[0];"
+ "footer.parentNode.removeChild(footer);" +
"})()");
view.loadUrl("javascript:(function() { " +
"var nav = document.getElementsByTagName('nav')[0];"
+ "nav.parentNode.removeChild(nav);" +
"})()");
view.loadUrl("javascript:(function() { " +
"var set = document.getElementsByClassName('banner');"
+ "set[0].style.margin = '0px';" +
"})()");
return true;
}
private void injectCSS() {
try {
InputStream inputStream = getResources().openRawResource(R.raw.css);
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
inputStream.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
wv1.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var style = document.createElement('style');" +
"style.type = 'text/css';" +
"style.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(style)" +
"})()");
} catch (Exception e) {
e.printStackTrace();
}
}
This worked for me like a charm.
Loading CSS using <link rel="stylesheet" href=""/> is going to be deprecated in March 2018. I just got a warning message for this in Developer Console today.
This is because nothing renders on the page till all the CSS has loaded.
So instead, the suggestion is that we load the CSS using JavaScript, and have a small inline stylesheet to render the basic look of the page; plus separate stylesheets for each section of the page, which are called from the <body> rather than the <head>.

Android Webview cannot load CSS and show blockquote font color effect

I have got the following html to be loaded on CSS through android webview . When it comes to the execution. there has no obseravle changes to the font color changes onto my wordings tagged by blockquote
the below is my html code :
<html>
<head>
<title>Example</title>
<link rel="stylesheet" type="text/css" href="file:///android_asset/style.css" />
</head>
<blockquote>拜年根本係學溝通同交際#hehe#</blockquote>
<br/><br/>唔明點解去完親戚屋企拜年 過幾日親戚要黎返我屋企再拜過年 [banghead]
</body>
</html>
CSS:
#CHARSET "UTF-8";
blockquote{
color:#d4d3d3
}
Actual android code
viewHolder.txContent = (WebView) v.findViewById(R.id.replycontent);
WebSettings settings = viewHolder.txContent.getSettings();
settings.setDefaultTextEncodingName("utf-8");
settings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
viewHolder.txContent.setFocusable(false);
viewHolder.txContent.setClickable(true);
viewHolder.txContent.setBackgroundColor(Color.parseColor("#00FFFFFF"));
String htmlPreffix = "<html><head><title>Example</title><link rel=\"stylesheet\" type=\"text/css\" href=\"file:///android_asset/style.css\" /></head>";
String htmlSuffixString = "</body></html>";
System.out.println("htmlParsed");
System.out.println(htmlPreffix + htmlParsed + htmlSuffixString);
viewHolder.txContent.loadDataWithBaseURL(null, htmlParsed, "text/html", "utf-8", null);
You're missing the opening <body> tag.

Changing HTML in a WebView programmatically

I'm loading an html asset page into a WebView using
webMain.loadUrl("file:///android_asset/record.html");
which works fine, but inside the html are a number of places where I'd like to use information from the app. For instance, the HTML may contain text that reads "[Custom]". Is there a way I can replace that word with information passed from the application?
This is an old and already accepted question, however I am sure that the problem can be solved in more elegant way by using javascript.
Keep the html file in your assets folder and surround the text which you want to replace into with div elements with unique id's.
<html>
<head> ... <head>
<body>
Static text
<div id="replace1">replace me</div>
<div id="replace2">replace me too</div>
More static text ...
</body>
</html>
Now create a javascript function which will replace the innerHtml of a div with an id:
function replace(id, newContent)
{
document.getElementById(id).innerHTML = newContent;
}
This function will be best placed directly in the html file, update the <head> section to look like this:
<head>
...
<script type="text/javascript">
function replace(id, newContent)
{
document.getElementById(id).innerHTML = newContent;
}
</script>
</head>
Now we need to call the javascript function from from the WebView Android api:
WebView helpView = (WebView)findViewById(R.id.helpView);
helpView.getSettings().setJavaScriptEnabled(true);
helpView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl("javascript:replace('replace1', 'new content 1')");
view.loadUrl("javascript:replace('replace2', 'new content 2')");
}
});
helpView.loadUrl("file:///android_asset/help.html");
Using this you will avoid reading potentially large data into memory and running expensive operations on it unnecessarily.
This is worked for me.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Payment Demo</title>
</head>
<body>
<div>
<input type="text" id="uname " name="uname " value="">
<input type="text" id="pass" name="pass" value="">
</div>
</body>
</html>
This is java code.
WebView wb = (WebView) findViewById(R.id.webView1);
wb.loadUrl("file:///android_asset/web1.html");
wb.getSettings().setJavaScriptEnabled(true);
wb.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView web, String url) {
// TODO Auto-generated method stub
String uname = "email#mail.com";
String pass = "******";
web.loadUrl("javascript:(function(){document.getElementById('uname').value = '"+uname+"';})()");
web.loadUrl("javascript:(function(){document.getElementById('pass').value = '"+pass+"';})()");
}
});
Actually I do not understand why the file size of record.html will affect maintainence of the code. Read the html string (using Java reader class or what ever) from the html file in asset, use replaceAll function with Regex to replace all the [Custom] in the html file. How long the html is should not really affect how you maintain the code. It should rather be a performance problem, or the string is really really long that exceeds the java String limit.
some code I have used before :
InputStream is = getApplicationContext().getAssets().open("details/product_jsmodify.html");
Reader r = new InputStreamReader(is);
String details = Utils.readertoString(r);
details = details.replace("%product_name%",productName );
Utils is my class doing the conversion to string. I am not using Regex here as I am only replacing word for once. Then I load the string like Cata does. It is quite clean I suppose.
Yes you can do that by loading your page in a String and then load that string in your WebView.
Eg:
String summary = "<html><body>You scored <b>192</b> points.</body></html>";
webview.loadData(summary, "text/html", null);
Taken from here
This one worked for me, with the html along with the text and images.
InputStream is = getAssets().open(html_name);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String str = new String(buffer);
str = str.replace("InitialTextToBeReplaced", "TextAfterReplacement");
//Now instead of webview.loadURL(""), I needed to do something like -
webView.loadDataWithBaseURL("file:///android_asset/", str, "text/html", "UTF-8",null);

Android 4.0.1 breaks WebView HTML 5 local storage?

I have a simple html5 test page which uses LocalStorage to display / save / redisplay a piece of data.
This code works perfectly in Android 2.3.x but logs an exception in 4.0.1 on line 18 of the html which is the frist localStorage.getItem() call and at this point the JS stops.
Exception: Uncaught Error: SECURITY_ERR: DOM Exception 18 at /data/data/my.app.name/app_htmlData:18
I've also tried setting the database path to getCacheDir() with the same result.
String htmlContent = "HTML content listed below";
File sharedDir = getActivity().getDir("htmlData", Context.MODE_PRIVATE);
WebView browser = (WebView)v.findViewById(R.id.wvBrowser);
browser.setWebChromeClient(new WebChromeClient(){
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(estimatedSize * 2);
}
});
browser.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url){
view.loadUrl("javascript:doTest()");
});
browser.getSettings().setDatabaseEnabled(true);
browser.getSettings().setDatabasePath(sharedDir.getPath());
browser.getSettings().setDomStorageEnabled(true);
browser.loadDataWithBaseURL(mSharedDir.getPath(),
htmlContent,
"text/html",
"utf-8",
null);
The HTML that the page is rendering is as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Simple localStorage test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
function doTest() {
$('#stuff').append('<p>reading</p>');
var item = read();
$('#stuff').append('<p>writing</p>');
localStorage['bar'] = new Date().toUTCString();
$('#stuff').append('<p> </p><p>reading again</p>');
read();
}
function read() {
var item = localStorage.getItem('bar');
if (item == null || (item == undefined)) {
item = '';
}
$('#stuff').append('<p> item: ' + item + '</p>');
return item;
}
</script>
</head>
<body>
<p>-Simple localStorage test-</p>
<div id="stuff"></div>
</body>
</html>
Source available here
Via some discussion with a Google engineer it seems that they've made the decision that the file:// scheme is insecure.
A work around for this is to do the following
browser.loadDataWithBaseURL("http://www.example.com",
htmlContent,
"text/html",
"utf-8",
null);
For android versions less than 4.4, loading data into a webview with a file scheme as a directory:
browser.loadDataWithBaseUrl("file:///android_asset/", html, "text/html", "UTF-8", null);
wont work with localStorage. If I add a filename it does work on older OS versions
browser.loadDataWithBaseUrl("file:///android_asset/test.html", html, "text/html", "UTF-8", null);

Categories

Resources