In Android Studio choose New Project → Empty Views Activity, with Language Java and Minimum SDK API 24.
2. Allow internet access
In AndroidManifest.xml, add <uses-permission android:name="android.permission.INTERNET" /> above the application element. Without it, every page fails to load.
3. Add the WebView
In activity_main.xml, add a thin horizontal ProgressBar and a WebView that fills the rest of the screen.
4. Load your website
In MainActivity, find the WebView and call loadUrl(HOME_URL). Change HOME_URL to your own site.
5. Turn on JavaScript
Most sites need it: getSettings().setJavaScriptEnabled(true). Also turn on DOM storage, which many modern sites use. Only do this for a site you trust.
6. Keep your links inside the app
Without a WebViewClient, tapping a link opens the phone's browser. In shouldOverrideUrlLoading, return false for links on your own site, so they load in the app. Open everything else (other sites, email and phone links) with an Intent and return true.
7. Show loading progress
A WebChromeClient reports progress from 0 to 100. Set it on the progress bar, show the bar when a page starts, and hide it when it finishes.
8. Make Back go back
Add an OnBackPressedCallback: if webView.canGoBack(), go back a page; otherwise let the app close.
9. Run it
Tap around your site, then press Back to step back through the pages. Turn on airplane mode and reload to see the offline message.
If something goes wrong
Blank screen or an error page: check the INTERNET permission and that the address starts with https://.
Links open Chrome: set your WebViewClient before calling loadUrl.
Your site looks broken: turn on JavaScript and DOM storage.
What's improved over the video
A loading bar, Back that walks through the pages with the current API, outside links opened safely, an offline message, and the page kept when you rotate the phone.
Files affected
Check what to add and what to replace before copying code.
Loads your site, shows loading progress, keeps your links in the app and handles Back.
MainActivity.java
packagecom.example.webviewapp;importandroid.annotation.SuppressLint;importandroid.content.ActivityNotFoundException;importandroid.content.Intent;importandroid.graphics.Bitmap;importandroid.net.Uri;importandroid.os.Bundle;importandroid.view.View;importandroid.webkit.WebChromeClient;importandroid.webkit.WebResourceError;importandroid.webkit.WebResourceRequest;importandroid.webkit.WebSettings;importandroid.webkit.WebView;importandroid.webkit.WebViewClient;importandroid.widget.ProgressBar;importandroid.widget.Toast;importandroidx.activity.EdgeToEdge;importandroidx.activity.OnBackPressedCallback;importandroidx.appcompat.app.AppCompatActivity;importandroidx.core.graphics.Insets;importandroidx.core.view.ViewCompat;importandroidx.core.view.WindowInsetsCompat;/** Shows a website inside the app, like a mini browser locked to one site. */publicclassMainActivityextendsAppCompatActivity{// Change this to your own website.privatestaticfinalStringHOME_URL="https://codelab-x.com/";WebView webView;ProgressBar progress;@SuppressLint("SetJavaScriptEnabled")// the site is ours, so JavaScript is safe to allow@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main),(v, insets)->{Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(bars.left, bars.top, bars.right, bars.bottom);return insets;});
webView =findViewById(R.id.webview);
progress =findViewById(R.id.progress);WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);// many modern sites need local storage
webView.setWebViewClient(newMyWebClient());// WebChromeClient reports loading progress for the bar at the top.
webView.setWebChromeClient(newWebChromeClient(){@OverridepublicvoidonProgressChanged(WebView view,int newProgress){
progress.setProgress(newProgress);}});// After a rotation, restore the page the user was on instead of starting over.if(savedInstanceState ==null|| webView.restoreState(savedInstanceState)==null){
webView.loadUrl(HOME_URL);}// Back goes back through the web pages first, and only leaves the app at the first page.getOnBackPressedDispatcher().addCallback(this,newOnBackPressedCallback(true){@OverridepublicvoidhandleOnBackPressed(){if(webView.canGoBack()){
webView.goBack();}else{setEnabled(false);getOnBackPressedDispatcher().onBackPressed();}}});}privateclassMyWebClientextendsWebViewClient{@OverridepublicvoidonPageStarted(WebView view,String url,Bitmap favicon){
progress.setVisibility(View.VISIBLE);}@OverridepublicvoidonPageFinished(WebView view,String url){
progress.setVisibility(View.GONE);}@OverridepublicbooleanshouldOverrideUrlLoading(WebView view,WebResourceRequest request){Uri url = request.getUrl();// Pages on our own site stay inside the app.if(url.getHost()!=null&& url.getHost().endsWith(Uri.parse(HOME_URL).getHost())){returnfalse;}// Everything else (other sites, mail, phone links) opens in the right app.try{startActivity(newIntent(Intent.ACTION_VIEW, url));}catch(ActivityNotFoundException e){Toast.makeText(MainActivity.this,R.string.no_app,Toast.LENGTH_SHORT).show();}returntrue;}@OverridepublicvoidonReceivedError(WebView view,WebResourceRequest request,WebResourceError error){if(request.isForMainFrame()){Toast.makeText(MainActivity.this,R.string.offline,Toast.LENGTH_LONG).show();}}}@OverrideprotectedvoidonSaveInstanceState(Bundle outState){super.onSaveInstanceState(outState);
webView.saveState(outState);}}