fragment下拦截返回键,home键和菜单键的思考

本文探讨了JS与Android的交互方式,包括JS调用Android方法和Android调用JS方法的具体实现。同时,深入讨论了在Android中监听手机按键(如返回键、Home键、菜单键)的多种方法及其局限性,特别关注了WebView环境下按键监听的实现与挑战。

一,需求前提:
网页上有一个挂机任务,当用户点击手机返回键,home键,菜单键,要通知网页,然后进行一系列操作,然后告知客户端下一步操作

二,首先我们知道js 与android相互调用的方式
1,js掉用android方法

①
webView.addJavascriptInterface(new InJsAndroid(), "injs_android");final class InJsAndroid{
  @JavascriptInterface
      public void gotoVideo() {}
}

2,Android调用js方法

① 不带参数
webView.loadUrl("javascript:onHome()");
② 带参数
webView.loadUrl("javascript:onHome('"+outbox+"')");

所以,想要客户端执行操作告诉网页并有回调,最简单最傻瓜式的操作:先调用网页方法执行 2方法,然后网页一系列操作后执行 1方法返回客户端
三,其次定位挂机任务界面,判断挂机界面 ,只在该界面有拦截,有两种方式
① 网页加载的url中添加特殊字符,在客户端shouldOverrideUrlLoading 方法时,判断一下,加个状态值,当点击返回时就以此值做判断
② 加载网页时加一个新方法,同样记录状态值

我们在前进后退页面时都会执行shouldOverrideUrlLoading方法,这样就可以知道是那个界面了

四,然后设置监听键方式:
打开百度,查到的最多的就是
① onKeyDown()

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return super.onKeyDown(keyCode, event);
    }

可惜 该方法里设置只在activity有用,在fragment中根本没这个方法,而且home和menu对应的 KEYCODE_HOME,KEYCODE_MENU都没作用
② onBackPressed()

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

只能针对返回键,在fragment中没这个方法

③ setOnKeyListener()

 webView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
                        webView.goBack();
                        return true;
                    }
                }
                return false;
            }
        });

这个还可以,能实现在fragment中返回操作,但同样不能实现home键,菜单键的监听拦截

④ onUserLeaveHint()

@Override 
    protected void onUserLeaveHint() { 
        super.onUserLeaveHint(); 
        Toast.makeText(this, "onUserLeaveHint", Toast.LENGTH_SHORT).show();
    }

据说这个可以监听home 键 ,先不管能不能用,在fragment下也是没有这个方法

⑤最后,网上很多资料都认为下面这个方法可行,能监听home键,菜单键 ,代码如下

       // 创建方法注册广播        
       if (getContext() != null) {
           getContext().registerReceiver(homeKeyEventReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
        }



//监听home键和菜单键
    private BroadcastReceiver homeKeyEventReceiver = new BroadcastReceiver() {
        String REASON = "reason";
        String HOMEKEY = "homekey";
        String RECENTAPPS = "recentapps";

        @Override
        public void onReceive(Context context, Intent intent) {
            if (onHookState && !onHookHomeState) {
                String action = intent.getAction();
                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                    String reason = intent.getStringExtra(REASON);
                    if (TextUtils.equals(reason, HOMEKEY)) {
                        // 点击 Home键
                        Log.e("ddddddddddd", "Home");
                        onHookHomeState = true;
                        webView.loadUrl("javascript:onHome()");
                    } else if (TextUtils.equals(reason, RECENTAPPS)) {
                        // 点击 菜单键
                        Log.e("ddddddddddd", "菜单键");
                        onHookHomeState = true;

                    }
                }
            }
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();
        //销毁方法里面记得反注册
        try {
            if (getContext() != null && homeKeyEventReceiver != null)
                getContext().unregisterReceiver(homeKeyEventReceiver);
        } catch (Exception ignored) {
        }
    }

onHookState 是指定该页面的标识,如果不是该网页,不监听。onHookHomeState 是标识是否点击了home,菜单键,可以直接忽略,看逻辑,确实实现了监听。

但是,但是,通过测试发现有如下几个问题:
① 每次点击home键都会执行该广播,不管是回到主界面,还是显示,这个好解决,加标识即可,如上onHookHomeState (未完善)
②点击了一次后,再次点击,广播好像不起反应了,不会触发了,可以尝试修改注册与反注册的时机,每次重新打开和暂停都注册与反注册

@Override
    protected void onResume() {
        super.onResume();
//注册
        registerHomeKeyReceiver(this);
    }

    @Override
    protected void onPause() {
// 解除
        unregisterHomeKeyReceiver(this);
        super.onPause();
    }

③ 点击回到主界面之后,再次点击home键是先执行该方法,而不会判断有没有打开,这个比较坑了,如果我打开别的应用,监听还在。
④该方式只能监听,不能拦截,点击home键,直接退到手机主界面了,根本没拦截到。
回到最初的需求,想要拦截home键,然后让网页做操作,然后返回啊,到最后查了很多地方,发现都不可行。

无能为力了

最后的办法是改需求,没错 ,就是改需求

理直气壮的告诉产品,home键和菜单键是系统级别的 ,没法子拦截,只能监听,然后做别的操作
在这里插入图片描述
把需求改为 返回键可以监听,与网页交互可正常回调,如果点击了home键和菜单键 直接告诉网页,客户端该回首页回首页,不做拦截,响应网页回调操作

最终效果 :在onPause()里判断下

@Override
    public void onPause() {
        super.onPause();
        if (onHookState){
            webView.loadUrl("javascript:onHome()");
        }
    }

以此记录一下,网上的方法代码真的是五花八门,各种方法都有,不管对不对,转发,写就完了,很多记录的不清不楚的,只写一半,还有小细节都不标明,需要一点一点的测试,有坑得跳

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值