事情的起因是这样的,因为需要在Email的显示界面中为电话号码添加高亮显示,从而提高用户体验。我想用过google自带邮箱的朋友都知道,当我们的收到邮件的内容中含有网址,邮箱地址时,会在显示界面中以超链接的方式显示,此时当我们点击该网址或者邮箱地址时,便会弹出浏览器或者撰写邮件。目前的情况是,当我们的邮件内容中含有可识别的电话号码时,我们可以点击并跳转到拨号界面,但却不能高亮显示,因此我们的目标就是将电话号码修改为高亮显示,如下图1:
图1:修改后的效果
那么我们还是列出我们的目的吧,以免忘记(我就容易忘记:D)。
目标:将接收邮件内容中的电话号码高亮显示。
因为自己也是第一次接触邮件这块,因此可能走了很多弯路或者说的并不清除,请别见笑,如果后文中有错误还恳请各位朋友指正。毕竟,没有人一生下来就是老鸟!!!
好了废话不多说,开始吧!
1.找到问题的根源
需要修改的Email读取邮件的界面,当我看到该界面的时候第一反应,这货应该是一个TextView,用于撰写Email的界面应该是一个EditText。毕竟TextView用于显示这些内容足够了啊,进而联想到xml布局文件中的android:autoLink属性,只要为该TextView控件加上该属性则在TextView中的网址,邮件地址,电话号码等自动会变为超链接(不信的可以自己试试)。有了这个思路那么我们首先应该找到显示邮件内容的布局文件(这里提一下,1.如果像我等小白的话可能就会老老实实的去找packages/apps/Email/res/layout,然后再去看哪个名字像是显示内容的,比如:Mmessage_content.xml这种就很像,我一开始就是这么找的T_T。2.如果以前看过源码的朋友估计会通过查看该APP的应用程序入口,然后根据如果跳转到邮件显示Activity最后再搜索setContentView方法就可以知道其布局文件。3.其实其实,SDK/tools文件夹下真的有好多有用的东西——hierarchyviewer就是其中之一,我们只要运行该工具同时连接上我们的设备,也可以是模拟器,该工具会自动列出当前界面的布局状态,如图2所示)。
图2 hierarchyviewer显示
我用的是Ubuntu10.04 64bit 在windows下都差不多的,hierarchyviewer存放在SDK下的tools目录中,通过hierarchyviewer我可轻松的分析该界面的布局状态。鼠标左键选中以上布局文件时,右边界面中会有提示。因此在这里我们可以很轻松的将我们前面的假设推翻,显示界面根本就不是什么TextView而是WebView(小白就是小白啊T_T)。怎么会是WebView呢,稍稍做过web开发的人都知道的吧,我们要在界面中显示图片,超链接,邮件等等,这些东西如果要放到TextView中去做???很明显应该选择WebView嘛,同时我们从服务其获得的信息就是html字符串(后文会提到)。因此前面的问题就变成了在WebView中对电话号码进行高亮显示。
2.查看源代码
Linux之父Linus曾说过,要了解程序原理的最好方法就是——Read the fucking source code.好吧,通过查看程序入口,然后跳转到显示界面这些步骤省略,最终我们找到/packages/apps/Email/src/com/android/email/activity/MessageView.java,该类主要完成消息内容的显示。那么如何开始查看呢?因为我们主要关心的WebView的设置,因此我们可以直接搜索WebView来查看,结果全文中只有一个WebView:
private WebView mMessageContentView;
mMessageContentView.setClickable(true);
mMessageContentView.setLongClickable(false); // Conflicts with ScrollView, unfortunately
mMessageContentView.setVerticalScrollBarEnabled(false);
mMessageContentView.getSettings().setBlockNetworkLoads(true);
mMessageContentView.getSettings().setSupportZoom(false);
mMessageContentView.setWebViewClient(new CustomWebViewClient());
这里对该WebView对象进行了一些设置。
(1).setClickable(true)是设置WebView可点击;
(2).setLongClickable(false)是该WebView不支持长点击事件,这是因为会和ScrollView冲突,因此将其设置位false,可以在ScrollView中处理长点击事件;
(3).setVerticalScrollBarEnabled(false)接着设置垂直方向滚动禁止,也是和ScrollView冲突;
(4).setBlcokNetworkLoads(true)设置是否阻止网络加载,如果邮件中含有图片则会打开该属性;
(5).setSupportZoom(false)这是设置当前WebView不支持缩放;
(6).setWebViewClient使WebView接收到各种通知和请求;
接下来我们继续查找mMessageContentView可以发现mMessageContentView.loadDataWithBaseURL(...)方法,通过命名我们可以知道该方法用于加载URL同时,其中的参数很是奇怪,有text,mHtmlTextWebView等,这些东西是什么呢,果断加入Log.i("TAG","text:"+text);将这些信息通过log.i输出来,加入这些代码之后单独编译Email并将修改之后的Email.apk push到/system/app路径下实践,根据打印出来的log我们可以初步将目光锁定到:
/**
* Reload the body from the provider cursor. This must only be called from the UI thread.
*
* @param bodyText text part
* @param bodyHtml html part
*
* TODO deal with html vs text and many other issues
*/
private void reloadUiFromBody(String bodyText, String bodyHtml) {
String text = null;
mHtmlTextRaw = null;
boolean hasImages = false;
if (bodyHtml == null) {
text = bodyText;
/*
* Convert the plain text to HTML
*/
StringBuffer sb = new StringBuffer("");
if (text != null) {
// Escape any inadvertent HTML in the text message
text = EmailHtmlUtil.escapeCharacterToDisplay(text);
// Find any embedded URL's and linkify
Matcher m = Patterns.WEB_URL.matcher(text);
while (m.find()) {
int start = m.start();
/*
* WEB_URL_PATTERN may match domain part of email address. To detect
* this false match, the character just before the matched string
* should not be '@'.
*/
if (start == 0 || text.charAt(start - 1) != '@') {
String url = m.group();
Matcher proto = WEB_URL_PROTOCOL.matcher(url);
String link;
if (proto.find()) {
// This is work around to force URL protocol part be lower case,
// because WebView could follow only lower case protocol link.
link = proto.group().toLowerCase() + url.substring(proto.end());
} else {
// Patterns.WEB_URL matches URL without protocol part,
// so added default protocol to link.
link = "http://" + url;
}
String href = String.format("%s", link, url);
m.appendReplacement(sb, href);
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
}
sb.append("");
text = sb.toString();
} else {
text = bodyHtml;
mHtmlTextRaw = bodyHtml;
hasImages = IMG_TAG_START_REGEX.matcher(text).find();
}
mShowPicturesSection.setVisibility(hasImages ? View.VISIBLE : View.GONE);
if (mMessageContentView != null) {
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
}
// Ask for attachments after body
mLoadAttachmentsTask = new LoadAttachmentsTask();
mLoadAttachmentsTask.execute(mMessage.mId);
}
(1).bodyText是对方通过Android邮箱给你发送邮件时,我们接收到的邮件信息是bodyText,不带Html标签;
(2).bodyHtml是通过网络邮箱发送时,我们接收到的信息是bodyHtml,带有Html标签;
根据打印出来的log信息我们可以看到:
http://www.baidu.com
[email protected]
3.深入分析并实现功能
有以上的分析,我们便可以开始动作实践了。但是问题又来了,要实现电话号码高亮的功能我们需要两个条件,第一,用于匹配电话号码的正则表达式,用于匹配邮件内容中的电话号码;第二,因为网址和邮件的高亮都有自己特殊的标志(邮件对应的是mailto),那么电话号码会不会也有对应的标志呢?在进一步分析前,我们先回过头想一想。虽然在邮件中我们的电话号码没有高亮,但是我们依然可以点击该号码跳转到拨号界面啊。也就是说该程序是识别到了电话号码的,只是没有高亮显示而已。继续分析,前面我们提到了,邮件显示网址和邮箱地址这些都是经过了正则匹配的(前面代码中),也就是匹配之后才知道是否为网址和邮箱地址。那么既然电话号码可以拨打肯定也是经过了正则匹配的。分析到这里,我们所需要的的两个条件之一已经基本解决,剩下的就是去找到已经定义好的电话号码匹配正则表达式。那么第二个问题呢?看似没有思路啊(0.0)!没关系,我们先来看看以下代码吧:
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String historyUrl) {
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
loadData(data, mimeType, encoding);
return;
}
switchOutDrawHistory();
WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
arg.mBaseUrl = baseUrl;
arg.mData = data;
arg.mMimeType = mimeType;
arg.mEncoding = encoding;
arg.mHistoryUrl = historyUrl;
mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
clearHelpers();
}
在该方法中将传入的参数封装到了BaseUrlData对象arg中,然后通过sendMessage()方法将arg对象发送出去。
void sendMessage(int what, Object obj) {
mEventHub.sendMessage(Message.obtain(null, what, obj));
}
private synchronized void sendMessage(Message msg) {
if (mBlockMessages) {
return;
}
if (mMessages != null) {
mMessages.add(msg);
} else {
mHandler.sendMessage(msg);
}
}
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, (msg.what < REQUEST_LABEL
|| msg.what
> VALID_NODE_BOUNDS ? Integer.toString(msg.what)
: HandlerDebugString[msg.what
- REQUEST_LABEL])
+ " arg1=" + msg.arg1 + " arg2=" + msg.arg2
+ " obj=" + msg.obj);
}
switch (msg.what) {
case WEBKIT_DRAW:
webkitDraw();
break;
...
case LOAD_DATA:
BaseUrlData loadParams = (BaseUrlData) msg.obj;
String baseUrl = loadParams.mBaseUrl;
if (baseUrl != null) {
int i = baseUrl.indexOf(':');
if (i > 0) {
/*
* In 1.0, {@link
* WebView#loadDataWithBaseURL} can access
* local asset files as long as the data is
* valid. In the new WebKit, the restriction
* is tightened. To be compatible with 1.0,
* we automatically add the scheme of the
* baseUrl for local access as long as it is
* not http(s)/ftp(s)/about/javascript
*/
String scheme = baseUrl.substring(0, i);
if (!scheme.startsWith("http") &&
!scheme.startsWith("ftp") &&
!scheme.startsWith("about") &&
!scheme.startsWith("javascript")) {
nativeRegisterURLSchemeAsLocal(scheme);
}
}
}
mBrowserFrame.loadData(baseUrl,
loadParams.mData,
loadParams.mMimeType,
loadParams.mEncoding,
loadParams.mHistoryUrl);
break;
...
case START_DNS_PREFETCH:
mBrowserFrame.startDnsPrefetch();
break;
}
}
};
到这里似乎没有眉目了啊。我们是想找到href中关于电话号码的关键词,这样可以使电话号码高亮显示,但跟踪到这里似乎并不能得到有用的信息。但我们可以知道,WebView的最终显示是通过将数据传递到JNI再到底层去实现的,有兴趣的朋友可以自己再去跟踪下。这里的nativeRegisterURLSchemeAsLocal位于external/webkit/WebKit/android/jni/WebViewCore.cpp中,对应的native方法是RegisterRULSchemeAsLocal()。继续跟踪可以跳转到/external/webkit/WebCore/page/SecurityOrigin.cpp中的SecurityOrigin::registerURLSchemeAsLocal()方法。后续没有再继续跟踪了,毕竟本人小菜一个,后面再进一步学习吧。
3.峰回路转柳暗花明
在前面饶了一大圈,头也晕了,我们还是整理整理思路吧。1.我们想找到设置电话号码高亮的标签(类似邮件的href=mailto)。2.找到用于匹配电话号码的正则表达式。经过了前面的查找,我们似乎还是无法找到电话号码的标签位。那我们换一下,这次先找匹配电话号码的正则表达式。首先,我们在代码:
private void reloadUiFromBody(String bodyText, String bodyHtml) {
String text = null;
mHtmlTextRaw = null;
boolean hasImages = false;
if (bodyHtml == null) {
text = bodyText;
/*
* Convert the plain text to HTML
*/
StringBuffer sb = new StringBuffer("");
if (text != null) {
// Escape any inadvertent HTML in the text message
text = EmailHtmlUtil.escapeCharacterToDisplay(text);
// Find any embedded URL's and linkify
Matcher m = Patterns.WEB_URL.matcher(text);
while (m.find()) {
int start = m.start();
/*
* WEB_URL_PATTERN may match domain part of email address. To detect
* this false match, the character just before the matched string
* should not be '@'.
*/
if (start == 0 || text.charAt(start - 1) != '@') {
String url = m.group();
Matcher proto = WEB_URL_PROTOCOL.matcher(url);
String link;
if (proto.find()) {
// This is work around to force URL protocol part be lower case,
// because WebView could follow only lower case protocol link.
link = proto.group().toLowerCase() + url.substring(proto.end());
} else {
// Patterns.WEB_URL matches URL without protocol part,
// so added default protocol to link.
link = "http://" + url;
}
String href = String.format("%s", link, url);
m.appendReplacement(sb, href);
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
}
sb.append("");
text = sb.toString();
} else {
text = bodyHtml;
mHtmlTextRaw = bodyHtml;
hasImages = IMG_TAG_START_REGEX.matcher(text).find();
}
mShowPicturesSection.setVisibility(hasImages ? View.VISIBLE : View.GONE);
if (mMessageContentView != null) {
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
}
// Ask for attachments after body
mLoadAttachmentsTask = new LoadAttachmentsTask();
mLoadAttachmentsTask.execute(mMessage.mId);
}
public static final Pattern PHONE
= Pattern.compile( // sdd = space, dot, or dash
"(\\+[0-9]+[\\- \\.]*)?" // +*
+ "(\\([0-9]+\\)[\\- \\.]*)?" // ()*
+ "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // +
mMessageContentView.setWebViewClient(new CustomWebViewClient());
private class CustomWebViewClient extends WebViewClient {
/**
* This is intended to mirror the operation of the original
* (see android.webkit.CallbackProxy) with one addition of intent flags
* "FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET". This improves behavior when sublaunching
* other apps via embedded URI's.
*
* We also use this hook to catch "mailto:" links and handle them locally.
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// hijack mailto: uri's and handle locally
if (url != null && url.toLowerCase().startsWith("mailto:")) {
return MessageCompose.actionCompose(MessageView.this, url, mAccountId);
}
// Handle most uri's via intent launch
boolean result = false;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
try {
startActivity(intent);
result = true;
} catch (ActivityNotFoundException ex) {
// If no application can handle the URL, assume that the
// caller can handle it.
}
return result;
}
}
4.最终实现
private void reloadUiFromBody(String bodyText, String bodyHtml) {
String text = null;
mHtmlTextRaw = null;
boolean hasImages = false;
if (bodyHtml == null) {
text = bodyText;
/*
* Convert the plain text to HTML
*/
StringBuffer sb = new StringBuffer("");
if (text != null) {
// Escape any inadvertent HTML in the text message
text = EmailHtmlUtil.escapeCharacterToDisplay(text);
// Find any embedded URL's and linkify
Matcher m = Patterns.WEB_URL.matcher(text);
while (m.find()) {
int start = m.start();
/*
* WEB_URL_PATTERN may match domain part of email address. To detect
* this false match, the character just before the matched string
* should not be '@'.
*/
if (start == 0 || text.charAt(start - 1) != '@') {
String url = m.group();
Matcher proto = WEB_URL_PROTOCOL.matcher(url);
String link;
if (proto.find()) {
// This is work around to force URL protocol part be lower case,
// because WebView could follow only lower case protocol link.
link = proto.group().toLowerCase() + url.substring(proto.end());
} else {
// Patterns.WEB_URL matches URL without protocol part,
// so added default protocol to link.
link = "http://" + url;
}
String href = String.format("%s", link, url);
m.appendReplacement(sb, href);
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
}
sb.append("");
text = sb.toString();
text = highLight(ALL, text);
} else {
text = bodyHtml;
text = highLight(PHONENUM, text);
mHtmlTextRaw = bodyHtml;
hasImages = IMG_TAG_START_REGEX.matcher(text).find();
}
mShowPicturesSection.setVisibility(hasImages ? View.VISIBLE : View.GONE);
if (mMessageContentView != null) {
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
}
// Ask for attachments after body
mLoadAttachmentsTask = new LoadAttachmentsTask();
mLoadAttachmentsTask.execute(mMessage.mId);
}
private void reloadUiFromBody(String bodyText, String bodyHtml) {
String text = null;
mHtmlTextRaw = null;
boolean hasImages = false;
if (bodyHtml == null) {
text = bodyText;
/*
* Convert the plain text to HTML
*/
StringBuffer sb = new StringBuffer("");
if (text != null) {
// Escape any inadvertent HTML in the text message
text = EmailHtmlUtil.escapeCharacterToDisplay(text);
// Find any embedded URL's and linkify
Matcher m = Patterns.WEB_URL.matcher(text);
while (m.find()) {
int start = m.start();
/*
* WEB_URL_PATTERN may match domain part of email address. To detect
* this false match, the character just before the matched string
* should not be '@'.
*/
if (start == 0 || text.charAt(start - 1) != '@') {
String url = m.group();
Matcher proto = WEB_URL_PROTOCOL.matcher(url);
String link;
if (proto.find()) {
// This is work around to force URL protocol part be lower case,
// because WebView could follow only lower case protocol link.
link = proto.group().toLowerCase() + url.substring(proto.end());
} else {
// Patterns.WEB_URL matches URL without protocol part,
// so added default protocol to link.
link = "http://" + url;
}
String href = String.format("%s", link, url);
m.appendReplacement(sb, href);
}
else {
m.appendReplacement(sb, "$0");
}
}
m.appendTail(sb);
}
sb.append("");
text = sb.toString();
text = highLight(ALL,text);//全部高亮,highLight的参数有三种PHONENUM,EMAILADDRESS,WEBURL
} else {
text = bodyHtml;
text = highLight(ALL,text);//为什么这里会是ALL?!后文会有讲解
mHtmlTextRaw = text;//这里也要注意修改哦 不然后面点击显示图片后文中的电话号码高亮会消失的哦:-)
hasImages = IMG_TAG_START_REGEX.matcher(text).find();
}
mShowPicturesSection.setVisibility(hasImages ? View.VISIBLE : View.GONE);
if (mMessageContentView != null) {
mMessageContentView.loadDataWithBaseURL("email://", text, "text/html", "utf-8", null);
}
// Ask for attachments after body
mLoadAttachmentsTask = new LoadAttachmentsTask();
mLoadAttachmentsTask.execute(mMessage.mId);
}
/**
* high light the telephone number and web url and email address.
* @author http://blog.csdn.net/yihongyuelan
* @param TYPE contains PHONENUM,EMAILADDRESS,WEBURL,ALL
* @return String which has been replaced
*/
public String highLight(int TYPE,String text){
replacedString = text;//这里的replacedString是全局变量
String replaceElement = "";//表示需要处理的元素电话号码用"tel:"表示,同样,邮件是"mailto:" web url则是""(空)
switch (TYPE) {
case PHONENUM://只对电话号码进行高亮处理
pattern = Patterns.PHONE ;//用于正则匹配phone的patterns
matcher = pattern.matcher(replacedString);
replaceElement = PHONE_HIGHLIGHT_ELEMENT;
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);//主要的替换方法
matcher = getMatcher(replacedString);
}
FLAG = true;
break;
case EMAILADDRESS://只对邮件地址号码进行高亮处理
pattern = Patterns.EMAIL_ADDRESS ;
matcher = pattern.matcher(replacedString);
replaceElement = EMAILADDRESS_HIGHLIGHT_ELEMENT ;
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);
matcher = getMatcher(replacedString);
}
FLAG = true;
break;
case WEBURL://只对web url进行高亮处理
pattern = Patterns.WEB_URL;
matcher = pattern.matcher(replacedString);
replaceElement = WEBURL_HIGHLIGHT_ELEMENT;
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);
matcher = getMatcher(replacedString);
}
FLAG = true;
break;
case ALL://只对以上三者进行高亮处理
pattern = Patterns.PHONE;
replaceElement = PHONE_HIGHLIGHT_ELEMENT;
matcher = pattern.matcher(replacedString);
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);
matcher = getMatcher(replacedString);
}
FLAG = true;
pattern = Patterns.EMAIL_ADDRESS;
replaceElement = EMAILADDRESS_HIGHLIGHT_ELEMENT;
matcher = pattern.matcher(replacedString);
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);
matcher = getMatcher(replacedString);
}
FLAG = true;
pattern = Patterns.WEB_URL;
replaceElement = WEBURL_HIGHLIGHT_ELEMENT;
matcher = pattern.matcher(replacedString);
while(FLAG){
replacedString = replaceKeyString(matcher,replaceElement);
matcher = getMatcher(replacedString);
}
FLAG = true;
default:
break;
}
return replacedString;
}
/**
* replace the key String.
* @author http://blog.csdn.net/yihongyuelan
* @param matcher Matcher
* @param mReplaceElement replace element "" or "tel:" or "mailto:"
* @return replacedString text has been replaced
*/
public String replaceKeyString(Matcher matcher, String mReplaceElement) {
String replaceElement = mReplaceElement;
String keyString = "";
String result = replacedString;
while (matcher.find()) {
keyString = matcher.group();
if (WEBURL_HIGHLIGHT_ELEMENT.equals(replaceElement)) {//在匹配web url时处理
int endUrl = matcher.start();
int startUrl = endUrl - 7;
if (startUrl > 0) {
String hrefStr = result.substring(startUrl, endUrl);
if (hrefStr.contains("href")) {
continue;//如果包含href说明已经处理过了,不再处理
}
}
int endSrc = matcher.start();
int startSrc = endSrc - 6;
if (startSrc > 0) {
String srcStr = result.substring(startSrc, endSrc);
if (srcStr.contains("src")) {
continue;//如果包含src说明是资源引用,不属于需要高亮的web url
}
}
int endXMLNS = matcher.start();
int startXMLNS = endXMLNS - 14;
if (startXMLNS > 0) {
String xmlnsStr = result.substring(startXMLNS, endXMLNS);
if (xmlnsStr.contains("xmlns")) {
continue;//命名空间需要高亮
}
}
int endStr = matcher.start() - 2;
int startStr = endStr - keyString.length();
if (startStr > 0) {
String webStr = result.substring(
endStr - keyString.length(), endStr);
if (keyString.contains(webStr)) {
continue;//已经处理过的不再需要处理
}
}
if(matcher.start()-1 >=0 && result.charAt(matcher.start()-1) == '@'){
continue;//不出里邮件格式如[email protected]
}
if(keyString.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")){
continue;不出里数字格式 ru 10.128.10.10
}
String url = keyString;
String link;
int start = matcher.start();
int end = start + 4;
String flagStr = result.substring(start, end);
if(!flagStr.contains("http") && !flagStr.contains("Http")
&& !flagStr.contains("HTTP") && !flagStr.contains("ftp")
&& !flagStr.contains("Ftp") && !flagStr.contains("FTP")
&& !flagStr.contains("rtsp") && !flagStr.contains("Rtsp")
&& !flagStr.contains("RTSP")){
link = "http://" + url;
String href = String.format("%s", link, url);
result = result.substring(0, matcher.start())+href+result.substring(matcher.end());
return result;//如果不包含http等的url 如www.baidu.com
}
}
if (PHONE_HIGHLIGHT_ELEMENT.equals(replaceElement)) {//在匹配电话号码时处理
if (4 == keyString.length()) {//低于4个数字的不处理
continue;
}
if (matcher.start() - 1 >= 0) {//数字前面含有@ - 等特殊字符的不处理
char keyChar = result.charAt(matcher.start() - 1);
if (keyChar == 45 || keyChar == 47 || keyChar == 61 || keyChar == 63
|| (35 <= keyChar && keyChar <= 38)) {
continue;
}
}
int end = matcher.start();
int start = end - 8;
if (start < 0) {
start = end - 7;
}
if(start>=0){//不处理数字前面以http之类开头的 如http://10.128.12.211
String urlStr = result.substring(start, end);
if (urlStr.contains("http") || urlStr.contains("Http")
|| urlStr.contains("HTTP") || urlStr.contains("ftp")
|| urlStr.contains("Ftp") || urlStr.contains("FTP")
|| urlStr.contains("rtsp") || urlStr.contains("Rtsp")
|| urlStr.contains("RTSP")) {
continue;
}
}
if (matcher.end() != result.length()) {//数字后面有字母包括或者@的不处理
char keyChar = result.charAt(matcher.end());
if ((64 <= keyChar && keyChar <= 122)
|| keyChar == 95) {
continue;
}
}
if (keyString.matches("\\d{1,4}\\-\\d{1,2}\\-\\d{1,2}(\\s\\d{1,2})?")) {//日期不处理
continue;
}
if(keyString.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")){//如 10.120.121.22不处理
continue;
}
int endPhone = matcher.start();
int startPhone = endPhone - 4;
String emailStr = result.substring(startPhone, endPhone);
if (emailStr.contains("tel")) {//包含tel标志的 不处理
continue;
}
int endStr = matcher.start() - 2;
int startStr = endStr - keyString.length();
if (startStr > 0) {
String webStr = result.substring(endStr - keyString.length(), endStr);
if (keyString.contains(webStr)) {
continue;//已经处理过的不再处理
}
}
}
if (EMAILADDRESS_HIGHLIGHT_ELEMENT.equals(replaceElement)) {//匹配邮件地址时
int endEmail = matcher.start();
int startEmail = endEmail - 7;
String emailStr = result.substring(startEmail, endEmail);
if (emailStr.contains("mailto")) {//已经有mailto标志的 不再匹配
continue;
}
int endStr = matcher.start() - 2;
int startStr = endStr - keyString.length();
if (startStr > 0) {
String webStr = result.substring(endStr - keyString.length(), endStr);
if (keyString.contains(webStr)) {
continue;//已经处理国的不再处理
}
}
}
String replacement = "" + keyString + "";//开始替换
result = result.substring(0, matcher.start())+replacement+result.substring(matcher.end());
return result;
}
FLAG = false;
return result;
}
/**
* construct the matcher.
* @author http://blog.csdn.net/yihongyuelan
* @param String to construct matcher
* @return matcher
*/
public Matcher getMatcher(String str) {
Matcher matcher = pattern.matcher(str);
return matcher;
}
针对以上代码做下简单的分析,其实代码的功能就是将找到需要替换的字符串然后在替换。比如,原:"你好,这是简单123的测试",替换:"你好,这是简单的测试"。
5.总结
经过了各种纠结,总算完成了需要的功能了。在此也小小的总结以下,对于SDK里面提供的工具自己还是应该多熟悉以下。其次应该使用StarUML将代码执行流程图画出来,这样一来直观而来也便于交流。最后,对于这种总结自己应该多做一些,一方面可以督促自己尽量去搞懂,另一方面也可以检查自己的知识漏洞。