今天说点关于android 和 webview 沟通的时候,需要监听软键盘的按键事件的问题
情境描述:由于js在部分手机上(比如华为青春版P8)无法监听到删除键,引起项目部分功能无法实现
解决思路:js 与android 互相沟通 就不多说了,网上一搜一大片,重点说一下 我的解决办法,之前在网上搜了一下,说的是andriod跟webview交互的时候,就把输入法管理 权交给webview了,从自己的界面代码是没有办法去监听软键盘的,所以想到了,看能不能去拦截下 输入链接桥梁,然后再拦截事件转交给 js,这样那些js无法监听软键盘的事件就ok了,
6.0手机以上 你可以采用像网上说的,自定义Webview,继承Webview,自定义里面的其他覆写方法不多说,网上一搜一大片,重点是复写onCreateInputConnection(EditorInfo outAttrs)方法,返回一个InputConnection输入法链接桥梁,然后对这个输入法链接桥梁 做一些你要干的事情,代码如下:
public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new MyInputConnection(super.onCreateInputConnection(outAttrs),//用父类的输入链接桥梁 转换成自己的,以便于对输入事件拦截, true,onItemClickCallBackI); //onItemClickCallBackI是自定义的一个回调接口,没什么可说的
}
public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new MyInputConnection(super.onCreateInputConnection(outAttrs),//用父类的输入链接桥梁 转换成自己的,以便于对输入事件拦截, true,onItemClickCallBackI); //onItemClickCallBackI是自定义的一个回调接口,没什么可说的
}
public class MyInputConnection extends InputConnectionWrapper { private OnItemClickCallBackI onItemClickCallBackI; public MyInputConnection(InputConnection target, boolean mutable,OnItemClickCallBackI onCallBackI) { super(target, mutable); if(onCallBackI!=null){ this.onItemClickCallBackI=onCallBackI; } } @Override public Handler getHandler() { return new Handler(); } @Override public boolean sendKeyEvent(KeyEvent event) { if(this.onItemClickCallBackI!=null){ onItemClickCallBackI.callFirstBack(event);//按键事件回调 } return super.sendKeyEvent(event); } @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace if (beforeLength == 1 && afterLength == 0) { // backspace return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } }
super.onCreateInputConnection(outAttrs) 华为青春版P8这个方法直接就返回空了,根本无法拦截
这就尴尬了,也一直在去搜索这方面知识,奈何时间又短,项目又紧张,根本没有时间去看系统代码,所以只能想其他办法,后面看到了EditText是如何拦截输入内容的,然后觉得如果将整个webview假设成为EditText有没有可能,没想到一试,还真行,代码如下:
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { super.onCreateInputConnection(outAttrs); return new MyInputConnection(new InputView(MyWebView.this,false,onItemTextClickCallBackI), true,onItemClickCallBackI);//InputView自己定义的继承基础输入链接桥梁类, } public class InputView extends BaseInputConnection { private OnItemClickCallBackI onItemTextClickCallBackI; public InputView(View targetView, boolean fullEditor,OnItemClickCallBackI textClickCallBackI) { super(targetView, fullEditor); this.onItemTextClickCallBackI=textClickCallBackI; } @Override public boolean commitText(CharSequence text, int newCursorPosition) { //System.out.println("截获的文字 :"+text); onItemTextClickCallBackI.callFirstBack(text);//文字拦截回调 return true; } } public class MyInputConnection extends InputConnectionWrapper { private OnItemClickCallBackI onItemClickCallBackI; public MyInputConnection(InputConnection target, boolean mutable,OnItemClickCallBackI onCallBackI) { super(target, mutable); if(onCallBackI!=null){ this.onItemClickCallBackI=onCallBackI; } } @Override public Handler getHandler() { return new Handler(); } @Override public boolean sendKeyEvent(KeyEvent event) { if(this.onItemClickCallBackI!=null){ onItemClickCallBackI.callFirstBack(event);//事件拦截回调 } return super.sendKeyEvent(event); } @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace if (beforeLength == 1 && afterLength == 0) { // backspace return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } }为什么去写了两个回调方法,一个是回调输入的文字,一个是回调软键盘的事件,当你去看到EditText 写拦截事件的时候,也没有整这么多内部类,原因就是以为webview毕竟不是EditView,不这么搞,要出事,
MyInputConnection 主要是去拦截软键盘的事件,
InputView 主要是去拦截输入的内容,
可能你只需要拦截软键盘事件,拦截内容干什么,接下来,你就明白了,
由于webview毕竟不是EditView,而且又是自定义的输入桥梁,当你在6.0以上系统是没有问题的,可是等到了6.0以下包括6.0,你会发现,你拦截的这个输入桥梁,根本无法输入汉字,英文 又是完全正常,这就尴尬了,好比以上的代码都是白费,其实不然,换个思路补救一下就OK,这就是为什么会有
InputView 这个类里面的 onItemTextClickCallBackI.callFirstBack(text);方法回调了
在回调的时候,将你拦截到的内容,传给js,让JS动态把这些字设到相应的控件上
这样中文 英文 都没有问题了,当然了,如果你有时间,可以去研究下系统源码,会有更好的处理中文和英文的办法
总的来说,解决办法就是 重新搭建 android 与webview的输入链接桥梁,拦截输入事件和内容,回调给js,这样在目前我实测了大量的手机下是没有问题的,
希望以上内容对您有所帮助,如果有更好的办法,还请指点