Android’s WebView allows you to integrate a webpage as a part of the app. WebView comes with all the features that of a desktop browser like managing history, cookies, HTML5 support and lot more. Using webview you can build very cool apps like integrating HTML5 games in the app.

In this article we are going to learn the basic usage of WebView starting from displaying a webpage to building a simple in-app browser that provides navigation and bookmark support. You will also learn how to use the WebView with other material elements like CollapsingToolbar and NestedScrollView to achieve the native android experience.

android-working-with-webview

1. The Basic Usage

Integrating a WebView in your app won’t take more than two steps. First you need to include the WebView element in your xml layout.

<WebView
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

Second you have load the specific url in webview from your activity. The below loads google’s homepage into web view.

WebView webView = (WebView) findViewById(R.id.webView);
webView.loadUrl("http://google.com");
android-webview-loading-url

Even though loading a simple url seems very easy, customizing the WebView needs thorough knowledge over WebView and the methods it is providing. We’ll start with basic methods WebView is providing and later on we’ll build a simple browser activity which acts as in-app browser that provides backward, forward and bookmark options. We’ll learn one by one by starting a simple project in Android Studio.

2. Creating New Project

1. Create a new project in Android Studio from File ⇒ New Project by filling the required details.

2. As we need to make network requests, we need to add INTERNET permission in AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.webview" >

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.NoActionBar" >
        <activity android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

3. Open build.gradle and add Glide library support. This is required to load the image in CollapsingToolbar. This step is optional, but I suggest you follow it for this article.

dependencies {
    ... 
    // glide
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

4. Download this resources folder and add the contents to your project. This folder contains required drawables and assets required for this project.

5. Open the layout files your main activity (activity_main.xml and content_main.xml) and the WebView element. Along with this, I am also adding CoordinatorLayout, Toolbar and a ProgressBar which will be shown while the webpage is being loaded.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@android:color/transparent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax" />
            </RelativeLayout>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="-7dp"
        android:indeterminate="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

content_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fadeScrollbars="false"
    android:scrollbarFadeDuration="0"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">


    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</android.support.v4.widget.NestedScrollView>

6. Now open the MainActivity.java and modify the code as below. Here initCollapsingToolbar() method is completely unrelated to WebView, but it is to provide collapsing effect when webpage is scrolled up. The Glide method is used to display the header image in toolbar.

package info.androidhive.webview;

import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

public class MainActivity extends AppCompatActivity {

    private String postUrl = "https://api.androidhive.info/webview/index.html";
    private WebView webView;
    private ProgressBar progressBar;
    private ImageView imgHeader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        webView = (WebView) findViewById(R.id.webView);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        imgHeader = (ImageView) findViewById(R.id.backdrop);

        // initializing toolbar
        initCollapsingToolbar();

        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl(postUrl);
        webView.setHorizontalScrollBarEnabled(false);
    }

    /**
     * Initializing collapsing toolbar
     * Will show and hide the toolbar txtPostTitle on scroll
     */
    private void initCollapsingToolbar() {
        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(" ");
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
        appBarLayout.setExpanded(true);

        // hiding & showing the txtPostTitle when toolbar expanded & collapsed
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            boolean isShow = false;
            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {
                    collapsingToolbar.setTitle("Web View");
                    isShow = true;
                } else if (isShow) {
                    collapsingToolbar.setTitle(" ");
                    isShow = false;
                }
            }
        });

        // loading toolbar header image
        Glide.with(getApplicationContext()).load("https://api.androidhive.info/webview/nougat.jpg")
                .thumbnail(0.5f)
                .crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(imgHeader);
    }
}

If you run the app now, you can see the webpage is loading in WebView. Now we’ll check the other useful methods that web view provides.

android-webview-tutorial

2.1 Loading Local Html, CSS and Font-Style

In some cases your might need to load a web page from app’s local storage instead from an url. In order to do that we can keep all the html, css and fonts in assets folder and load them from there.

7. Create a new folder in src/main called assets (src/main/assets) and place your html, css and fonts over there. I am keeping an html file named sample.html. Also I am adding two custom fonts Roboto-Light.ttf and Roboto-Medium.ttf to apply custom font face in CSS. I hope you downloaded these resources from here.

android-webview-loading-from-assets
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Android WebView Tutorial</title>
    <style type="text/css">
     @font-face {
         font-family: 'roboto';
         src: url('Roboto-Light.ttf');
     }

     @font-face {
         font-family: 'roboto-medium';
         src: url('Roboto-Medium.ttf');
     }

    body{
        color:#666;
        font-family: 'roboto';
        padding: 0.3em;
     }
    h1{
         color:#5f50e1;
         font-family: 'roboto-medium';
     }

    </style>
</head>

<body>
<h1>WebView loading local html</h1>
This is content is loaded from app's assets folder with custom css and font style 🙂
</body>
</html>

8. Calling the below code in your MainActivity.java loads the the sample.html from assets folder.

// Loading local html file into web view
webView.loadUrl("file:///android_asset/sample.html");
android-webview-loading-local-html

2.2 Enabling / Disabling Javascript

You can enable or disable javascript functionality on a webpage by calling setJavaScriptEnabled() method.

// enable / disable javascript
webView.getSettings().setJavaScriptEnabled(true);

2.3 Enabling Zooming Controls

WebView provides in-build zooming controls to zoom-in or zoom-out the webpage. These controls will be very useful when you have difficulty in reading the smaller fonts on webpage. Below code enables zooming controls on the webpage.

/**
* Enabling zoom-in controls
* */
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(true);

2.4 Building a Simple In-App Browser

Now with the basic knowledge we have, let’s see how to build a simple browser activity with backward, forward navigations and bookmark option. This in-app browser will be very useful to keep the users in your app instead of navigating them to third browser like Chrome.

9. Create a class named Utils.java and add the below code. Here

> isSameDomain() checks whether an url is from same domain or not. This method will be useful to launch the browser activity incase of external url.

> bookmarkUrl() method adds or removes an url from bookmarks list using SharedPreferences. isBookmarked() checks whether an url is bookmarked or not.

> tintMenuIcon() changes the color of toolbar icon. This method is to change the bookmark icon color when an url is bookmarked.

package info.androidhive.webview;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.view.MenuItem;

/**
 * Created by Ravi Tamada on 28/05/16.
 * www.androidhive.info
 */
public class Utils {

    public static boolean isSameDomain(String url, String url1) {
        return getRootDomainUrl(url.toLowerCase()).equals(getRootDomainUrl(url1.toLowerCase()));
    }

    private static String getRootDomainUrl(String url) {
        String[] domainKeys = url.split("/")[2].split("\\.");
        int length = domainKeys.length;
        int dummy = domainKeys[0].equals("www") ? 1 : 0;
        if (length - dummy == 2)
            return domainKeys[length - 2] + "." + domainKeys[length - 1];
        else {
            if (domainKeys[length - 1].length() == 2) {
                return domainKeys[length - 3] + "." + domainKeys[length - 2] + "." + domainKeys[length - 1];
            } else {
                return domainKeys[length - 2] + "." + domainKeys[length - 1];
            }
        }
    }

    public static void tintMenuIcon(Context context, MenuItem item, int color) {
        Drawable drawable = item.getIcon();
        if (drawable != null) {
            // If we don't mutate the drawable, then all drawable's with this id will have a color
            // filter applied to it.
            drawable.mutate();
            drawable.setColorFilter(ContextCompat.getColor(context, color), PorterDuff.Mode.SRC_ATOP);
        }
    }

    public static void bookmarkUrl(Context context, String url) {
        SharedPreferences pref = context.getSharedPreferences("androidhive", 0); // 0 - for private mode
        SharedPreferences.Editor editor = pref.edit();

        // if url is already bookmarked, unbookmark it
        if (pref.getBoolean(url, false)) {
            editor.putBoolean(url, false);
        } else {
            editor.putBoolean(url, true);
        }

        editor.commit();
    }

    public static boolean isBookmarked(Context context, String url) {
        SharedPreferences pref = context.getSharedPreferences("androidhive", 0);
        return pref.getBoolean(url, false);
    }
}

10. Under res ⇒ menu, create a new menu called browser.xml. This menu places the back, forward and bookmark icons on toolbar.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_bookmark"
        android:icon="@drawable/ic_bookmark_white_24dp"
        android:orderInCategory="100"
        android:title="@string/action_bookmark"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_back"
        android:icon="@drawable/ic_keyboard_arrow_left_white_24dp"
        android:orderInCategory="101"
        android:title="@string/action_back"
        app:showAsAction="always" />


    <item
        android:id="@+id/action_forward"
        android:icon="@drawable/ic_keyboard_arrow_right_white_24dp"
        android:orderInCategory="102"
        android:title="@string/action_forward"
        app:showAsAction="always" />
</menu>

11. Create a new activity called BrowserActivity.java and add the below code. This activity handles the browser forward and backward navigation in the toolbar along with bookmark option.

package info.androidhive.webview;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;

public class BrowserActivity extends AppCompatActivity {

    // private String TAG = BrowserActivity.class.getSimpleName();
    private String url;
    private WebView webView;
    private ProgressBar progressBar;
    private float m_downX;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_browser);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle("");

        url = getIntent().getStringExtra("url");

        if (TextUtils.isEmpty(url)) {
            finish();
        }

        webView = (WebView) findViewById(R.id.webView);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);

        initWebView();

        webView.loadUrl(url);
    }

    private void initWebView() {
        webView.setWebChromeClient(new MyWebChromeClient(this));
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                progressBar.setVisibility(View.VISIBLE);
                invalidateOptionsMenu();
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                webView.loadUrl(url);
                return true;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                progressBar.setVisibility(View.GONE);
                invalidateOptionsMenu();
            }

            @Override
            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                super.onReceivedError(view, request, error);
                progressBar.setVisibility(View.GONE);
                invalidateOptionsMenu();
            }
        });
        webView.clearCache(true);
        webView.clearHistory();
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setHorizontalScrollBarEnabled(false);
        webView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {

                if (event.getPointerCount() > 1) {
                    //Multi touch detected
                    return true;
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: {
                        // save the x
                        m_downX = event.getX();
                    }
                    break;

                    case MotionEvent.ACTION_MOVE:
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP: {
                        // set x so that it doesn't move
                        event.setLocation(m_downX, event.getY());
                    }
                    break;
                }

                return false;
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.browser, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {

        if (!webView.canGoBack()) {
            menu.getItem(0).setEnabled(false);
            menu.getItem(0).getIcon().setAlpha(130);
        } else {
            menu.getItem(0).setEnabled(true);
            menu.getItem(0).getIcon().setAlpha(255);
        }

        if (!webView.canGoForward()) {
            menu.getItem(1).setEnabled(false);
            menu.getItem(1).getIcon().setAlpha(130);
        } else {
            menu.getItem(1).setEnabled(true);
            menu.getItem(1).getIcon().setAlpha(255);
        }

        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.

        if (item.getItemId() == android.R.id.home) {
            finish();
        }

        if (item.getItemId() == R.id.action_back) {
            back();
        }

        if (item.getItemId() == R.id.action_forward) {
            forward();
        }

        return super.onOptionsItemSelected(item);
    }

    private void back() {
        if (webView.canGoBack()) {
            webView.goBack();
        }
    }

    private void forward() {
        if (webView.canGoForward()) {
            webView.goForward();
        }
    }

    private class MyWebChromeClient extends WebChromeClient {
        Context context;

        public MyWebChromeClient(Context context) {
            super();
            this.context = context;
        }


    }
}

12. Open the MainActivity.java modify the code as below. Here we use a custom MyWebChromeClient() to intercept the methods of WebView. In shouldOverrideUrlLoading() we detect whether the clicked link is internal or external. If it’s external, we launch the BrowserActivity.

package info.androidhive.webview;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

public class MainActivity extends AppCompatActivity {

    private String postUrl = "https://api.androidhive.info/webview/index.html";
    private WebView webView;
    private ProgressBar progressBar;
    private float m_downX;
    private ImageView imgHeader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        webView = (WebView) findViewById(R.id.webView);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        imgHeader = (ImageView) findViewById(R.id.backdrop);

        if (!TextUtils.isEmpty(getIntent().getStringExtra("postUrl"))) {
            postUrl = getIntent().getStringExtra("postUrl");
        }

        initWebView();
        initCollapsingToolbar();
        renderPost();
    }

    private void initWebView() {
        webView.setWebChromeClient(new MyWebChromeClient(this));
        webView.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                /**
                 * Check for the url, if the url is from same domain
                 * open the url in the same activity as new intent
                 * else pass the url to browser activity
                 * */
                if (Utils.isSameDomain(postUrl, url)) {
                    Intent intent = new Intent(MainActivity.this, MainActivity.class);
                    intent.putExtra("postUrl", url);
                    startActivity(intent);
                } else {
                    // launch in-app browser i.e BrowserActivity
                    openInAppBrowser(url);
                }

                return true;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                progressBar.setVisibility(View.GONE);
            }
        });
        webView.clearCache(true);
        webView.clearHistory();
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setHorizontalScrollBarEnabled(false);
        webView.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {

                if (event.getPointerCount() > 1) {
                    //Multi touch detected
                    return true;
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN: {
                        // save the x
                        m_downX = event.getX();
                    }
                    break;

                    case MotionEvent.ACTION_MOVE:
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP: {
                        // set x so that it doesn't move
                        event.setLocation(m_downX, event.getY());
                    }
                    break;

                }

                return false;
            }
        });
    }

    private void renderPost() {
        webView.loadUrl(postUrl);
    }

    private void openInAppBrowser(String url) {
        Intent intent = new Intent(MainActivity.this, BrowserActivity.class);
        intent.putExtra("url", url);
        startActivity(intent);
    }

    /**
     * Initializing collapsing toolbar
     * Will show and hide the toolbar txtPostTitle on scroll
     */
    private void initCollapsingToolbar() {
        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(" ");
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
        appBarLayout.setExpanded(true);

        // hiding & showing the txtPostTitle when toolbar expanded & collapsed
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            boolean isShow = false;
            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {
                    collapsingToolbar.setTitle("Web View");
                    isShow = true;
                } else if (isShow) {
                    collapsingToolbar.setTitle(" ");
                    isShow = false;
                }
            }
        });

        // loading toolbar header image
        Glide.with(getApplicationContext()).load("https://api.androidhive.info/webview/nougat.jpg")
                .thumbnail(0.5f)
                .crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(imgHeader);
    }

    private class MyWebChromeClient extends WebChromeClient {
        Context context;

        public MyWebChromeClient(Context context) {
            super();
            this.context = context;
        }
    }
}

Run the app and click on external link in the webpage. You can see the in-app browser launched with the navigation.

andriod-webview-in-app-browser

Here the code block that launches the in-app browser. Pass the intended url that you want to load.

Intent intent = new Intent(MainActivity.this, BrowserActivity.class);
intent.putExtra("url", url);
startActivity(intent);

I hope this article clears most of the doubts you have regarding WebView. Fell free to ask the queries if you have in the comments section below.

Subscribe
Notify of
guest
129 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Neeloor Palai
Neeloor Palai
3 years ago

download source is not working

Ravi Tamada
3 years ago
Reply to  Neeloor Palai

Fixed. Thank you.

Neha Sharma
Neha Sharma
3 years ago

Its Nice. Please Make a tutorial based on Kotlin….Its My Request to all you guys…

Kenny Dabiri
Kenny Dabiri
3 years ago

I’m motivated and challenged @Prushni Jani.

santosh
santosh
3 years ago

thanks for the article!
how to handle the url redirect time out?

vinay 17142
vinay 17142
3 years ago

i am not able to browse completely if i change THE URL

Ravi Tamada
3 years ago
Reply to  vinay 17142

Which url?

Dharmendra Mishra
Dharmendra Mishra
3 years ago

How to download from link in webview ??

harry
harry
3 years ago

very nice….

chaitanya malluru
chaitanya malluru
3 years ago

its not working yaaa

Ravi Tamada
3 years ago

Congrats:)

nirosha
nirosha
3 years ago
Reply to  Ravi Tamada

hiiii ravi i have one doubt how to sd card vides play on webview?

plzzz solve……..

syam
syam
3 years ago

@chaitanya malluru, it’s working perfectly… if you are using genymotion to run the codes, please enable the internet connection or wifi on the simulator.. 🙂

Sudheer
Sudheer
3 years ago

hi, can you do an video on native google+ login using Oauth2 token,that token sent to our php register API server were we get response of Sessionid,user details, with this we have to login in webview also at same time wen we call webview.loadUrl(Base_URL);

Android_Rocks
Android_Rocks
3 years ago

what about pdf file ??? this browser not open pdf file . and also where is download folder . please check

Paperwrk Labs
Paperwrk Labs
3 years ago

Please also do a tutorial on using Blogger API

Debajyoti Basak
Debajyoti Basak
3 years ago

please do a tutorial on how to make native apps for blogs and wordpress accounts

Kurniawan
Kurniawan
3 years ago

Please also do a tutorial how to create Shopping cart

Ambreen Khan
Ambreen Khan
3 years ago

Sir
I am contacting you because no one on the internet help me to resolve my app issue.
Sir I am loading image with the help of your tutorial : “http://www.androidhive.info/2012/07/android-loading-image-from-url-http/” and also I am using parse with list view, where as my app runs well but after I Host parse server my self and change “Parse Android SDK version to 1.13.1” for self hosted server the OkHttp error occurs.
“Some time Same code works great but most of the time it stuck with the following error and app get down rating on play store”
Respectable sir I also submit issue on Parse server and parse Android SDK github pages but no help got from there. And Parse android SDK seems stop updating on its github page.
I think your method “Imageloader and more its helping classes” conflicts with parse okHttp method.
Please Please resolve my issue because I dont get help from any side and your site is my final hope (As I First begin, Learn and start android development from your site)
Note: I also use proguard-rules as “-keep class com.parse.* { ; }
-dontwarn com.parse.”
but not get any solution.

“Where as The URL / hostname is correct”

java.net.UnknownHostException: Unable to resolve host “lh3.googleusercontent.com”: No address associated with hostname
at java.net.InetAddress.lookupHostByName(InetAddress.java:394)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
at java.net.InetAddress.getAllByName(InetAddress.java:214)
at com.android.okhttp.internal.Dns$1.getAllByName(Dns.java:28)
at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:216)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:122)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:292)
at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:179)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:246)
at com.myappid.ImageLoader1.getBitmap(ImageLoader1.java:73)
at com.myappid.ImageLoader1.access$000(ImageLoader1.java:24)
at com.myappid.ImageLoader1$PhotosLoader.run(ImageLoader1.java:149)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)

Ravi Tamada
3 years ago
Reply to  Ambreen Khan

Hi Ambreen

Have you tried using Glide to load images from url?
http://www.androidhive.info/2016/04/android-glide-image-library-building-image-gallery-app/

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Respectable Sir
Thanks for taking time to answer me.
Yes sir I use Glide,Picasso, Your tutorial image load helping classes, Every repo gives same issue (Issue like to be intermittent), Now I am using Universal Image Loader which loads images but not synchronously and loads images very very slow but without any “UnknowHost” error (So user still frustrated). Sir I think there is an issue with Parse Android SDK Version 1.13.1 (Which is essential for self hosted parse)and Image loading library OkHttp methods.
Sir Please suggest or give me any tip/direction to resolve the issue.
I will keep respect in my heart to my teacher to stand here in android world.

Ravi Tamada
3 years ago
Reply to  Ambreen Khan

First we’ll solve the image issue. Can you give me the image url for which you are getting unkownhost exception.

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Sir
Sorry for late response.

The Url is Given bellow:comment image

And alot of like that (Its just one problematic URL I giving you)

Getting from Parse Server the url is like That..
[
for (ParseObject country : ob) {
imageUrls[i] = country.getString(“url”);
imageUrls2[i] = country.getInt(“sort”);
PhoneList map = new PhoneList();
map.setPhone(country.getString(“url”));
phonearraylist.add(map);
i++;
}
]

And GridViewAdopter to load images in G.View
is
[
imageLoader.DisplayImage(phonearraylist.get(pstn).getPhone(),
holder.phone);
(Here ImageLoader is your Tutorial Image loader help classes )
]

Sir: Url is extracting well but when loading image process starts it give above error (some of the time its loads correctly).
Sir I double check the image URL its fine. (As you see its hosted on google server so there is minimal chance to get down the server). When error comes then I check the problematic URL in browser It works and load fine in Browser but not load in App.
Sir I observe the issue when I use Parse Android SDK version 1.13.1 ,
Alternatively When I Replace parse with Firebase It works fine, But I want it with parse Server.
Please Help..

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ambreen Khan

Sir…!?

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Sir I am still waiting..
Is there No solution for my problem??
At least Sir Answer.

shohel
shohel
3 years ago
Reply to  Ambreen Khan

what type of browse you are prepared?

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  shohel

I am using Standerd Imageview

shohel
shohel
3 years ago
Reply to  Ambreen Khan

ok can you attach my fb channel…. and give me the better solution….this my fb link(Shohelrana Mamon)there have better solution mam…

shohel
shohel
3 years ago
Reply to  Ambreen Khan

ok that s good…can visit my website or Facebook page?

shohel
shohel
3 years ago
Reply to  Ambreen Khan

or my Skype…shohel_mamon

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Respectable sir
I am still waiting your suggestion.
Sir How can I retry to execute following code after UnKnownHostException caught?

private Bitmap getBitmap(String url) {
File f = fileCache.getFile(url);

Bitmap b = decodeFile(f);
if (b != null)
return b;

// Download Images from the Internet
try {
Bitmap bitmap = null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex) {
ex.printStackTrace();
if (ex instanceof OutOfMemoryError) {

clearCache();

}
if (ex instanceof UnknownHostException) {

/* What Should Be there to execute same url again and again Until it loads correctly??
Sir I use This method
getBitmap(url)
But its not working in expected manner Please give me a hint */

}
return null;
}
}

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Sir I am still waiting..
Please hint me or tell me any suggestion Please.
Sir I am using App: https://play.google.com/store/apps/details?id=com.mobilepricess.novelscollectionurdu
Sir please there is a serious problem and I am founding solution from long time.

Ravi Tamada
3 years ago
Reply to  Ambreen Khan

Still same problem after 6months? Tell me what’s the problem?

Ambreen Khan
Ambreen Khan
3 years ago
Reply to  Ravi Tamada

Yes sir, Still bear same problem as mentioned before, I Can share my app source code (Privately).
If you renew and remove bugs from my app I will thankful to you (And also bit pay you if you want)…!

Ravi Tamada
3 years ago
Reply to  Ambreen Khan

Hi, please mail me your query to ravi.info

tracy miche
3 years ago

I have worked on this part for 3 days, at last after many confusions and errors I got the result. There are many sites for android tutorials but I find that your site is the best because I’m learning here from the beginning of this site. Thank you Ravi and team.

Ravi Tamada
3 years ago
Reply to  tracy miche

Thanks Tracy for supporting androidhive.

SriMaharshi Manchem
SriMaharshi Manchem
3 years ago

Hi Ravi,

Please do tutorial on Account manager with authentication on server side. There are very few references available.
Help please!
I’m working in a consultancy services based company(Hyderabad) as android app developer for the last 2 yrs.There are no experienced people in my team , so i have few queries regarding android development and my way of approach.Please let me know how to contact you ,so that i can share my queries.

Ravi Tamada
3 years ago

Hi

I have prepared the article and not published yet. Got occupied with other works. You can ask the questions here.

SriMaharshi Manchem
SriMaharshi Manchem
3 years ago
Reply to  Ravi Tamada

Hi

Thanks for your response and i’m looking forward to the article on Account Manager.
Coming to my queries,
1) I have been randomly learning and working on topics based on Project requirement.Is it right way of approach.
2) Are there any coding standards to follow for best user experience and performance of the apps.If so, could you share them.

Ravi Tamada
3 years ago

I’ll share the article once I am free.

1) I have been randomly learning and working on topics based on Project requirement.Is it right way of approach.
Yes

2) Are there any coding standards to follow for best user experience and performance of the apps.If so, could you share them.
This comes by practise and experience. Don’t worry about it initially, but make sure that you are improving your coding methods from project to project.

al ambari
al ambari
3 years ago

Hi Ravi, thanks great tutorial!
i’m confused how to combine webview and notification using sqlite php and mysql.
Please create tutorial. thanks ravi 😀

Ravi
Ravi
3 years ago

Hi Ravi, Thanks for your all great tutorial.
I have a request for you, please share some good tutorial for NDK.
Thanks!

Sahil Mathur
Sahil Mathur
3 years ago

Mr Ravi i want to ask how can take tab functional in a web browser such as in first tab facebook is running and In another gmail is running both these are running behind mainActivity?

AdnanRaza
AdnanRaza
3 years ago

I want to navigate from page1.html to page2.html, What I’m trying is same as we do in html Page2 but it doesn’t happen,

page1.html and page2.html are in same dir

Anup Sarkar
Anup Sarkar
3 years ago

Sir how can I open a PDF file from any link within webview in my application..
When I click on any PDF file from my site nothing happening ..
Please help me

Arbaz Alam
Arbaz Alam
3 years ago
Reply to  Anup Sarkar

Try this:

public class Ques_webpage extends AppCompatActivity {

private WebView webView;
public void onCreate(Bundle savedInstanceState) {

String dwnload_file_path = “http://www.arvindguptatoys.com/arvindgupta/cbt14-Short%20Stories%20For%20Children.pdf”;
super.onCreate(savedInstanceState);
setContentView(R.layout.websiteview);
webView = (WebView) findViewById(R.id.webView1);
startWebView(dwnload_file_path);
}

private void startWebView(String url) {
webView.setWebViewClient(new WebViewClient() {
ProgressDialog progressDialog;

public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
if (url.endsWith(“.pdf”)) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
return false;
}
});

webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollbarFadingEnabled(false);
webView.getSettings().setDisplayZoomControls(false);
webView.getSettings().setBuiltInZoomControls(true);
webView.loadUrl(url);
}

private boolean resumeHasRun = false;

@Override
protected void onResume() {
super.onResume();
if (!resumeHasRun) {
resumeHasRun = true;
return;
}
// Normal case behavior follows
}

@Override
// Detect when the back button is pressed
public void onBackPressed() {
if(webView.canGoBack()) {
webView.goBack();
} else {
// Let the system handle the back button
super.onBackPressed();
}
}
}

ABILASH SOMAN
ABILASH SOMAN
3 years ago

is it possible to download image from webview???

Sejpal Pavan
Sejpal Pavan
3 years ago

Hello Ravi Tamada,
your site is really awesome,
i’m a fresher right now and i can find lots of best examples to become a professional developer from your site,thank you so much….:-)

freerecharge227
freerecharge227
3 years ago

Gradle sync failed: Could not find method android() for arguments [build_8pex9ikr0ohjphi9ttsrsoyv2$_run_closure3@ab33cb] on root project ‘WebView’ of type org.gradle.api.Project.
Consult IDE log for more details (Help | Show Log)
————————————Build.gradle Code here—————

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath ‘com.android.tools.build:gradle:2.2.2’

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
comment image
android {
compileSdkVersion 25
buildToolsVersion ‘25.0.2’
}
dependencies {
}

Dilshad Khan
Dilshad Khan
3 years ago

sir how to enable horizontal scroll in web view???

bahman
bahman
3 years ago
Reply to  Dilshad Khan

???

Mingli Technologies
Mingli Technologies
3 years ago

Can someone show me how to add a splash screen to this app?

bahman
bahman
3 years ago

sir how to enable horizontal scroll in web view???

irwan
irwan
3 years ago

A very good tutorial for a beginner to me and thank you. But when I run the project there is an error on the toolbar .. how to solve it?

Ravi Tamada
3 years ago
Reply to  irwan

What is the error?

Abdul Rehman
Abdul Rehman
3 years ago

sir i have downloaded the source code but in this gradle is not working please guide and helpcomment image

Jvd
Jvd
3 years ago

some website is not working properly on webview in those mobiles who running below android 4.4.4 .
i tried crosswalk view but i still have the same problem.
P.S = i want to run html 5 website on those mobiles who is running android 4.4 or below
thanks is advance

Neeraja
Neeraja
3 years ago

Collapsing toolbar is not showing up in lollipop device. Even the image in the assets folder is not visible.

Nancy Hedlund
Nancy Hedlund
3 years ago

love you mate. keep posting.

Ravi Tamada
3 years ago
Reply to  Nancy Hedlund

Thank you.

Dadan Back
Dadan Back
3 years ago

I can not use admob code … if open aplication, opening “unfortunately Webview has stopped”…….
Please help..

Dadan Back
Dadan Back
3 years ago
Reply to  Dadan Back

Done,
And can using Image for header from local stronge apk….. ?

Thinker
Thinker
3 years ago

thank you

Andx Gallardo
Andx Gallardo
3 years ago

Hi, thanks for this tutorial, unfortunately, I follow it to the letter and I get errors, so I had to unload the file that they put above and modify it to my liking.

I have a little question:
How do I make the header image not a link of an image but an image saved in the same project? What happens is that it does not load the image of the link that I put so that it shows.

Sorry for the English, my language is Spanish.

Thanks in advance.comment image

Mobeen Riaz
Mobeen Riaz
3 years ago

Please refer any tutorial to do same task in iOS

Mobeen Riaz
Mobeen Riaz
3 years ago

Can we show push notifications in webview app?

Aakash Sugandhi
Aakash Sugandhi
3 years ago

hi,
i’m fresher for this field and i hvae also suffiecient knowledge about android but at that time i’m find job so i’m try make something new projects for strong my resume so,

problem is that i’m working on one project so how can i put my own logo on loading screen like comment image

i need my logo on replaced this ring progress bar so how can i make?

i thing it’s like Custom Progress bar but how can i implement in my project please help us.

Aziz
Aziz
3 years ago

Hi, Ravi
Getting window leaked error. Can you help?

Raina
Raina
3 years ago

How can I view bookmarked item? Where it is saved?

Ravi Tamada
3 years ago
Reply to  Raina

Currently it’s not saved. You have to implement saving it in onOptionsItemSelected method.

Mukesh Yadav
Mukesh Yadav
2 years ago
Reply to  Ravi Tamada

Plz implement this Feature

Dev Cen
Dev Cen
3 years ago

shouldOverrideUrlLoading is deprecated and I am trying to use WebResourceRequest request but Url get red. kindly give me solved code for this error

Dev Cen
Dev Cen
3 years ago

Is there anybody here?

Ravi Tamada
3 years ago
Reply to  Dev Cen

Yes, tell me.

Tabarek Ghassan
Tabarek Ghassan
3 years ago

not working

Ravi Tamada
3 years ago

Any error report?

Esan Josh
Esan Josh
2 years ago
Reply to  Ravi Tamada

Error:(28) No resource identifier found for attribute ‘layout_behavior’ in package ‘com.esjo.www.webview’
This error occured about 32 times

De Code
De Code
2 years ago

unfortunately webview has stopped

De Code
De Code
2 years ago

how can i load css and javaScript files into html file ?

Sagar
Sagar
2 years ago

Very Good

Akhil Mankala
Akhil Mankala
2 years ago

Hi this is a very good tutorial, thank you very much. I have a question, Can we set the font for the dynamic html text from JSON in webview. If yes, can you please guide me through it.

Thanks,
Akhil

Mukesh Yadav
Mukesh Yadav
2 years ago

Hello sir

I have 4 button(multiple url) on main activity and I m create a new activity (web view) browser activity implement code web view it’s working fine but I have remaining 3 button (url) I want to open all url in same activities..

Its posible

Thank you

Ravi Tamada
2 years ago
Reply to  Mukesh Yadav

You have to pass the url in Intent to your browser activity.

Read this to know how to send data b/w activities
https://www.androidhive.info/2011/08/how-to-switch-between-activities-in-android/

Subol
Subol
2 years ago

I’m trying to build a webview app using your tutorial. Everything is OK. But I want a selected website url to open in Device Browser from Browse Activity. How can I send a specific website url to Device browser from Browser activity?

i.e: when Main activity send a url contain http://www.facebook.com then Browser Activity will not open it rather it will send to Device Browser.

Ravi Tamada
2 years ago
Reply to  Subol

Do you want to identify the external URLs rather than your apps?

Benchur Wong
Benchur Wong
2 years ago

Good job.

Ravi Tamada
2 years ago
Reply to  Benchur Wong

Thank you.

129
0
Would love your thoughts, please comment.x
()
x