chromium浏览器页面longclick弹出菜单功能的实现
来源:互联网 发布:中航信托银川大数据数 编辑:程序博客网 时间:2024/05/22 00:08
最开始做这个功能是在chromium34上面实现的,后来移植到39上面,调用的相关的系统和内核的底层的接口还都好用,从34到39版本变化,chromium内核对于事件的传递这块逻辑代码应该没有太大的变化。
首先说下webkit浏览器是如何实现长按网页弹出菜单的:
从最开始的说起,对于android使用原生webview的浏览器来讲,长按一个链接(当然也包括图片,网站,邮箱,手机号码等),都会弹出一个菜单供用户选择,当然用户点击长按的内容不同,菜单弹出来的内容也不一样。那么系统把判断用户点击的类别大致包括下面几类:WebView.HitTestResult.PHONE_TYPE,WebView.HitTestResult.EMAIL_TYPE,WebView.HitTestResult.GEO_TYPE,WebView.HitTestResult.IMAGE_TYPE,WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE,WebView.HitTestResult.SRC_ANCHOR_TYPE,WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE。
这些在一个android原生浏览器的代码中,都是可以看到的,上面也写出了类名,方便大家查找。
那么这些信息,在应用层是如何得到的呢?在webview依赖的activity中,有一个方法:
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
}
这其中第二个参数,返回的webview就能够获取到WebView.HitTestResult的相关信息(当然这块不是所有的时候都会返回webview,我在这里说的我想大家应该都明白,我就不像写代码那样严谨的描述了)。接下来就是处理的相关逻辑了,这里不再赘述,自己看代码就好了。
接下来说下chromiun内核的浏览器,应用层可以copy安卓原生浏览器的代码,非常简单,和底层的交互就略有些复杂。在实现这个功能的过程中,主要做两部分内容的工作:一部分是响应事件;另一部分是是将点击事件的位置信息传到底层,底层处理后将获取到的信息再反给上层。
先在这里插一句:我们是将contentshell封装成自己的webview,提供了和android原生的相似的接口供上层调用,这也符合软件开发的基本原则。
1.事件响应:想要得到onCreateContextMenu回调,需要webview performLongclick,contentView中的performLongclick也要设置为返回true,这样才能保证一层一层的传给activity
2.将点击事件的位置信息传到底层,底层处理后将获取到的信息再反给上层:
webview的onTouchEvent传给Shell进行处理,在shell中调用nativeRequestNewTestDataAt方法,对应的c++文件是shell_android.cc文件,添加RequestNewTestDataAt方法,再调用shell_render_view_host_ext.cc中的RequestNewTestDataAt方法,这个方法有两个参数(Int view_x, int view_y),这两个就是坐标信息。前面的操作都是在主进程中进行,我们要把这两个参数通过browser进程发送给render进程。我们在shell_render_view_message.h中注册IPC通信的代码:
(browser to render)
IPC_MESSAGE_ROUTED2(ShellViewMsg_DoHitTest, int, int)
(render to browser)
IPC_MESSAGE_ROUTED1(ShellViewHostMsg_UpdateHitTestData, content::ShellHitTestData)
这块注册了两个IPC_MESSAGE信息,分别用于收发。
发送消息流程:shell_render_view_host_ext.cc中的RequestNewTestDataAt进行发送;
shell_render_view_ext.cc中进行接收,下面是主要代码:
(省略了大部分详细处理过程,省略的这些在chromium39源码中都能找到)
void ShellRenderViewExt::OnDoHitTest(int view_x, int view_y) {
if (!render_view() || !render_view()->GetWebView())
return;
const blink::WebHitTestResult result =
render_view()->GetWebView()->hitTestResultAt(
blink::WebPoint(view_x, view_y));
ShellHitTestData data;
if (!result.urlElement().isNull()) {
data.anchor_text = result.urlElement().innerText();
data.href = GetHref(result.urlElement());
}
PopulateHitTestData(result.absoluteLinkURL(),
result.absoluteImageURL(),
result.isContentEditable(),
&data);
Send(new ShellViewHostMsg_UpdateHitTestData(routing_id(), data));
}
将处理后的信息,封装成ShellHitTestData再次发送给browser进程,注意,shell_render_view_ext.cc是在子进程中进行的。
render进程再次将处理后封装好的东西发送给browser进程。(ShellHitTestData是在shell_hit_test_data.cc中创建的,有的代码里面叫AwHitTestData,这里不再贴代码了)
下面是在shell_render_view_host_ext.cc中处理的代码(主进程)
void ShellRenderViewHostExt::OnUpdateHitTestData(
const ShellHitTestData& hit_test_data) {
DCHECK(CalledOnValidThread());
last_hit_test_data_ = hit_test_data;
has_new_hit_test_data_ = true;
}
这里面同时也要提供接口:
const ShellHitTestData& ShellRenderViewHostExt::GetLastHitTestData() const {
DCHECK(CalledOnValidThread());
return last_hit_test_data_;
}
我们在shell_android.cc中调用上面的接口:
void Shell::UpdateLastHitTestData(JNIEnv* env, jobject obj) {
if (!shell_render_view_host_ext_->HasNewHitTestData()) return;
const ShellHitTestData& data = shell_render_view_host_ext_->GetLastHitTestData();
shell_render_view_host_ext_->MarkHitTestDataRead();
// Make sure to null the Java object if data is empty/invalid.
ScopedJavaLocalRef<jstring> extra_data_for_type;
if (data.extra_data_for_type.length())
extra_data_for_type = ConvertUTF8ToJavaString(
env, data.extra_data_for_type);
ScopedJavaLocalRef<jstring> href;
if (data.href.length())
href = ConvertUTF16ToJavaString(env, data.href);
ScopedJavaLocalRef<jstring> anchor_text;
if (data.anchor_text.length())
anchor_text = ConvertUTF16ToJavaString(env, data.anchor_text);
ScopedJavaLocalRef<jstring> img_src;
if (data.img_src.is_valid())
img_src = ConvertUTF8ToJavaString(env, data.img_src.spec());
Java_Shell_updateHitTestData(env,
obj,
data.type,
extra_data_for_type.obj(),
href.obj(),
anchor_text.obj(),
img_src.obj());
}
上面代码中最后一个掉用的方法,刚好是回调Shell.java中的方法,相当于转了一圈又回到了应用层,调用java层的updateHitTestData方法中包含了一些参数,其中data.type就是最前面说的哪几种类型,后面就不说了,源码中bean里面的注释都有自己看吧。
接下来就是在onCreateContextMenu中进行处理了,回调也有了,数据也传回来了,接下来全都是在java层处理的代码,打开新窗口,下载等操作了。
- chromium浏览器页面longclick弹出菜单功能的实现
- js关闭当前页面不弹出提示的方法 js实现浏览器的各种菜单命令
- 【Android】菜单功能的实现:弹出Popup菜单 以及小结
- [chromium][browser] [bug][closed] 长按页面中图片和链接,没有弹出菜单
- Flash 弹出菜单,点击舞台其他地方,关闭菜单功能的 实现方法
- chromium浏览器的编译
- jQuery 怎么实现点击页面其他地方隐藏菜单? 做了个按钮点击时弹出菜单,想实现点击其他地方时隐藏弹出的菜单
- 弹出菜单功能
- 页面弹出一个浏览器
- 浏览器弹出小页面
- Android创建浮动的上下文菜单,实现微信通讯录列表长按弹出菜单项功能
- 弹出窗口功能的实现
- [DevExpress控件应用]XtraNavBar: 实现弹出快捷菜单功能
- 用javascript 实现网页鼠标右键弹出菜单功能
- 微信中长按弹出菜单(1) 没有实现功能
- 微信中长按弹出菜单(2)实现了功能
- ActivityGroup基本菜单的实现和弹出菜单的实现
- 【Android】菜单功能的实现:上下文菜单
- &与&&的区别
- Ubuntu 平台配置 LAMP集成环境
- Could not initialize class sun.awt.X11GraphicsEnvironment
- 黑马程序员Java基础第一章----关键字,标识符,数据类型,运算符
- android 中解决输入法挡住输入框的问题
- chromium浏览器页面longclick弹出菜单功能的实现
- 工厂模式和抽象工厂模式
- Linux编辑器nano使用
- PDF转word免费在线转换
- 解决IE不兼容maxlength的方法
- Linux下Redis的安装使用
- C#图像剪裁、缩放、旋转、转化为鼠标光标
- 防止表单重复提交的几种策略
- xcode6生产内测包.