Android浏览器Browser二次开发(二)支持WML

第二章 修改浏览器使之支持WML格式页面。 
对于移动终端,有时候服务器返回的是WML格式的页面。 比如说中国移动的一些需要使用cmwap接入点的业务页面(DCD, 移动梦网), 这就要求终端浏览器必须能够支持对WML格式页面的解析和显示。 Android原始代码里的webkit层虽然提供了WML相关的解析类,但是并没有很好地支持,所以在页面上无法正确显示。 我们需要做以下一些修改: 
1. 打开对WML格式解析的通道 
修改源码的\external\webkit\WebCore\dom\DOMImplementation.cpp 
获取到服务器返回的数据中的content-type字段值后,会调用这个类里面的isXMLMIMEType()方法来判断是否按照XML格式来解析。我们看这个方法: 
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) return true; 

修改framework/base/core/java/android/webkit/LoadListener.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中的超链接元素(WMLAElementWMLAnchorElement)href属性值里面的变量替换。 
笔者发现,在一个WML的登陆页面上,填入用户名和密码后,点击登陆,附加到url后面的用户名和密码是$(username) $(password) ,有web开发经验的XDJM都知道,这是没有将变量替换为页面上相应值。我们看WMLAElement.cpp中处理点击事件的方法: 
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,不需要我们再去写一个了。修改如下 
#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页面被忽略了。 返回的hrefnull. 
首先要在WMLAElement.cpp中提供接口, 返回链接。 
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的方法是这样的: 
WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node) 

WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node); 
return anchor ? anchor->href() : WebCore::String(); 

在这里增加WML的支持, 修改如下: 
/**add WML anchor support. 20110224, begin**/ 
#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(); 

还有获取链接标题的方法,修改如下: 
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, 包含了xhtmlxml两种格式。而CMCC的数据本身又不是严格按照W3C标准来的, 导致在解析的时候出现了语法错误提示。 对于这种情况,我们显然无法去要求CMCC改变数据, 只能把这种格式当做普通的html来显示, html没有那么严格的语法检查, 可以正常显示。修改framework/base/core/java/android/webkit/LoadListener.java: 
// Does the header parsing work on the WebCore thread. 
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"; 
}  

摘自:http://seya.iteye.com/blog/931289 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值