Create Android WebView App from Scratch
Create Android WebView App from Scratch

Want to turn your Android application into a web application? If yes, then an Android WebView is all that you need to work on.

Starting with what exactly is an Android WebView. It is an extension of Android’s class View, and what it does is that it integrates webpages inside the app, allowing webpages to be displayed within your application. WebView offers all the features of a typical web browser.  We can also specify the HTML string and then show it inside the app using WebView.

In this article, we shall learn using WebView from displaying a simple webpage to creating an in-app browser that shall have the features of forward, backward and bookmark. Let’s get started then!

Start by creating a new project in the Android Studio.

We need to add INTERNET permission in AndroidManifest.xml as we will be making network requests:

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>

Now add the WebView element in the xml layout:

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

Then we load the particular url in WebView from our activity. E.g. loading Google’s homepage in this example:

WebView webView = (WebView) findViewById(R.id.webView);
webView.loadUrl("http://google.com");
Android WebView Frontend example
Android WebView Frontend example

Next add the Glide library support in the build.gradle. This will allow us to load the image in CollapsingToolbar:

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

Download this resources folder that contains required drawables and assets required for this project. Then add the contents of folder to your project.

In the activity_main.xml, add the CoordinatorLayout, Toolbar and a ProgressBar which will be shown while the webpage is being loaded.

Activity_main.xml:

<?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>

Open the MainActivity.java and modify the code as below.

The initCollapsingToolbar() method enables the collapsing effect when webpage is scrolled up and the Glide method displays the header image in toolbar:

package buzzmycode.com.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 = "http://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("http://api.androidhive.info/webview/nougat.jpg")
                .thumbnail(0.5f)
.crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(imgHeader);
    }
}

On running the app now, we will see the webpage being loaded in the WebView! Woohoo, way to go!

Sometimes however, instead of loading a webpage from a url, we might want to load it from our app’s local storage. In that case, all html, css and fonts in the assets folder of your project and load them from there. Suppose we name the html file in the assets folder as example. html:

Example.html:

<!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 <img class="emoji" draggable="false" alt=" " 
src="https://s.w.org/images/core/emoji/2/svg/1f642.svg">
</body>
</html>

Call the following code in your MainActivity.java which will load the example.html from assets folder:

// Loading local html file into web view
webView.loadUrl("file:///android_asset/example.html

Now by calling setJavaScriptEnabled() method, you can easily enable or disable javascript functionality on a webpage:

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

Next enable the zooming controls (zooming in and zooming out of the webpage), using the following code:

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

Now let’s move over to building a simple browser activity with the forward, backward navigations and bookmark option.

Start by creating a class named Utils.java and add the below code:

Utils.java:

package buzzmycode.com.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 Ayma on 11/02/17.
 * www.buzzmycode.com
 */
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("buzzmycode", 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);
    }
}

Here the isSameDomain() checks whether or not the url is from same domain or not. bookmarkUrl() adds or removes a url from bookmarks list using SharedPreferences. isBookmarked() checks if a url is bookmarked or not.

Create a new menu called browser.xml. under menu in the res, which places the back, forward and bookmark icons on toolbar:

BrowserActivity.java:

package buzzmycode.com.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;
        }
 
 
    }
}

Now modify the code in MainActivity.java as follows:

MainActivity.java:

package buzzmycode.com.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 = "http://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("http://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;
        }
    }
}

Here MyWebChromeClient() intercepts the methods of WebView. shouldOverrideUrlLoading() detects whether the link that has been clicked is internal or external. If it’s external, the BrowserActivity is launched.

Now that everything is done, run the app and click on the external link in the webpage and you will be able to see the in-app browser launched with the navigation.

The following code will launch the in-app browser.

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

In place of url, enter the url that you want to load.

2 COMMENTS

  1. Plz can you tell me how to download any file like (.docx, .pdf, .img, etc)

    using webview app from my website to my mobile using android app?

    I want to download file from my website into my mobile using web view app.

    Please Help me.
    I am waiting for your reply..

Leave a Reply