推荐 最新
抠香糖

为何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: 小米浏览器有一个扩选的功能,而且扩选之后是可以正常展示菜单和光标的。或者有知道小米的是如何实现的吗?

0
1
0
浏览量171
ciiiiinema

JSON.parse是否存在解析超大json字符串导致的拒绝服务DOS问题呢?

最近关注DOS问题,了解到后端服务在解析构造的超大超多空对象字符串后导致服务端DOS了,那么前端是否也存在因为JSON.parse解析超大超多空对象字符串导致的浏览器拒绝服务呢? 在网上搜索都没有相关讨论,难道浏览器不存在dos问题,或者浏览器的dos问题没有利用价值不值得被关注,特此一问,求各位大佬解惑。

0
1
0
浏览量191
云卿山手

求助:getUserMedia展示本机摄像头只能展示两个吗?为什么第三个会报错?

navigator.mediaDevices.getUserMedia 方法最多只能获取两个摄像头数据吗? 这边有一个设备有三个摄像头。使用navigator.mediaDevices.enumerateDevices方法获取到设备列表之后,循环调用getUserMedia,结果就是前两个可以展示在video标签中,第三个调用getUserMedia时会报错:DOMException: Could not start video source。 调整过展示顺序,三个摄像头的确没问题,谁第三个加载谁就不行。 html中有三个video标签,id分别是v0,v1,v2。 下面是js的调试代码。第三个getUserMedia会报错。好无奈啊。 export default { data(){ return { } }, mounted(){ this.test(); }, methods:{ async test(){ let arr = await navigator.mediaDevices.enumerateDevices(); console.log(arr); let list = []; for(let i=0;i{ let element1 = document.getElementById("v0"); element1.srcObject = stram; }).catch((e)=>{ console.log('Error',list[0],e) }); navigator.mediaDevices.getUserMedia(list[1]).then((stram)=>{ let element2 = document.getElementById("v1"); element2.srcObject = stram; }).catch((e)=>{ console.log('Error',list[1],e) }); navigator.mediaDevices.getUserMedia(list[2]).then((stram)=>{ let element3 = document.getElementById("v2"); element3.srcObject = stram; }).catch((e)=>{ console.log('Error',list[2],e) }); }, } } https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20240920/c3c406c1717815c1e15bddb5979402ec.png

0
1
0
浏览量135