Android 编译文件使其支持wml
前不久发现android默认没有放开对wml的支持,这样就导致某些网站无法访问,从网上搜索到的文档都说只要ENABLE_WML=1就可以支持,但是我把ENABLE_WML设置成1之后,就出现了编译通不过的情况,经过一番调试,最终可以编译并且实现了对wml的支持。
2. Windows
必备条件把Webkit编译通过了,具体参考webkit.org上的说明,把必须的SDK,patch都安装了。
VC2005和VC Express 2005都能编过,安装VC的几个patch能大大提升编译速度,磨刀不误砍柴功。
编译成功后默认wml是关闭的,修改如下几个文件,把wml相关配置(ENABLE_WML)打开
FeatureDefines.xcconfig
GNUmakefile.am
configure.ac
features.pri
FeatureDefines.vsprops这时开始编译,必然会失败,停在webcore编译上,提示如下:
WMLElementFactory.cpp 中ConstructorFunction重定义
然后关键的两步:
1.找到DerivedSources.cpp,注释掉如下两行
//#include "WMLElementFactory.cpp" //#include "WMLNames.cpp"
2. 修改webcore.vcproj,把上面两个文件参与编译(关闭“从生成中排除”)。
这样就能编译成功了。
下面主要纪录一下如何编译通过,编译不通过一开始都是说找不到WMLNames.h之类的错误,所以我们需要在脚本里面添加上生成该文件的语句,并且把wml里面的头文件都include进来。
首先在external/webkit下的Android.mk 中添加
LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) / $(LOCAL_PATH)/WebCore/wml
D:\Webkit\WebCore\Android.derived.mk
然后在Android.derived.mk中添加wml的user agent style sheetsstyle_sheets := $(style_sheets) $(LOCAL_PATH)/css/wml.css
参考XMLNames.cpp的生成方式,生成wml对应的WMLNames.cpp .h等
ifeq ($(ENABLE_WML), true)
GEN:=$(intermediates)/WMLNames.cpp$(intermediates)/WMLNames.h$(intermediates)/WMLElementFactory.cpp$(intermediates)/WMLElementFactory.h
$(GEN):PRIVATE_PATH:=$(LOCAL_PATH)
$(GEN):PRIVATE_CUSTOM_TOOL=perl-I$(PRIVATE_PATH)/bindings/scripts$<--tags$(wml_tag)--attrs$(wml_attrs)--factory--wrapperFactory--output$(dir$@)
$(GEN):wml_tag:=$(LOCAL_PATH)/wml/WMLTagNames.in
$(GEN):wml_attrs:=$(LOCAL_PATH)/wml/WMLAttributeNames.in
$(GEN):$(LOCAL_PATH)/dom/make_names.pl$(wml_tag)$(wml_attrs)
$(transform-generated-source)
LOCAL_GENERATED_SOURCES+=$(GEN)
endif
这样在out目录下就会生成WMLNames.cpp等文件当然同样需要把webkit/webcore/wml下的文件都添加的Android.mk中来编译。
要让android支持wml,还需要进行一些代码方面的修改
对于移动终端,有时候服务器返回的是WML格式的页面。 比如说中国移动的一些需要使用cmwap接入点的业务页面(DCD, 移动梦网…), 这就要求终端浏览器必须能够支持对WML格式页面的解析和显示。 Android原始代码里的webkit层虽然提供了WML相关的解析类,但是并没有很好地支持,所以在页面上无法正确显示。 我们需要做以下一些修改:
1.打开对WML格式解析的通道
修改源码的\external\webkit\WebCore\dom\DOMImplementation.cpp获取到服务器返回的数据中的content-type字段值后,会调用这个类里面的isXMLMIMEType()方法来判断是否按照XML格式来解析。我们看这个方法:
java代码:- bool DOMImplementation::isXMLMIMEType(const String& mimeType)
- {
- if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl")
- return true;
- static const char* const validChars = "[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]"; // per RFCs: 3023, 2045
- DEFINE_STATIC_LOCAL(RegularExpression, xmlTypeRegExp, (String("^") + validChars + "+/" + validChars + "+\\+xml$", TextCaseSensitive));
- return xmlTypeRegExp.match(mimeType) > -1;
- }
复制代码
这里只包含了text/xml, application/xml, text/xls. 我们需要把WML相应的MiMeType类型加进去
If(mimeType==“text/vnd.wap.wml”)returntrue;
修改framework/base/core/java/android/webkit/LoadListener.java,源码如下:
java代码:- // Does the header parsing work on the WebCore thread.
- private void handleHeaders(Headers headers) {
- …
- } else if (mMimeType.equals("text/vnd.wap.wml")) {
- // As we don't support wml, render it as plain text
- mMimeType = "text/plain";
- }
复制代码
我们可以看到, 原来是不支持wml格式的, 都当做text/plain来处理了,这样显然是不能正确显示的。 所以这一行mMimeType = "text/plain";需要注释掉,打开给外围。
2.对WML中的超链接元素(WMLAElement和WMLAnchorElement)中href属性值里面的变量替换。
笔者发现,在一个WML的登陆页面上,填入用户名和密码后,点击登陆,附加到url后面的用户名和密码是$(username)和$(password),有web开发经验的XDJM都知道,这是没有将变量替换为页面上相应值。我们看WMLAElement.cpp中处理点击事件的方法:
java代码:- void WMLAElement::defaultEventHandler(Event* event)
- {
- if (isLink() && (event->type() == eventNames().clickEvent || (event->type() == eventNames().keydownEvent && focused()))) {
- MouseEvent* e = 0;
- if (event->type() == eventNames().clickEvent && event->isMouseEvent())
- e = static_cast<MouseEvent*>(event);
- KeyboardEvent* k = 0;
- if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent())
- k = static_cast<KeyboardEvent*>(event);
- if (e && e->button() == RightButton) {
- WMLElement::defaultEventHandler(event);
- return;
- }
- if (k) {
- if (k->keyIdentifier() != "Enter") {
- WMLElement::defaultEventHandler(event);
- return;
- }
- event->setDefaultHandled();
- dispatchSimulatedClick(event);
- return;
- }
- if (!event->defaultPrevented() && document()->frame()) {
- String url = document()->completeURL(deprecatedParseURL(getAttribute(HTMLNames::hrefAttr)));
- document()->frame()->loader()->urlSelected(url, target(), event, false, false, true, SendReferrer);
- }
- event->setDefaultHandled();
- }
- WMLElement::defaultEventHandler(event);
复制代码
通过打印Log发现,getAttribute(HTMLNames::hrefAttr)获取的只是href后面的字符串,包含变量$(). 我们需要对其中的变量进行转化。还好WMLVariables里面已经提供了相应的方法substituteVariableReferences,不需要我们再去写一个了。修改如下 java代码:
- #include "WMLVariables.h"
- if (!event->defaultPrevented() && document()->frame()) {
- // Substitute variables within target url attribute value. String href = getAttribute(HTMLNames::hrefAttr);
- href = substituteVariableReferences(href, document(), WMLVariableEscapingEscape);
- String url = document()->completeURL(deprecatedParseURL(href));
- document()->frame()->loader()->urlSelected(url, target(), event, false, false, true, SendReferrer);
- }
复制代码
别忘了,WMLAnchorElement.cpp中相应的地方也要同样改掉。
3.在页面上长按链接时弹出选项点击失效
这是由于点击时是从webkit层去获取这个链接的地址和标题的,而源码中只考虑了HTML格式的页面,WML页面被忽略了。返回的href为null.
首先要在WMLAElement.cpp中提供接口,返回链接。
java代码:- KURL WMLAElement::href() const
- {
- // Substitute variables within target url attribute value.
- String href = substituteVariableReferences(getAttribute(HTMLNames::hrefAttr),
- document(), WMLVariableEscapingEscape);
- return document()->completeURL(href);
- }
复制代码
由于WMLAnchorElement继承了WMLAElement, 就不需要再添加这个方法了。 然后修改WebViewCore.cpp, 原来获取href的方法是这样的: java代码:
- WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
- {
- WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
- return anchor ? anchor->href() : WebCore::String();
- }
复制代码
在这里增加WML的支持, 修改如下: java代码:
- #if ENABLE(WML)
- WebCore::WMLAnchorElement* WebViewCore::retrieveWMLAElement(WebCore::Frame* frame, WebCore::Node* node)
- {
- if (!CacheBuilder::validNode(m_mainFrame, frame, node))
- return 0;
- if (!node->hasTagName(WebCore::WMLNames::aTag))
- return 0;
- return static_cast<WebCore::WMLAnchorElement*>(node);
- }
- #endif
- /**add WML anchor support 20110224, end**/
- WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
- {
- /**retrieve WMLAnchor element. 20110224, begin**/
- #if ENABLE(WML)
- if (node->isWMLElement()) {
- WebCore::WMLAnchorElement* anchor = retrieveWMLAElement(frame, node);
- return anchor ? anchor->href() : WebCore::String();
- }
- #endif
- /**retrieve WMLAnchor element. 20110224, end**/
- WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
- return anchor ? anchor->href() : WebCore::String();
- }
复制代码
还有获取链接标题的方法,修改如下: java代码:
- WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
- {
- /**retrieve WMLAnchor element. 20110224, begin**/
- #if ENABLE(WML)
- if (node->isWMLElement()) {
- WebCore::WMLAnchorElement* anchor = retrieveWMLAElement(frame, node);
- return anchor ? anchor->title() : WebCore::String();
- }
- #endif
- /**retrieve WMLAnchor element. 20110224, end**/
- WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
- return anchor ? anchor->text() : WebCore::String();
- }
复制代码
4. 移动梦网无法正确显示,解析出错。
移动梦网返回的数据格式为application/vnd.wap.xhtml+xml,包含了xhtml和xml两种格式。而CMCC的数据本身又不是严格按照W3C标准来的,导致在解析的时候出现了语法错误提示。对于这种情况,我们显然无法去要求CMCC改变数据,只能把这种格式当做普通的html来显示,html没有那么严格的语法检查,可以正常显示。修改framework/base/core/java/android/webkit/LoadListener.java:
java代码:- private void handleHeaders(Headers headers) {
- 。。。
- String contentType = headers.getContentType();
- if (contentType != null) {
- parseContentTypeHeader(contentType);
- // If we have one of "generic" MIME types, try to deduce
- // the right MIME type from the file extension (if any):
- if (mMimeType.equals("text/plain") ||
- mMimeType.equals("application/octet-stream")) {
- // for attachment, use the filename in the Content-Disposition
- // to guess the mimetype
- String contentDisposition = headers.getContentDisposition();
- String url = null;
- if (contentDisposition != null) {
- url = URLUtil.parseContentDisposition(contentDisposition);
- }
- if (url == null) {
- url = mUrl;
- }
- String newMimeType = guessMimeTypeFromExtension(url);
- if (newMimeType != null) {
- mMimeType = newMimeType;
- }
- } else if (mMimeType.equals("text/vnd.wap.wml")) {
- // As we don't support wml, render it as plain text
- // mMimeType = "text/plain";
- } else {
- // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
- // subtypes are used interchangeably. So treat them the same.
- //if (mMimeType.equals("application/vnd.wap.xhtml+xml")) {
- // mMimeType = "application/xhtml+xml";
- //}
- /* Webkit used libxml2 as the xml parser, but the CMCC's WAP sites
- written in WML or XHTML do not meet W3C's specification well,
- and libxml2 will throw a lot of grammatical errors when it parses
- the document which has the mime type is "application/xhtml+xml" or
- "application/vnd.wap.xhtml+xml". When i opened the macro named
- "XHTMLMP" in config.h in webcore and tested, i found some bugs,
- i believed that Google did not do detail test works for this macro.
- So i could handle "XHTML" mime type as "HTML" only in order to
- open CMCC's WAP sites in browser.
- */
- if (mMimeType.equals("application/vnd.wap.xhtml+xml") ||
- mMimeType.equals("application/xhtml+xml"))
- {
- mMimeType = "text/html";
- }
复制代码
WebKit支持WML,可现在这句话需要打个折扣了,变成“WebKit曾经支持WML”。
一直以来,WebKit的ENABLE(WML)开关默认是关闭的,需要在编译时打开才能提供WML的支持。苹果在iPhone的Safari上一直都不支持WML,谷歌在Android的Chrome Lite也是不支持WML的。
如果你去查看WebKit的最新源代码,你会发现原来的wml目录没有了,不管是源码的wml还是测试用例的wml,都没有了。查询WebKit的开发日志,可以在2011年4月28日的记录上看到相关信息,Remove WML在这之后的版本提交中多次被写到开发日志中。其中有一段是这样的:
2011-04-28 Adam Barth < [email protected]>
Reviewed by Eric Seidel.
Remove WML https://bugs.webkit.org/show_bug.cgi?id=59678
This patch removes WML from WebCore. After removing WML, there’s a
bunchoftwistedcodethatcouldbeuntwisted,butthispatchcontains
only the purely mechanical part of removing the feature.There’s been a lot of discussion on webkit-dev about whether we should
removeWML.Inadditiontothosethreads,we’vehadaninformalpoll
ofthereviewersaswellasanin-persondiscussionattheWebKit
contributor’smeeting.Removinganyfeatureislikelytomakesome
folksunhappy,but,onbalance,removingWMLappearstobetheright
thing for the project to do at this time.这次的代码提交对应的版本号是85256,移除了WebCore下的WML支持。
2.3.5
_____________________________________________________________________________________________
使用VS2005编译库: 1. 下载Qt源码并解压(qt-win-opensource-src-4.5.3.zip);
2. 安装vs2005,win7自动更新到最新补丁!!!
3. 启动vs2005,选中“工具”,“visual studio 命令提示”
3. 进入解压目录,键入
configure -platform win32-msvc2005 -opensource -nomake examples -nomake demos 4. 编译成功后,在vs2005中打开解压目录下的 project.sln。设置 browser 为启动项目,编译真个工程即可。
如果运行时没找到dll。只要拷贝到同一个目录下执行。
支持wml版本:
1,打开E:\projects\webkit\src\src\3rdparty\webkit\WebCore\WebCore.pro
(最终生成E:\projects\webkit\src\src\3rdparty\webkit\WebCore\QtWebKit.vcproj)
将 !contains(DEFINES, ENABLE_WML=.): DEFINES += ENABLE_WML=0
由0改为1.
2, 用
configure -platform win32-msvc2005 -opensource -nomake examples -nomake demos
编译。
3,
注意使用的编译器是哪个版本的:
E:\projects\webkit\src> configure -platform win32-msvc2005 -opensource -nomake e
xamples-nomakedemos
Foundmorethanoneknowncompiler!Using"Microsoft(R)32-bitC/C++Optimizing
Compiler.NET 2005 (8.0)"This is the Qt for Windows Open Source Edition.
You are licensed to use this software under the terms of
theGNUGeneralPublicLicense(GPL)version3
or the GNU Lesser General Public License (LGPL) version 2.1.Type '3' to view the GNU General Public License version 3 (GPLv3).
Type'L'toviewtheLesserGNUGeneralPublicLicenseversion2.1(LGPLv2.1).
Type'y'toacceptthislicenseoffer.
Type'n'todeclinethislicenseoffer.