402

I have an app in which I have a WebView where I display some websites. It works, clicking a link in the webpage goes to the next page in the website inside my app. But when I click the phone's back button, it takes me straight into my app. I want to go back to the previous page in the website instead. How can I do this?

Here is the code sample I'm using:

public class Webdisplay extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
        setContentView(R.layout.webdisplay);

        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
                Window.PROGRESS_VISIBILITY_ON); 

        Toast loadingmess = Toast.makeText(this,
                "Cargando El Diario de Hoy", Toast.LENGTH_SHORT);
        loadingmess.show();

        WebView myWebView;

        myWebView = (WebView) findViewById(R.id.webview);
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.loadUrl("http://www.elsalvador.com");
        myWebView.setWebViewClient(new WebViewClient());
        myWebView.setInitialScale(1);
        myWebView.getSettings().setBuiltInZoomControls(true);
        myWebView.getSettings().setUseWideViewPort(true);

        final Activity MyActivity = this;
        myWebView.setWebChromeClient(new WebChromeClient() 
        {
            public void onProgressChanged(WebView view, int progress)   
            {
                MyActivity.setTitle("Loading...");
                MyActivity.setProgress(progress * 100); 

                if(progress == 100)
                    MyActivity.setTitle(R.string.app_name);
            }
        });
    }
}
Andrew T.
  • 4,701
  • 8
  • 43
  • 62
zvzej
  • 6,276
  • 7
  • 33
  • 41
  • For xwalkview refer to [How to use back button to go back with XWalkView of CrossWalk, or disable it?](https://stackoverflow.com/q/40968633/6521116) – LF00 Jun 23 '17 at 04:15

18 Answers18

591

I use something like this in my activities with WebViews:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                if (mWebView.canGoBack()) {
                    mWebView.goBack();
                } else {
                    finish();
                }
                return true;
        }

    }
    return super.onKeyDown(keyCode, event);
}

Edit:

For this code to work, you need to add a field to the Activity containing the WebView:

private WebView mWebView;

Initialize it in the onCreate() method and you should be good to go.

mWebView = (WebView) findViewById(R.id.webView);
friederbluemle
  • 33,549
  • 14
  • 108
  • 109
FoamyGuy
  • 46,603
  • 18
  • 125
  • 156
  • 1
    were should I place that code? under all my code? or just under the loasUrl just like the builtinZoom? – zvzej May 20 '11 at 20:54
  • 3
    You'd put it inside your activity, but outside the onCreate() method. – FoamyGuy May 20 '11 at 21:06
  • when I place your code it gives me an error for the mWebView variable since is out of the oncreate, where should I place that variable? – zvzej May 20 '11 at 21:12
  • you need to put it inside activity, but before onCreate, see edit. – FoamyGuy May 20 '11 at 21:20
  • 6
    instead of `finish()` put `return super.onKeyDown(keyCode, event)` – Bostone Jan 16 '13 at 19:13
  • 6
    or in fact just simply remove whole `else` block – Bostone Jan 16 '13 at 19:23
  • I think the below answer (@Kevin's one) would be better.. anyway.. GG ;) – andrea.rinaldi Jul 14 '14 at 12:00
  • I used this code but not working in my app. but I am testing it on Emulator. how to test it on emulator? – Mohini Jan 01 '15 at 13:33
  • Remove the `else` block. This way the volume buttons doesn't close the application – RobinF Jan 24 '15 at 14:50
  • @RobinF the else block would not have any effect on the volume buttons the way the code is written because of the switch/case. The only thing removing the else block does is cause it not to ever close the activity with the back button. – FoamyGuy Jan 28 '15 at 22:57
349

If using Android 2.2 and above (which is most devices now), the following code will get you what you want.

@Override
public void onBackPressed() {
    if (webView.canGoBack()) {
        webView.goBack();
    } else {
        super.onBackPressed();
    }
}
Ion Aalbers
  • 7,830
  • 3
  • 37
  • 50
Kevin Westwood
  • 7,739
  • 8
  • 38
  • 52
  • 6
    Nice. I use a variation of this answer, but without the "else" block. Otherwise when the user presses back too many times they end up at a blank app "start" screen, with no option for the user to move forward. – George Armhold Nov 12 '12 at 16:49
  • 1
    This looks like the most appropriate answer. @CaffeineComa, you could probably just code your app start screen to not show in the app "activity" history. Just add `android:noHistory="true"` attribute in the `` you want, in the AndroidManifest.xml – LocalPCGuy Sep 27 '13 at 21:48
  • Should this `return;`? It does in the [training guide](https://developer.android.com/training/implementing-navigation/temporal.html#back-webviews). – ki9 Apr 25 '17 at 05:29
  • 1
    I love u so much – Jonathan Aste Feb 11 '22 at 15:14
132

This is my solution. It works also in Fragment.

webView.setOnKeyListener(new OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            WebView webView = (WebView) v;
            
            switch(keyCode) {
                case KeyEvent.KEYCODE_BACK:
                    if (webView.canGoBack()) {
                        webView.goBack();
                        return true;
                    }
                    break;
            }
        }
        
        return false;
    }
});
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
petrnohejl
  • 7,581
  • 3
  • 51
  • 63
  • 17
    this my opinion, this should be the proper answer. – Arvin Jul 16 '13 at 02:23
  • 2
    Why this answer should be the proper answer? Any issue with the top two answers? – ca9163d9 Jan 09 '15 at 04:12
  • 13
    @dc7a9163d9 an activity might want to have several views or objects that depend on keyDown. this answer abstracts out the need for the activity to keydown dependency via webview (which is better design). also, newer apps almost exclusively use fragments as opposed to activities, and this answer supports that use case as opposed to the others – David T. Jul 21 '15 at 04:02
  • I like this approach. Instead of the whole activity listening just the WebView – davejoem Nov 21 '17 at 08:55
  • Agree this is better, so the main activity doesn't need to hold a WebView only used by fragments. – Jannik Dec 20 '17 at 23:19
  • SUPERB! Thanks, this is especially useful in a Fragment! Thanks! – tm1701 Aug 18 '19 at 13:00
  • This is what i need. Thanks. – user1090751 Dec 28 '19 at 13:47
  • How to reload previous page ? – Hardik Parmar May 17 '20 at 21:18
  • 1
    This excellent solution naturally requires that the `WebView` has focus. If necessary, Issue `webView.requestFocus()` (for example in the case of a `Fragment` that is visible alongside the UI of its parent `Activity`) – Bad Loser Jan 10 '21 at 20:34
  • 1
    @Arvin It depends. In my case I want the back button to back the webview, even if other views have focus. – pmiguelpinto90 Apr 01 '21 at 09:36
21

Full reference for next button and progress bar : put back and next button in webview

If you want to go to back page when click on phone's back button, use this:

@Override
public void onBackPressed() {
    if (webView.canGoBack()) {
        webView.goBack();
    } else {
        super.onBackPressed();
    }
} 

You can also create custom back button like this:

btnback.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if (wv.canGoBack()) {
                wv.goBack();
            }
        }
    }); 
Parsania Hardik
  • 4,593
  • 1
  • 33
  • 33
17

Focusing should also be checked in onBackPressed

    @Override
    public void onBackPressed() {
        if (mWebview.isFocused() && mWebview.canGoBack()) {
            mWebview.goBack();       
        } else {
            super.onBackPressed();
            finish();
        }
    }
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
14

Why not use onBackPressed()?

@Override
public void onBackPressed() {
    // super.onBackPressed(); Do not call me!

    // Go to the previous web page.
}
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Gyan aka Gary Buyn
  • 12,242
  • 2
  • 23
  • 26
12

here is a code with confirm exit:

@Override
    public void onBackPressed()
    {
        if(webView.canGoBack()){
            webView.goBack();
        }else{
            new AlertDialog.Builder(this)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setTitle("Exit!")
            .setMessage("Are you sure you want to close?")
            .setPositiveButton("Yes", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();    
                }

            })
            .setNegativeButton("No", null)
            .show();    
        }   
    }
Mohammed Ahmed
  • 431
  • 5
  • 11
12

In kotlin:

override fun onBackPressed() {
    when {
        webView.canGoBack() -> webView.goBack()
        else -> super.onBackPressed()
    }
}

webView - id of the webview component in xml, if using synthetic reference.

vishnu benny
  • 998
  • 1
  • 11
  • 15
6
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check if the key event was the Back button and if there's history
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it wasn't the Back key or there's no web page history, bubble up to the default
    // system behavior (probably exit the activity)
    return super.onKeyDown(keyCode, event);
}
Mahesh
  • 2,862
  • 2
  • 31
  • 41
5
 WebView mWebView;

 mWebView = findViewById(R.id.webView);

    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            webView.goBack();
        } else {
            super.onBackPressed();
        }
    }
Abubakar
  • 111
  • 3
  • 13
3

The first answer by FoamyGuy is correct but I have some additions; low reputations cannot allow me to do comments. If for some reasons your page fails to load, ensure that you set a flag to take note of the failure and then check it on the onBackPressed override. Otherwise your canGoBack() will be forever executed without heading to the actual back activity if it was there:

//flag with class wide access 
public boolean ploadFailFlag = false;

//your error handling override
@Override
public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
    onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
    ploadFailFlag = true;       //note this change 
    .....
    .....
}

//finally to the answer to this question:
@Override
public void onBackPressed() {
    if(checkinWebView.canGoBack()){
        //if page load fails, go back for web view will not go back - no page to go to - yet overriding the super 
        if(ploadFailFlag){
            super.onBackPressed();
        }else {
            checkinWebView.goBack();
        }
    }else {
        Toast.makeText(getBaseContext(), "super:", Toast.LENGTH_LONG).show();
        super.onBackPressed();
    }
}
Ajowi
  • 449
  • 3
  • 12
2

If someone wants to handle backPressed for a webView inside a fragment, then he can use below code.

  1. Copy below code into your Activity class (that contains a fragment YourFragmmentName)

    @Override
    public void onBackPressed() {
    List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
    
    boolean handled = false;
    for(Object f: fragmentList) {
        if(f instanceof YourFragmentName) {
            handled = ((YourFragmentName)f).onBackPressed();
            if(handled) {
                break;
            }
        }
    }
    
    if(!handled) {
        super.onBackPressed();
    }
    

    }

  2. Copy this code in the fragment YourFragmentName

    public boolean onBackPressed() {
       if (webView.canGoBack()) {
           webView.goBack();
           return true;
       } else {
           return false;
       }
    }
    

Notes

  • Activity should be replaced with the actual Acitivity class you are using.
  • YourFragmentName should be replaced with the name of your Fragment.
  • Declare webView in YourFragmentName so that it can be accessed from within the function.
Faraz Ahmad
  • 515
  • 1
  • 6
  • 13
2

You can try this for webview in a fragment:

private lateinit var webView: WebView

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val root = inflater.inflate(R.layout.fragment_name, container, false)
    webView = root!!.findViewById(R.id.home_web_view)
    var url: String = "http://yoururl.com"
    webView.settings.javaScriptEnabled = true
    webView.webViewClient = WebViewClient()
    webView.loadUrl(url)
    webView.canGoBack()
    webView.setOnKeyListener{ v, keyCode, event ->
        if(keyCode == KeyEvent.KEYCODE_BACK && event.action == MotionEvent.ACTION_UP
            && webView.canGoBack()){
            webView.goBack()
            return@setOnKeyListener true
        }
        false
    }
    return root
}
2

I think I'm a little late but according to the android documentation, you can have custom back navigation inside fragments done by the following piece of code.

 requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
            if (binding.webView.canGoBack()){
                binding.webView.goBack()
            } else {
                findNavController().popBackStack()
            }
        }

you can customize what to do when you the webView cant go back as per your needs.

DharmanBot
  • 1,066
  • 2
  • 6
  • 10
Ammar Ahsan
  • 83
  • 1
  • 9
1

You should the following libraries on your class handle the onBackKeyPressed. canGoBack() checks whether the webview can reference to the previous page. If it is possible then use the goBack() function to reference the previous page (go back).

@Override
public void onBackPressed() {
    if( mWebview.canGoBack()){
        mWebview.goBack(); 
    } else {
        //Do something else. like trigger pop up. Add rate app or see more app
    }
}
Fah
  • 199
  • 9
Daniel Nyamasyo
  • 2,152
  • 1
  • 24
  • 23
1

Here is the Kotlin solution:

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    if (event?.action != ACTION_UP || event.keyCode != KEYCODE_BACK) {
        return super.onKeyUp(keyCode, event)
    }

    if (mWebView.canGoBack()) {
        mWebView.goBack()
    } else {
        finish()
    }
    return true
}
Gibolt
  • 42,564
  • 15
  • 187
  • 127
0

Official Kotlin Way:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    // Check if the key event was the Back button and if there's history
    if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
        myWebView.goBack()
        return true
    }
    // If it wasn't the Back key or there's no web page history, bubble up to the default
    // system behavior (probably exit the activity)
    return super.onKeyDown(keyCode, event)
}

https://developer.android.com/guide/webapps/webview.html#NavigatingHistory

SANAT
  • 8,489
  • 55
  • 66
-4

use this code to go back on page and when last page came then go out of activity

 @Override
    public void onBackPressed() {
        super.onBackPressed();
        Intent intent=new Intent(LiveImage.this,DashBoard.class);
        startActivity(intent);
    }
Pradeep Kumar
  • 2,349
  • 1
  • 10
  • 18