转:
对于WAP网站来说我们知道手机的机型适配变得异常重要。在讨论UA前我们看下典型的几个UA的例子:
1)SCH-M609/1.0 POLARIS/5.30.WAP CTC/1.0
2)Mozilla/5.0 (LG-KV755/CH755V05;U;REX/1.0;BREW/3.1.5;240*320;CTC/1.0) Polaris/6.15
3)K-Touch/Windows CE 5.2,Pocket PC Profile/MIDP-2.0 Configuration/CLDC-1.1 /1.0
第一个UA我们通过第一个字串SCH-M609可以知道该手机为三星M609;而第二个UA说明这个浏览器兼容Mozilla 5.0标准,而能识别机型的特征字串LG-KV755并不在UA前面几个字节,这里知道用户的机型为LG KV755。而第三个UA我们只能从K-Touch知道这个是天宇朗通的某款手机,并且操作系统为Windows CE 5.2,不过我们还是无法知道具体是哪个机型。
前面两个UA是我们需要程序识别的,而第三个UA要求程序来识别过于苛刻。即便是为了识别以上两个UA我们面临一个非常大的问题是,从第一、第二两个例子当中我们可以看出,我们无法简单的取第一个斜杠前的数据作为判断的依据。当然我们可以考虑全字符串匹配,但这面临着另外一个问题,尤其针对智能机来说,用户可以安装不同的浏览器,或者这些机器出厂的时候就带了多个浏览器。
下图是我们在WAP网关取到的一些天语E61机型留下的UA数据,例子中我们就选取了个别数据作为说明,实际E61的UA可能多达十几种。我们可以看到基本上如果按全字符串匹配会需要维护非常庞大的数据,并且随着浏览器版本升级,这样的数据会越来越多。
在WAP网关发现天语E61的UA
Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11) TY-E61/V2116 MSIEMobile/6.0 CTC/1.0
Mozilla/5.0 (TY-E61/810118_2190_V3018;U;Windows Mobile/6.1;Profile/MIDP-2.0
Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.0) TY-E61/V0809 MSIEMobile/6.0 CTC/1.0
Mozilla/5.0_(TY-E61/V2116;U;Windows Mobile/6.1;Profile/MIDP-2.0_Configuration/CLDC1.1;;CTC/2.0)_OPERA/9.51
Mozilla/5.0_(TY-E61/V2111;U;WindowsMobile/6.1;Profile/MIDP-2.0_Configuration/CLDC1.1;;CTC/2.0)_OPERA/9.51-
……………………..
当然你觉得这可能是智能机由于安装软件方便,是导致一款机型,不同UA众多的主要原因,不是个例。不过我们同样可以取到三星的非智能手机F539这款机器的UA也接近10种。
在WAP网关发现三星F539的UA
SCH-F539 Infraware/5.30.CU (GUI)/WAP2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,Profile/MIDP-2.0 Configuration/CLDC-1.1,UNTRUSTED/1.0
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,UNTRUSTED/1.0
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.0,UNTRUSTED/1.0
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,Profile/MIDP-2.0 Configuration/CLDC-1.0,UNTRUSTED/1.0
SCH-F539/F539CG17 POLARIS/5.30 CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1
SCH-F539/F539CG17 POLARIS/5.30 CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,Profile/MIDP-2.0 Configuration/CLDC-1.1,UNTRUSTED/1.0
SCH-F539/F539CG17 POLARIS/5.30 CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1,UNTRUSTED/1.0
……………………..
所以我们需要考虑使用某种算法来识别机型,可以明显看出TY-E61,和SCH-F539是最识别机型的最重要数据。我们可能会考虑是否可以用正则表达式进行匹配。不过熟悉程序开发的人很快会想到如果有1000款手机,1000个正则表达式下来,是相当耗费资源的事情。
解决办法其实也相当简单,我们需要的是找出机型的特征串,整理出来如下图表格的数据:
手机型号
特征串
生产厂家
操作系统
分辨率
上市时间
三星F309
SCH-F309
三星
REX
176×220
200812
三星F319
SCH-F319
三星
REX
128×160
200511
三星F539
SCH-F539
三星
REX
240×320
200904
天语E61
TY-E61
天语
Windows Mobile
240×320
200905
酷派N900+
YL-Coolpad_N900+
宇龙酷派
Windows CE
320×480
200912
酷派N900C
YL-COOLPAD_N900C
宇龙酷派
Windows CE
320×480
200911
华为C7100
HUAWEI-C7100
华为
REX
240×320
200809
华为C7168
HUAWEI-C7168
华为
REX
176×220
200609
华为C7188
HUAWEI-C7188
华为
REX
240×320
200712
华为C7189
HUAWEI-C7189
华为
REX
240×320
201004
华为C7200
HUAWEI-C7200
华为
REX
240×320
200802
1) 我们可以考虑将特征串作为某个Hash的key,而Value设置为手机机型,以上数据转换为
Hash:Mobile {
"SCH-F309" => "三星F309";
"SCH-F319" => "三星F319";
"SCH-F539" => "三星F539";
"TY-E61" => "天语E61";
"YL-Coolpad_N900+" => "酷派N900+";
"YL-COOLPAD_N900C" => "酷派N900C";
"HUAWEI-C7100" => "华为C7100";
"HUAWEI-C7168" => "华为C7168";
"HUAWEI-C7188" => "华为C7188";
"HUAWEI-C7189" => "华为C7189";
"HUAWEI-C7200" => "华为C7200";
}
2)将这样的数据可以使用Java Servlet,或者MemCached预先放入内存里面。这个时候就可以对于用户访问WAP网站的UA进行判断。
比如以下UA:
SCH-F539/1.0 POLARIS/5.30.WAP CTC/1.0 Profile/MIDP-2.1 Configuration/CLDC-1.1
我们可以使用空格,斜杠等作为分隔符将以上UA拆分成字符串数组为
{“SCH-F539”,“1.0”,“POLARIS”,“5.30.WAP”,“CTC”,“1.0”,“Profile”,“MIDP-2.1”,“Configuration”,“CLDC-1.1”}
3)这些字串分别作为Key到内存Hash里面取值,我们会发现仅仅字串“SCH-F539”会取到数据为:“三星F539”,而其他Key取到的都为Null;这样我们就可以判断机型为:三星F539
4 ) 同样的我们也可以将生产厂家,操作系统,分辨率,上市日期这些值作为内存Hash,这样我们就可以取到其他该机型的其他必要数据。
User-Agent(简称UA)是HTTP请求头部用来标识客户端信息的字符串, 包括操作系统, 浏览器等信息. 为了建立手机客户端的信息数据库, 需要从手机的http请求中取到这一字符串.
iPhone中取到UA信息的方法如下:
1. 利用浏览器控件UIWebView建立一个http请求
2. 在请求建立的期间, 建立一个新的事件循环用来判断UA信息是否已经建立
3. 在发送http请求之前截获UA信息, 并且取消这一http请求;)
获取iPhone UA的代码如下:
- UIWebView *_webView;
- NSString *userAgent;
- - (void)createHttpRequest {
- _webView = [[UIWebView alloc] init];
- _webView.delegate=self;
- [_webView loadRequest:[NSURLRequest requestWithURL:
- [NSURL
URLWithString:@"http://www.google.com"]]]; - NSLog(@"%@", [self userAgentString]);
- [_webViewrelease];
- }
- -(NSString *)userAgentString
- {
- while (self.userAgent ==nil)
- {
- NSLog(@"%@", @"in while");
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- return self.userAgent;
- }
- -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithReque
st:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType - {
- if (webView ==_webView) {
- self.userAgent = [requestvalueForHTTPHeaderField:@"User-Agent"];
- // Return no, we don't care about executing an actual request.
- returnNO;
- }
- return YES;
- }
- - (void)dealloc {
- [userAgentrelease];
-
[superdealloc]; - }
程序在iPhone4.1模拟器中运行结果如下:
2010-12-21 12:52:38.302 UATest[6722:207] in while
2010-12-21 12:52:38.305 UATest[6722:207] in while
2010-12-21 12:52:38.307 UATest[6722:207] in while
2010-12-21 12:52:38.307 UATest[6722:207] in while
2010-12-21 12:52:38.308 UATest[6722:207] in while
2010-12-21 12:52:38.309 UATest[6722:207] in while
2010-12-21 12:52:38.312 UATest[6722:207] Mozilla/5.0 (iPhone Simulator; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Mobile/8B117
Android中获取UA的方法如下:
1. 建立一个WebView可以从中得到WebSettings
2. WebSettings这个类有个getUAString函数
Android中获取UA的代码如下:
1
2
3
4
5
6
Nexus One手机中测试结果UA如下:
Mozilla/5.0 (Linux; U;
getUserAgent的源码如下:
991
992
993
994
995
996
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1010
1011
1012
296
298
299
300
301
302
303
304
306
307
309
311
312
313
314
315
317
318
319
320
322
324
328
329
333
334
335
336
337
和源码比较后可以看出, android的UA字符串包括: 基本信息+版本号+国家语言+型号+型号ID+浏览器信息
其中,
基本信息:
"Mozilla/5.0 (Linux; U;Android "
浏览器信息:
AppleWebKit/533.1 (KHTML, likeGecko) Version/4.0Mobile Safari/533.1
这两部分并没有源码可寻, 说明android的开源并不彻底.
参考资料:
一个android在线源码的地址: