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>.
Related
I have an html file in asset folder and i would like to load it in a webview. I would like to use the string, and not the file in order to replace the content of file when i want (keep only one file and change the content i want to display).
For example my html file is like this:
<!DOCTYPE html>
<html>
<head>
<title>This is demo</title>
</head>
<body>
<p data-height="265" data-theme-id="0" data-slug-hash="dYPxYp" data-default-tab="html,result" data-user="sckarolos" data-embed-version="2" data-pen-title="SVG Shape Example" class="codepen">
See the Pen SVG Shape Example
by sckarolos (#sckarolos) on CodePen.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
</body>
</html>
I have these two methods for reading the html file from assets as string and load it in a webview:
private String getHtmlFromAsset() {
InputStream is;
StringBuilder builder = new StringBuilder();
String htmlString = null;
try {
is = getAssets().open(htmlFilename);
if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
htmlString = builder.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return htmlString;
}
/**
* Loads html page with the content.
*/
private void loadHtmlPage(WebView webView) {
String htmlString = getHtmlFromAsset();
if (htmlString != null) {
webView.loadDataWithBaseURL(null, htmlString, "text/html", "UTF-8", null);
}
else
Toast.makeText(this, "No such page", Toast.LENGTH_LONG).show();
}
And in my activity i use webview like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
AssetManager assetManager = getAssets();
//try to display html content
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowContentAccess(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
loadHtmlPage(webView);
}
On debuging i can see that my file read successfully and my string has the content of html file. But when i am trying load it in webview, the result is nothing. If i try to load the local html file using this:
webView.loadUrl("file:///android_asset/myFile.html");
then the file loads and displays successfully.
I suppose that my fault is in the way i use the string that i take back from getHtmlFromAsset and pass in loadHtmlPage.
Any help will be appreciated.
Here, code pan required javascript access so when link load you need to provide javascript access. this is working code also check into my emulator. Also, don't forget to give internet permission on the manifest.
XML:
<WebView
android:id="#+id/wv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
JAVA:
String str = "<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <title>This is demo</title>\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"<p data-height=\"265\" data-theme-id=\"0\" data-slug-hash=\"dYPxYp\" data-default-tab=\"html,result\" data-user=\"sckarolos\" data-embed-version=\"2\" data-pen-title=\"SVG Shape Example\" class=\"codepen\">\n" +
" See the Pen SVG Shape Example\n" +
" by sckarolos (#sckarolos) on CodePen.</p>\n" +
"<script async src=\"https://production-assets.codepen.io/assets/embed/ei.js\"></script>\n" +
"\n" +
"\n" +
"</body>\n" +
"</html>";
WebView wv = findViewById(R.id.wv);
wv.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url){
// do your handling codes here, which url is the requested url
view.getSettings().setJavaScriptEnabled(true);
view.loadUrl(url);
return false; // then it is not handled by default action
}
});
wv.loadData(str, "text/html", "UTF-8");
I am trying to get my app to sync itself with a website, and display only the table of a website. Example: Normal HTML framework, and the table is inside a div#table, so I did it pretty simple and built the HTML Framework:
String html = "<html> " +
"<head>" +
"</head>" +
"<body style=\"background-color: transparent\">" +
"?body" +
"</body>" +
"</html>";
And then I tried to replace the ?body with the table, but here's my problem: I have no clue how to do that and then load it into a transparent WebView. I found a little bit code online, and tried to get it working for my case, so here's that:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<String> links = new ArrayList();
setContentView(SliderCreator.createSlider(R.layout.activity_news, this));
wv = (WebView) findViewById(R.id.newsWebView);
wv.setBackgroundColor(Color.TRANSPARENT);
try {
String finalHTML = getIntent().getStringExtra("html");
if (!finalHTML.contains("<html>")) {
String css = "";
for(String link : links) {
css+=Utils.getHTML(link);
}
finalHTML = html.replace("?body", getIntent().getStringExtra("html")).replace("?css", css);
}
wv.getSettings().setJavaScriptEnabled(true);
//open URLs in external Browser
wv.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
});
wv.loadDataWithBaseURL("", finalHTML, "text/html", "UTF-8", "");
} catch(Exception e) {
Toast.makeText(this, "An error occured...", Toast.LENGTH_LONG).show();
}
But that doesn't work.. Can somebody help me out get that working for me?
(Btw.: I tried it with RegEx, didn't work, I tried it with JSoup, didn't work either...)
try using HTML Agility Pack if not working with RegEx
Please note, your RegEx might not work the desired way if the text contains nested table tags
I'm developing an Android application in which I have used an HTML file for help contents. I have used a WebView to display the content and every thing is fine.
The problem is that user can change the theme and font size of the application. How can I propagate these properties to the content of WebView? Exactly how can I change the font size and text color in WebView? Is there a simple way to do that or I should create different HTMLfiles or CSSes? How to handle the size units (dp, sp, ...)?
I will appreciate your help with this situation.
loadUrl("javascript:(document.body.style.backgroundColor ='red');");
loadUrl("javascript:(document.body.style.fontSize ='20pt');");loadUrl("javascript:(document.body.style.color ='yellow');");
On your android application, use following code to load a web page with user chosen font size and color:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebChromeClient(new InredisChromeClient(this));
myWebView.setWebViewClient(new InredisWebViewClient(this));
myWebView.clearCache(true);
myWebView.clearHistory();
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.loadUrl("http://demo.com/content.html?font-size=12&fontcolor=blue");
On the content.html page, enable JavaScript and use jQuery and its function as below:
function getCssValue(sCSS)
{
var sPageURL = window.location.search.substring(1);
var sValues = sPageURL.split('&');
for (var i = 0; i < sValues.length; i++)
{
var sPair = sValues[i].split('=');
if (sPair[0] == sCSS)
{
return sPair[1];
}
}
}
$(document).ready(function(){
// Set the Font Size from URL
$('html').css('font-size', getCssValue('font-size'));
});
It is best to do theme activities using CSS and Javascript. However if we want to pass on some settings from Android to the WebView dynamically, it is possible and a solution is to use the JavascriptInterface. Here is one way of doing it:
Firstly, we define a class which will be used as a bridge between the Android app and the WebView for JS interactions.
Here WebInterface is an inner class in the Activity and hence it has direct access to myWebView, which is a WebView instance variable.
public class WebInterface {
private Activity activity;
public WebInterface(Activity activiy) {
this.activity = activiy;
}
#JavascriptInterface
public void changeTheme() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// All of the theme settings could go here, the settings passed on by Android
myWebView.loadUrl("javascript:document.body.style.backgroundColor ='red';");
myWebView.loadUrl("javascript:document.body.style.fontSize ='20pt'");
myWebView.loadUrl("javascript:document.body.style.color ='yellow';");
//OR load your data as shown here http://stackoverflow.com/a/7736654/891092
htmlData = "<link rel=\"stylesheet\" type=\"text/css\" href=\"theme.css\" />" + htmlData;
// lets assume we have /assets/theme.css file
myWebView.loadDataWithBaseURL("file:///android_asset/", htmlData, "text/html", "UTF-8", null);
}
});
}
}
Note that it is very important to run your code in UI Thread otherwise it will not work.
Here is how the Activity registers the WebView with the JavascriptInterface:
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(jsInterface, "JSInterface");
In the HTML file, which the user is viewing, a button or widget could be made to change theme by calling code in Android through the bridge:
<input type="button" value="Say hello" onClick="doChangeTest()" />
<script type="text/javascript">
function doChangeTest(){
JSInterface.changeTheme(); // this calls the changeTheme in WebInterface
}
</script>
First you need to define a webView and after that use below method.
lightFont is your font that you should store in asset folder.
color is your text color.
font size : you can change font size.(for example 20px or medium and etc).
at the end you need to use seconde method to show html on webView
First Method:
public static String getStyledFont(String html) {
boolean addBodyStart = !html.toLowerCase().contains("<body>");
boolean addBodyEnd = !html.toLowerCase().contains("</body");
return "<style type=\"text/css\">" +
"#font-face {font-family: CustomFont;" +
"src: url(\"file:///android_asset/lightFont.ttf\")}" +
"body {color: #787878;}"+
"body {font-family: CustomFont;font-size: x-small;}</style>" +
(addBodyStart ? "<body>" : "") + html +(addBodyEnd ? "</body>" : "");
}
Second method:
String htmlText = getStyledFont(yourText);
webView.loadDataWithBaseURL("file:///android_asset/",
htmlText ,
"text/html; charset=UTF-8", null, null);
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);
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" />