a lot of Android developer implement their own webview.
Although a lot of questions related to this topic are discussed on stackoverflow, here is probably a cause of this lack of clarity.
To open links within your WebView, android developer define their own webview.
According to http://developer.android.com/guide/webapps/webview.html returning false in shouldOverrideUrlLoading should be used, to open the url in the current Webview.
("current" means presumably created or used lately?)
According to http://developer.android.com/resources/tutorials/views/hello-webview.html and various blogs:
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
true must me returned.
Is there a mistake in one of the developer sites? It there difference between API level?
What is the cleanest and best use of shouldOverrideUrlLoading?
An answer would help our team and a lot of other developers working with android webviews.Thanks.
In case you decide to implement WebViewClient:
webView.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
// My own condition to decide if I should skip URL loading
boolean avoidURLLoading = ...
if (avoidURLLoading)
{
// Ask the WebView to avoid loading the URL,
// I want to manage this case on my own.
return true;
}
else
{
// Let the WebView load the URL
return false;
}
};
});
If you don't implement WebViewClient, every time you'll ask the WebView to load an URL with the loadUrl method, it will ask the Activity Manager to find a proper app to load the URL (typically a web browser installed in the device).
The default implementation of shouldOverrideUrlLoading in WebViewClient is
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
return false;
}
So if you just write something like this
webView.setWebViewClient(new WebViewClient());
the URL will load inside your own WebView and not in an external web browser.
You'll typically return true in shouldOverrideUrlLoading when you want to modify the URL and then load the new one with another loadUrl call or when you just want to avoid loading the URL and handle the request in a different way.
The behavior in your example
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
view.loadUrl(url);
return true;
}
is equivalent to
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
return false;
}
because you're telling the WebView to avoid handling the URL loading (return true), but you're also making another request with view.loadUrl(url) so in fact you end up loading the URL.
In order to open the link in the current WebView(Not the browser) you sould return false like this:
mWebView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url){
return false;
}
});
As long as you implement the setWebViewClient(..) my answer and the axample do the same thing. If you on the other hand do not implement it the browser will start instaed.
Related
I am attempting to load another site's iframe into my android app via webview. I am able to properly load other websites but when I load a stream from sportsbay.org which provides you with an iframe embed code snippet, the stream goes black and it prints "Sandboxing is not allowed". I have gone through several other questions to find an answer to this. My android project is as follows.
The specific url that I am passing in as video_url is https://sportsbay.org/embed/45629/1/btn-big-ten-network-live.html. The iframe snippet that sportsbay provides is <iframe allow='encrypted-media' width='640' height='360' marginwidth='0' marginheight='0' scrolling='no' frameborder='0' allowfullscreen='yes' src='//sportsbay.org/embed/45629/1/btn-big-ten-network-live.html'></iframe>. This url loads two urls 1) https://lowend.xyz/stream/45629.html which is the actual stream and moments later loads 2) https://sportsbay.org/live-streams to redirect you to the home page of sportsbay. I have code in MyWebViewClient that prevents the main sportsbay page from loading which would interrupt the stream I want to play (THIS is where I get the sandboxing message). I have tried replacing loadUrl with loadData and other variations that pass in the iframe html string along with the mimeType but what I have currently is the closest I have come to loading the stream (others don't get far enough to post the sandboxing message).
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Bring Linear layout into view.
setContentView(R.layout.webview);
// Grab current intent & pull out video url.
Intent i = getIntent();
String video_url = i.getStringExtra("video_url");
// Removes app name banner at top. Allows for orientation changes without reload.
getSupportActionBar().hide();
// Creates webview object.
WebView web = findViewById(R.id.webView);
// Configure settings for webview.
WebSettings webSettings = web.getSettings();
// Allows use of the phones file storage.
webSettings.setDomStorageEnabled(true);
// Sets encoding standard for urls.
webSettings.setDefaultTextEncodingName("utf-8");
// Able to zoom.
webSettings.setSupportZoom(true);
// Needed for websites to load javascript enabled content (most videos/streams).
webSettings.setJavaScriptEnabled(true);
// Attached webview to java class MyWebViewClient that vets the incoming urls before loading.
// Blocks Ads / viruses / popups.
// Also keeps url from launch in a browser.
web.setWebViewClient(new MyWebViewClient());
// Checks if channel is sourced from sportsbay.org.
if(video_url.contains("sportsbay.org"))
{
// Changes the browser user agent since chrome user agent returns 403 Forbidden message.
webSettings.setUserAgentString("Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion");
}
web.loadUrl(video_url);
}
public class MyWebViewClient extends WebViewClient {
public boolean shouldOverrideKeyEvent (WebView view, KeyEvent event) {
return true;
}
#SuppressWarnings("deprecation")
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
final Uri uri = Uri.parse(url);
return handleUri(uri);
}
#TargetApi(Build.VERSION_CODES.N)
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
final Uri uri = request.getUrl();
return handleUri(uri);
}
private boolean handleUri(final Uri uri) {
Log.i(TAG, "Uri =" + uri);
final String host = uri.getHost();
final String scheme = uri.getScheme();
// Check requested URL to known good
if (host.equals("s1-tv.blogspot.com") ||
host.equals("reddit-tv-streams.blogspot.com") ||
host.equals("newdmn.icu") ||
host.equals("lowend.xyz"))
{
// Returning false means that you are going to load this url in the webView itself
return false;
} else {
// Do not load the requested URL
return true;
}
}
}
Great news! I figured it out. The sandboxing message was not because of the server incorrectly interacting with my app, it was because my app did not have permission to use the file storage outside of the android application (the app sandbox). This was fixed with:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
which needs to be placed in the Android Manifest.xml in the permissions area (under the top package).
im trying to use the returned url after mypage finishes loading and comparing it with another url which is the same.
here is my code:
String success ="https://example.com/success";
public void onPageFinished(WebView webv, String url){
if(success==url){
doFunction1();
}else{
doFunction2();
}
}
it seems like the two Links are not the same then only doFunction2() is called.
(The page redirects to the success page and I just wanna check if the page really redirected or not)
I am assuming that you have set your WebViewClient.If not then you can do like below,
You can use this method to achieve what you want
webView.setWebViewClient(new MyWebViewClient());
String success ="https://example.com/success";
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String currentUrlLink = request.getUrl().toString();
if(success.equals(currentUrlLink)){
doFunction1();
}else{
doFunction2();
}
return false;
}
}
here currentUrlLink is the string where it gets the webView's current URL. and using .equals() you can match the success string with the current URL.
I have created an app that will load links from my server into the webview. However, I have also written an intent to open the link in the user's browser so they can download the file. I want the link to change a bit while it loads in the browser.
I.e:
This is the link : https://www.example/v/file
My app should change "v" to "f" and load in the user's browser.
Like this: https://www.example/f/file
My code:
private void initWebDowload(String s){
webView.loadUrl(s);
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(s));
startActivity(i);
}
Kinda complicated but you need to attach a custom WebViewClient to your WebView so you can change the URL loading behaviour.
Just to give an example:
webView.setWebViewClient(new CustomWebViewClient());
private class CustomWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// right here you are given the chance to change the [url] ^
view.loadUrl(url.replace("/v/file", "/f/file")); // replace v with f
return true;
}
}
}
Android webview mulitple windows. How to detect is created window from html target="blank" or it is a javascript popup?
I have next code in own browser:
WebSettings settings = webView.getSettings();
settings.setDomStorageEnabled(true);
settings.setJavaScriptEnabled(true);
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(false);
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
settings.setGeolocationEnabled(true);
settings.setSupportMultipleWindows(true);
also implementation create new windows in our ChromeClient:
#Override
public void onCreateWindow(WebView webView, boolean isDialog, boolean isUserGesture, Message resultMsg) { //logic for create new webview and set new url in it. }
We want to warn user about created new tab, but only if popup get from javascript code, because it is usually ad, and also many non ad pages use target="blank" attribute from html.
Okay. First you can try do something by adding custom WebChromeClient. Methods
onJsBeforeUnload(WebView view, String url, String message, JsResult result)
onJsConfirm(WebView view, String url, String message, JsResult result)
Also, ou can try by changing WebSettings of your WebView.
https://developer.android.com/reference/android/webkit/WebSettings.html
I found this. setJavaScriptCanOpenWindowsAutomatically(boolean flag)
#Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
WebView.HitTestResult result = view.getHitTestResult();
int type = result.getType();
if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
}
in if case we can handle action from html only, else different cases: auth2.0, or window.open("http://test.ua")
I'm trying to get the favicon of the loaded page after using
WebView webView = new WebView(getActivity());
webView.loadUrl("http://" + url);
I'm attaching the asynchronous WebViewClient to the WebView to get the favicon after it loads
webView.setWebViewClient(new WebViewClient()
{
#Override
public void onPageFinished(WebView view, String url)
{
String linkTitle = view.getTitle();
Bitmap favicon = view.getFavicon();
onLinkUrlFinished(url, linkTitle);
}
});
The favicon getting back is always null, even for websites such as google/facebook that has favicons for sure.
Another thread says to use WebIconDatabase but it's deprecated:
Display the Android WebView's favicon
The API on android site refers to WebViewClient.onReceivedIcon which doesnt even exist.http://developer.android.com/reference/android/webkit/WebView.html#getFavicon%28%29
What's going on here?
In order to use onReceiveIcon(), you should use setWebChromeClient.
This is what I do and it's working for me.
webView.setWebChromeClient(new WebChromeClient() {
#Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
progressBar.setProgress(newProgress);
}
#Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
webImage.setImageBitmap(icon);
}
});
WebIconDatabase is deprecated as of API 19. According to the comments in the code:
#deprecated This class is only required when running on devices up to
{#link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
So unless you don't want to support API 18 and below, you should still be using WebIconDatabase:
WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath());
And then, regardless what API you want to support, you need to specify in a custom WebChromeClient:
public class MyCustomWebChromeClient extends WebChromeClient {
#Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
// do whatever with the arguments passed in
}
}
Remember to register your custom WebChromeClient with your WebView:
mWebView.setWebChromeClient(new MyCustomWebChromeClient());
The key is to open the WebIconDatabase so WebView has somewhere to put the icons, and override WebChromeClient.onReceivedIcon. For additional information, see this StackOverflow article.
I know its an old thread but, for those facing problems getting favicon using webview client.
Kotlin:
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
tabTitle.text = view?.title // read website title
loadImg(view) // method to load the favicon
}
private fun loadImg (view: WebView?){
// u can directly use tabImage.setBitmap instead of assigning tabImg as val
val tabImg: ImageView = findViewById(R.id.tabImage)
// creating handler object to delay the associated thread a little bit after onPageFinished is called.
val handler = Handler()
val runnable = Runnable {
if(view?.favicon != null) {
tabImg.setImageResource(0) //remove the default image
tabImg.setImageBitmap(view?.favicon) // set the favicon
}
}
handler.postDelayed(runnable, 200) // delay time 200 ms
}
It worked for me, hope it helps new readers, plz up vote if it helps u, so that u can help others!
Best regards
So in the end I didn't end up using the deprecated API, instead I found out that if you put /favicon.ico after the domain, it'll give you the ico file, which I used in the end to fetch the image. The Uri API will have a getHost() method that will give you the host without having to manually parse it
String faviconUrl = Uri.parse(url).getHost() + "/favicon.ico";
For google for example the icon url will be www.google.com/favicon.ico