为何Android WebView 调用JS 扩选文本导致长按菜单不出现?-灵析社区

抠香糖

Android WebView 使用JS扩选的问题:我的需求是当用户选择webview的文本内容的时候,首次的长按的时候帮助用户选择整段,后续用户扩选的时候,自动帮用户选择整句。 我的思路是当原生这边创建系统菜单的时候(也就是用户开始选择之后),调用js,通过js的Selection API去做一个扩选。比如使用了下面的代码: function modify() { function forwardWord(selection) { var focusNode = selection.focusNode; var range = selection.getRangeAt(0); range.setEnd(range.endContainer, focusNode.textContent.length); selection.addRange(range); } let selection = window.getSelection(); selection.modify("extend", "backward", "paragraphboundary"); forwardWord(selection); console.log("selection.toString()", selection.toString()); return selection.toString(); } 调用了该Js之后,发现是能扩选成功的,但是系统的菜单就不再出现了,光标也不展示了。 其中,系统菜单是在长按的时候出现的那些例如:复制,全选,分享之类的系统自带的。 我是通过重写WebView的`startActionMode(ActionMode.Callback callback)`和`startActionMode(ActionMode.Callback callback, int type)`方法,创建自己的Callback代理,例如: fun proxyWebMenuCallback(callback: ActionMode.Callback, noticeH5: () -> Unit): ActionMode.Callback { return if (SdkVersion.maxThanM()) { WebViewMenuCallback2(callback, noticeH5) } else { WebViewMenuCallback(callback, noticeH5) } } @SuppressLint("NewApi") class WebViewMenuCallback2( private val callback: ActionMode.Callback, private val noticeH5: () -> Unit ) : ActionMode.Callback2() { override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { return callback.onCreateActionMode(mode, menu).also { LogUtil.d("WebViewMenuCallback2", "onCreateActionMode:$it") } } override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { noticeH5() return callback.onPrepareActionMode(mode, menu).also { LogUtil.d("WebViewMenuCallback2", "onPrepareActionMode:$it") } } override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { return callback.onActionItemClicked(mode, item).also { LogUtil.d("WebViewMenuCallback2", "onActionItemClicked:$it") } } override fun onDestroyActionMode(mode: ActionMode?) { callback.onDestroyActionMode(mode).also { LogUtil.d("WebViewMenuCallback2", "onDestroyActionMode:$it") } } override fun onGetContentRect(mode: ActionMode?, view: View?, outRect: Rect?) { if (callback is ActionMode.Callback2) { callback.onGetContentRect(mode, view, outRect) } else { super.onGetContentRect(mode, view, outRect) } } } class WebViewMenuCallback( private val callback: ActionMode.Callback, private val noticeH5: () -> Unit ) : ActionMode.Callback { override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { return callback.onCreateActionMode(mode, menu) } override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { noticeH5() return callback.onPrepareActionMode(mode, menu) } override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { return callback.onActionItemClicked(mode, item) } override fun onDestroyActionMode(mode: ActionMode?) { callback.onDestroyActionMode(mode) } } 我的想法是在创建菜单的监听中去执行JS代码进行扩选,但是无论我把`noticeH5`回调放在`onPrepareActionMode`还是`onCreateActionMode`中调用,还是`noticeH5`的实现是会通过`postDelay`去调用JS,结果都是扩选成功,但是菜单却被隐藏了,光标不见了。 然后我尝试在执行JS完成之后,例如: evaluateJavascript("javascript:" + js, value -> { postDelay(1000){ //performLongClick(); //showContextMenu(); } } ); 都不起效,无论是否一起调用。 后面我尝试在自定义菜单也不可以。 还尝试了自定义菜单,然后在执行完成JS之后,调用`startActionMode`方法,发现是会出现菜单的,但是菜单的位置出现不正确,而且光标也不见了,同时该方法还只能去设置执行一次,否则会陷入死循环,因为调用该方法之后,Callback里面的方法又开始执行了。 最后尝试了全部逻辑交由JS实现,结果就是js的菜单位置,扩选啥的都能直接做到,但是却不能自由选择了,光标没有了。 我的想法是这是否是Chrome的Bug,即在JS扩展选区的时候不能同步到原生端?因为扩选选区之后是会回调Callback的`onGetContentRect`方法的,我还在给官方提了bug,但是暂时也没有回应。[When JavaScript expand the selection,WebView ContextMenu aoto dimiss](https://link.segmentfault.com/?enc=1XnMCNZmELKGSLHmFBaiyg%3D%3D.QEG5P%2F%2BeEM6fcdtgDzRYTOKwaEAxTGgudnnW3g74Tbzh3sdfzobdxWvZgGpa7ZdavGCMqXL7P5rGlP2FqgFhoeishO8%2Btqra60bCI%2FieXTICLzqOilqNKuWXke7L3BEP) 请问应该如何实现JS扩展选区,扩选之后菜单能保持在正确的位置。 PS: 小米浏览器有一个扩选的功能,而且扩选之后是可以正常展示菜单和光标的。或者有知道小米的是如何实现的吗?

阅读量:172

点赞量:0

问AI
最终是修改了方案实现,用户可以自由复制,端上通过自定义Callback实现全自定义菜单。通过开源方案选择完整句子"get-selection-more" (https://link.segmentfault.com/?enc=nFPP7VFCuVTTQUIZ0g%2FdyA%3D%3D.HJALImj2U0buNJZNiGMPakqf%2FgeJF36bFu0LfYGZ6Bx6u5rcA5SXqHjtAR3lTGC8),对开源的方案进行了优化,增加了换行补充。