How can i load resources dynamically from an android webview using onLoadResource() callback from a webviewClient?
Below is the code i have written so far. when i get new resources, it loads for example, the whole page of one single imagine instead of updating and displaying the image on the same original url of the webpage.
If a webpage has 5 images and text, my current code will load 5 pages each time onLoadResource tries to load an image.
what i want it to do is to load the images in the same page and any other resources as well such as JS, jquery's etc.
#Override
public void onLoadResource(WebView view, String url) {
addRequestToProxy(url);
}
public void addRequestToProxy(String url){
//pass url to proxy and wait for respoonse
String response;
//handle response
if(mime-type == IMAGE){
String urlStr = "http://example.com/my.jpg";
String pageData = "<img src=\"data:" + contentResponse.getMimeType()
+ ";base64," + contentResponse.getContent() + "\" />";
mWebView.loadDataWithBaseURL(urlStr, pageData, "text/html", null,
urlStr);
}else{
mWebView.loadDataWithBaseURL(null, response, "text/html", null,
null);
}
Instead of overriding onLoadResource() it's better to do it this way - shouldInterceptRequest()
webview shouldInterceptRequest example
Related
I try to load my contant as PDF in webview android but it display No Preview Available How can i solve
My Code is Here :-
webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setLoadWithOverviewMode(true);
webview.getSettings().setUseWideViewPort(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setPluginState(WebSettings.PluginState.ON);
webview.setWebChromeClient(new WebChromeClient());
String URLPATH = "http://myaccount365.in/public/oddeve78/report/ledger/11/summaryLedger?fromDate=01/11/2019&toDate=09/12/2019";
String url = "https://docs.google.com/gview?embedded=true&url=" + URLPATH;
webview.loadUrl(url);
The problem is clearly this:
You have two URLs - the URL of the PDF and the URL of google docs. Since you want to pass one URL to the other URL as a GET parameter (?embedded=true&url=) and the URL that you try to pass contains GET parameters as well: ?fromDate= and &toDate=, the seconds URL has to be URLEncoded.
So please just call
String url = "https://docs.google.com/gview?embedded=true&url=" + URLEncoder.encode(URLPATH, "ISO-8859-1");
and try again.
Caution: when working with URLEncoder.encode: you always have this problem: you can either call the #Deprecated method URLEncoder.encode(String s) without a specific encoding or the preferred method with URLEncoder.encode(String s, String enc) where you can specifiy the encoding, but this method has throws UnsupportedEncodingException in its signature :-O
Anyhow, both URLEncoder.encode(url) and URLEncoder.encode(url, "UTF-8") or URLEncoder.encode(url, "ISO-8859-1") will yield the same result since you have no UTF-8 or ISO-8859-1 specific characters in the URL:
https://docs.google.com/gview?embedded=true&url=http%3A%2F%2Fmyaccount365.in%2Fpublic%2Foddeve78%2Freport%2Fledger%2F11%2FsummaryLedger%3FfromDate%3D01%2F11%2F2019%26toDate%3D09%2F12%2F2019
I'm using this and works for me: Check Here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView=new WebView(MainActivity.this);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginState(WebSettings.PluginState.ON);
//---you need this to prevent the webview from
// launching another browser when a url
// redirection occurs---
webView.setWebViewClient(new Callback());
String pdfURL = "http://www.expertagent.co.uk/asp/in4glestates/{16D968D6-198E-4E33-88F4-8A85731CE605}/{05c36123-4df0-4d7d-811c-8b6686fdd526}/external.pdf";
webView.loadUrl(
"http://docs.google.com/gview?embedded=true&url=" + pdfURL);
setContentView(webView);
}
private class Callback extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(
WebView view, String url) {
return(false);
}
}
OR Try
I think Exact Problem is in URL encoding which we concat with "http://docs.google.com/gview?url=". This means we have to replace all special character(:, /, & etc) of url with unicode. Uri.encode("") do the trick for us.
Like this
String url = Uri.encode("your link");
String finalUrl = "http://docs.google.com/viewer?url=" + url + "&embedded=true";
I think it is your pdf file URL problem, please check your URLPATH it wether return a pdf URL like this https://www.tutorialspoint.com/css/css_tutorial.pdf
I use this URL it render normal
String URLPATH = "https://www.tutorialspoint.com/css/css_tutorial.pdf";
String url = "https://docs.google.com/gview?embedded=true&url=" + URLPATH;
//url:https://docs.google.com/gview?embedded=true&url=https://www.tutorialspoint.com/css/css_tutorial.pdf
webview.loadUrl(url);
I think your URLPATH is a dynamic url, it return a file url according to the params. but now it may be not return a correct url. it can to check it, or you change the URLPATH to a url which has http://host:port/path/.pdf . use it to test your code.
String URLPATH = "http://www.pdf995.com/samples/pdf.pdf";
String url = "https://docs.google.com/gview?embedded=true&url=" + URLPATH;
webview.loadUrl(url);
Open the pdf in the webview using google docs
Open the same pdf or different pdf again and again.
Sometimes it will show the blank/white page in the android untill we refresh the webpage again for 1 or 2 times.
I have made the sample on the pdf. The link for the project is shown below:
https://github.com/gopalawasthi123/PdfWebView
Hope this will help you Better.
public void SetWebView(WebView webview,string externalUrl){
webview.Tag = "webview";
webview.Settings.JavaScriptEnabled = true;
webview.Settings.SupportZoom ();
webview.Settings.SetAppCacheEnabled(true);
webview.Settings.DomStorageEnabled = true;
webview.ZoomOut ();
webview.ZoomIn ();
webview.Settings.BuiltInZoomControls = true;
webview.Settings.LoadWithOverviewMode = true;
webview.Settings.UseWideViewPort = true;
//webview.Settings.SetSupportZoom (true);
webview.Settings.SetPluginState (WebSettings.PluginState.On);
webview.Settings.GetPluginState ();
if (externalUrl.StartsWith("http://") || externalUrl.StartsWith("https://"))
webview.LoadUrl (externalUrl);
webview.SetWebViewClient (new MonkeyWebViewClient (imgViewBack, imgViewForward, imgRefresh));
webview.SetWebChromeClient (new WebChromeClient ());
}
You can reload the page until it displays the pdf in this way:
public void onPageFinished(WebView view, String url) {
if (view.getTitle().equals(""))
view.reload();
}
After testing second PDF URL file, WebView seems like that can not load large PDF file.
Reason:
WebView display HTML. The fact that this works at all is by a hack- google will convert simple PDFs into HTML. It doesn't seem like they support anything that big. Even if they did, I would expect loading a large page PDF converted to HTML would be so large I highly doubt you'd be able to load it without going OOM. Use an appropriate PDF library, make a real PDF rendering view, and make sure not to render more of the PDF at a time than you need (or else you'll go OOM anyway). In other words, don't rely on hacky solutions you never should have relied on in the first place.
Solution:
You should try alternatives like PDF.js running locally in your device, instead of a service like Google Docs preview.(Or download PDF first to local file path)
Put it in your assets folder and tweak the example:
wv.loadUrl("file:///android_asset/web/viewer.html");
Also, you can have Out Of Memory situations. An alternative to try is a native viewer like AndroidPdfViewer.
We can solve the Problem in the two ways.
1. One is to use the Js.Pdf Plugin on the server end. It surely solve the problem but if we have multiple pdf's in the Fragment then it may cause the out of memory situations
and app can crash.
2. Second option is we can recursively called the function to load webview. This will also cause the issue but with less frequency Below is the code:
private void showPdf(final String imageString) {
pdfView.invalidate();
pdfView.getSettings().setJavaScriptEnabled(true);
pdfView.getSettings().setSupportZoom(true);
pdfView.loadUrl("http://docs.google.com/gview?embedded=true&url=" + imageString);
pdfView.setWebViewClient(new WebViewClient() {
boolean checkhasOnPageStarted = false;
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
checkhasOnPageStarted = true;
}
#Override
public void onPageFinished(WebView view, String url) {
if (checkhasOnPageStarted ) {
pdfView.loadUrl(removePdfTopIcon);
} else {
showPdf(imageString);
}
}
});
}
I was having the exact same issue and found that there was always a chance the WebView would not load on the first load attempt, especially if the pdf was on the larger side. The code I put together below works 100% of the time. From my beginner's understanding, it safely utilizes a separate thread to loop through and test the load status of the WebView, re-attempting a load of the view until successful. As this question was posted a year ago, I have generalized my solution to best benefit new viewers.
public class WebViewActivity extends AppCompatActivity {
String PDFView;
WebView webView;
String PDFBrowserView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get the intended "PDFView"
PDFView = getIntent().getExtras().get("PDFView").toString();
//Have to manually encode (?) the url to display it
try {
PDFView = URLEncoder.encode(PDFView, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//Full display url
PDFBrowserView = "https://docs.google.com/gview?embedded=true&url=" + PDFView;
//Initialize a new "WebView" instance
webView = new WebView(WebViewActivity.this);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginState(WebSettings.PluginState.ON);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
//This handles callbacks (?)
webView.setWebChromeClient(new WebChromeClient());
//Call this to load page if page is blank with pdf url until page is not blank
checkPageFinished();
}
public void checkPageFinished() {
//If view is blank:
if (webView.getContentHeight() == 0) {
//Run off main thread to control delay
webView.postDelayed(new Runnable() {
#Override
public void run() {
//Load url into the "WebView"
webView.loadUrl(PDFBrowserView);
}
//Set 1s delay to give the view a longer chance to load before
// setting the view (or more likely to display blank)
}, 1000);
//Set the view with the selected pdf
setContentView(webView);
webView.postDelayed(new Runnable() {
#Override
public void run() {
//If view is still blank:
if (webView.getContentHeight() == 0) {
//Loop until it works
checkPageFinished();
}
}
//Safely loop this function after 1.5s delay if page is not loaded
}, 1500);
}
}
}
There are some ways through which we can identify whether a Page/URL is loaded properly or not from onPageFinished() method of the Webview and based on that reload() url.
Option 1 : To check with contentHeight of the webview.
override fun onPageFinished(view: WebView?, url: String?) {
if(view?.contentHeight == 0){
view?.reload()
return
}
super.onPageFinished(view, url)
}
Option 2 : To check with title of the webview.
override fun onPageFinished(view: WebView?, url: String?) {
if(view?.title.isNullOrEmpty()){
view?.reload()
return
}
super.onPageFinished(view, url)
}
Tested in multiple devices and working within API 29
in Kotlin
val webSettings: WebSettings = webview.settings
webSettings.javaScriptEnabled = true
webSettings.useWideViewPort = true
webSettings.loadWithOverviewMode = true
webSettings.domStorageEnabled = true
webview.webViewClient = AppWebViewClients()
// val TERM_CONDITION_URL = "http://docs.google.com/gview?embedded=true&url="
// + "YOUR_DOC_URL_HERE"
bindind?.webview?.loadUrl(TERM_CONDITION_URL)
and here AppWebViewClients class
class AppWebViewClients : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean {
view.loadUrl(url)
return true
}
override fun onPageFinished(view: WebView?, url: String?) {
if (view?.contentHeight == 0)
view?.reload();
else {
super.onPageFinished(view, url)
}
}
}
I think you should do as below:
public void onPageFinished(WebView view, String url) {
if (!view.getUrl().equals(url)) {
view.loadUrl(url);
return;
}
}
After update API (27) in Android OREO this code is no longer working:
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl("javascript:(function() {document.getElementById(\"imPage\").style.display='none';})()");
}
I have also tried with:
webView.loadUrl(
"javascript:(function() { " +
"document.addEventListener(\"DOMContentLoaded\", function(event) {" +
"document.getElementById(\"imPage\").style.display='none';" +
"});" +
"})()");
Element not hiding and debug return:
I/chromium: [INFO:CONSOLE(1)] "Uncaught TypeError: Cannot read property 'style' of null", source: mywebsite/ (1)
So I think the javascript is injected before loading page, this explains why the line is 1, because I have other code called after loading page is finished but this code is called when page is white, not loaded.
In my own project I have been using evaluateJavascript(script,null) in onPageFinished to hide html elements. view.loadUrl() Should work the same way.
If you don't need the function be called at later time you could simplify your JS string and instead of \" try using '.
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.loadUrl("javascript:document.getElementById('imPage').style.display='none';");}
document.getElementById(\"imPage\") must be returning null.
So there is either no imPageelement or you haven't loaded the page at the time.
I would suggest moving your entire js code into
document.addEventListener("DOMContentLoaded", function(event) {
//insert here
});
You have to enable Javascript Seetings like below :-
view.getSettings().setJavaScriptEnabled(true); //Yes you have to do it
Hi this doesnt work for me:
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
s="url clicked: "+url;
view.loadDataWithBaseURL(null, s, "text/html", "utf-8", null);
return true;
}
});
I have links in my html, it shows during loading in main activity,
but when I click them I get a white blank screen
I want to be able to read what those urls are, in the program, and I assume this url override function is the purpose for this.
I have tried with loadData() as well.
Thank you
You're not passing the new url to the WebView.
Should be
view.loadDataWithBaseURL(url, null, "text/html", "utf-8", null);
Edit: This also gives me a blank screen because loadDataWithBaseUrl expects you to provide some text or html as the data parameter yourself. Just use
view.loadUrl(url);
I didn't write http:// in my links, and wrote only x. This was the problem, it works now.
I am very new to Android Dev and I am developing what I thought would be a simple app. I have some HTML code that is stored is the raw resources folder - the code includes some Javascript. When I run the code in Google Chrome it runs fine - however when I load it into the webview using the loadData function it doesn't run the Javascript.
I have enabled javascript with:
mWebView.getSettings().setJavaScriptEnabled(true);
I need to be able to run this Javascript within the browser - any help?
Try this:
webView.loadDataWithBaseURL("blarg://ignored", getData(), "text/html",
"utf-8", "");
Try call JS function from code. Like this:
mWebView.loadUrl("javascript:myFunction()");
What does the loaded HTML data look like? In my case, the raw HTML data I generated was in the format:
<html>
<head>
<style>..</style>
<script>..</script>
</head>
<body>...</body>
</html>
Testing in a normal browser, things worked as expected. However, once I had used WebView.loadData, the CSS seemed to be recognized but I found that the Javascript was not working.
What found that worked for me was moving the Javascript to external files (more specifically I put the scripts I needed to assets/ using content providers.
<html>
<head>
<link rel="stylesheet" type="text/css" href="content://PATHTOSTYLESHEET" />
<script src="content://PATHTOJS"></script>
</head>
<body>...</body>
</html>
According to What is the difference between Android webview's loadData and loadDataWithBaseURL it sounds even more simple if you set a proper base URL which your style/scripts are stored - using the appropriate file:// for anything you store locally.
I am following up on #Cobaia's answer above, with another (I think) useful feature:
Since I need to keep changing the embedded HTML while testing and debugging, I decided to grab the raw page from my local web server during the development of the page and pass it to the webView as follows:
String url, str;
str = getFromURL(url);
webView.loadDataWithBaseURL("blarg://ignored", str, "text/html", "UTF-8", "");
where getFromURL() is defined as:
public String getFromURL(String urlToRead) {
URL url;
HttpURLConnection conn;
BufferedReader rd;
String result = "";
char[] chunk = new char[8192];
int blen = chunk.length;
int amt;
try {
url = new URL(urlToRead);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((amt = rd.read(chunk, 0, blen)) > 0) {
result += new String(chunk, 0, amt);
}
rd.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Note that I had to create a special controller (I'm using CodeIgniter) to allow downloading the file as a text file from the server.
Hope this hint helps others too!
The above solutions did not work for me because I was loading a string that held the HTML instead of a separate HTML file. The HTML in the string referenced JavaScripts that were in assets/www/. What worked was to use mWv.loadDataWithBaseURL("file:///android_asset/www/", HTML_AS_STRING, "text/html", "UTF-8", null);
See below for a full example. The example create a webview, loads the HTML from the string, and then calls a function in a separate JavaScript file. The function simply shows an alert.
public class MainActivity extends Activity{
private WebView mWv;
private static final String HTML_AS_STRING =
"<!DOCTYPE html>" +
"<html>" +
"<head>" +
"</head>" +
"<body>" +
"<p>Just some text in a paragraph.</p>" +
"<div align=\"center\" style=\"color:#0000FF\">" +
"<h3>This is a heading in a div element</h3>" +
"<p>This is some text in a div element.</p>" +
"</div>" +
"<font size=\"4\" color=\"0000FF\">" +
"This is some sized and colored text." +
"</font>"
+
"<script src=\"index.js\"></script>" +
"</body>" +
"</html>";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mWv = (WebView)findViewById(R.id.webview);
mWv.getSettings().setJavaScriptEnabled(true);
mWv.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url){
mWv.loadUrl("javascript:showAlert()");
}
});
mWv.setWebChromeClient(new WebChromeClient());
mWv.loadDataWithBaseURL("file:///android_asset/www/", HTML_AS_STRING, "text/html", "UTF-8", null);
}
}
index.js (A separate file in assets/www/):
function showAlert() {
alert("A simple alert!");
}