UIWebView是iOS开发中经常使用的一个视图控件,多数状况下,它被用来显示HTML格式的内容。html
除了HTML之外,UIWebView还支持iWork, Office等文档格式:jquery
载入这些文档的方法也和html同样:ios
1
2
3
4
|
NSString *path = [[NSBundle mainBundle] pathForResource:
"test.doc"
ofType:nil];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
|
移动设备浏览器的功能愈来愈强大,包括对HTML五、CSS3的支持,提供丰富的JavaScript API用于调用设备各类功能,使得开发出来的Web App很是接近原生App。git
HTML5技术有以下优势:github
固然,HTML5也有它的缺点:web
随着HTML5的流行,出现了许多优秀的HTML5框架,它们可使开发变得更加简单,进一步提升开发效率:apache
Native App须要较高的技术水平,虽然性能优越用户体验较好,但跨平台兼容性差,并且开发、维护成本过高,难以适应快速更新的需求变化;而Web App技术门槛低,良好的跨平台兼容性,开发、维护成本低,可是性能低致使用户体验较差。浏览器
Native App开发方法适合于游戏等须要良好用户体验的应用,而Web App开发方法适合没有太多交互的应用。这两种方法就像两个极端,而通常性应用并非特别须要其中一种方法带来的好处,因而就产生告终合这两种开发方法的折中方案:Hybrid开发方法。app
针对通常性应用,使用Hybrid开发方法,开发者就能使用跨平台的HTML5技术开发大部分的应用程序代码,又能在须要的时候使用一些设备的功能,充分结合了Native App开发方法和Web App开发方法的长处,在提供良好用户体验的同时,大大下降开发和维护的成本以及提升效率。框架
Hybrid开发方式也有一些框架/工具:
其中,Xamarin能够采用纯C#代码开发iOS/Android应用。而PhoneGap则是针对不一样平台的WebView进行封装和扩展,使开发人员能够经过Javascript访问设备的一些功能。
固然,使用这些框架/工具须要必定的学习成本,若是对Objective-C和HTML5相关技术比较熟悉,也能够彻底不用依赖于这些框架进行开发。
UIWebView提供了stringByEvaluatingJavaScriptFromString方法,它将Javascript代码嵌入到页面中运行,并将运行结果返回。
1
2
3
4
|
NSString *result1 = [webView stringByEvaluatingJavaScriptFromString:@
"alert('lwme.cnblogs.com');"
];
// 弹出提示,无返回值
NSString *result2 = [webView stringByEvaluatingJavaScriptFromString:@
"location.href;"
];
// 返回页面地址
NSString *result3 = [webView stringByEvaluatingJavaScriptFromString:@
"document.getElementById('lwme').innerHTML;"
];
// 返回页面某个标记内容
NSString *result4 = [webView stringByEvaluatingJavaScriptFromString:@
"document.getElementById('lwme').innerHTML = 'lwme.cnblogs.com';"
];
// 设置页面某个标记内容
|
须要注意的是:
另外须要注意,运行部分脚本时须要肯定页面是否加载完成(DOMContentLoaded)。
固然,stringByEvaluatingJavaScriptFromString只是Native向UIWebView中的网页单向的通讯,UIWebView中的网页向Native通讯则须要经过UIWebView的协议webView:shouldStartLoadWithRequest:navigationType:
。
首先,建立一个文件命名为test.html,内容以下:
<a href="js-call://test/lwme.cnblogs.com">测试</a> <a href="js-call://other/lwme.cnblogs.com">测试2</a>
而后,在Native实现以下代码:
@interface LwmeTestViewController ()<UIWebViewDelegate> @end @implementation LwmeTestViewController - (void)viewDidLoad { [super viewDidLoad]; // 设置delegate并加载html self.webView.delegate = self; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"]; NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [self.webView loadHTMLString:fileContent baseURL:nil]; } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *requestString = [[request URL] absoluteString]; NSString *protocol = @"js-call://"; if ([requestString hasPrefix:protocol]) { NSString *requestContent = [requestString substringFromIndex:[protocol length]]; NSArray *vals = [requestContent componentsSeparatedByString:@"/"]; if ([vals[0] isEqualToString:@"test"]) { //test方法 [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"alert('地址:%@');", vals[1]]]; } else { [webView stringByEvaluatingJavaScriptFromString:@"alert('未定义');"]; } return NO; // 对于js-call://协议不执行跳转 } return YES; }
这样就完成了简单的通讯,UIWebView中的网页须要访问设备的功能均可以在webView:shouldStartLoadWithRequest:navigationType:
编写相应的代码来实现。
iOS 6以上版本的Mobile Safari支持在网页中调用摄像头,只须要放置如下代码:
<input type="file" capture="camera" accept="image/*" id="cameraInput">
可是iOS 5的浏览器还不支持这个功能,若是须要调用摄像头,则依然须要经过Hybrid开发方式来实现。
首先,建立一个文件命名为camera.html,定义三个按钮分别用于获取摄像头、图库、相册:
<script> function cameraCallback(imageData) { var img = createImageWithBase64(imageData); document.getElementById("cameraWrapper").appendChild(img); } function photolibraryCallback(imageData) { var img = createImageWithBase64(imageData); document.getElementById("photolibraryWrapper").appendChild(img); } function albumCallback(imageData) { var img = createImageWithBase64(imageData); document.getElementById("albumWrapper").appendChild(img); } function createImageWithBase64(imageData) { var img = new Image(); img.src = "data:image/jpeg;base64," + imageData; img.style.width = "50px"; img.style.height = "50px"; return img; } </script> <p style="text-align:center;padding:20px;"> <a href="js-call://camera/cameraCallback">拍照</a> <a href="js-call://photolibrary/photolibraryCallback">图库</a> <a href="js-call://album/albumCallback">相册</a> </p> <fieldset> <legend>拍照</legend> <div id="cameraWrapper"> </div> </fieldset> <fieldset> <legend>图库</legend> <div id="photolibraryWrapper"> </div> </fieldset> <fieldset> <legend>相册</legend> <div id="albumWrapper"> </div> </fieldset>
Native实现代码以下:
#import "LwmeViewController.h" #import "NSData+Base64.h" // Base64代码从 http://svn.cocoasourcecode.com/MGTwitterEngine/NSData+Base64.h 和 http://svn.cocoasourcecode.com/MGTwitterEngine/NSData+Base64.m 获取 @interface LwmeViewController ()<UIWebViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate> { NSString *callback; // 定义变量用于保存返回函数 } @end @implementation LwmeViewController - (void)viewDidLoad { [super viewDidLoad]; // 设置delegate并载入html文件 self.webView.delegate = self; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"camera" ofType:@"html"]; NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; [self.webView loadHTMLString:fileContent baseURL:nil]; } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *requestString = [[request URL] absoluteString]; NSString *protocol = @"js-call://"; //协议名称 if ([requestString hasPrefix:protocol]) { NSString *requestContent = [requestString substringFromIndex:[protocol length]]; NSArray *vals = [requestContent componentsSeparatedByString:@"/"]; if ([[vals objectAtIndex:0] isEqualToString:@"camera"]) { // 摄像头 callback = [vals objectAtIndex:1]; [self doAction:UIImagePickerControllerSourceTypeCamera]; } else if([[vals objectAtIndex:0] isEqualToString:@"photolibrary"]) { // 图库 callback = [vals objectAtIndex:1]; [self doAction:UIImagePickerControllerSourceTypePhotoLibrary]; } else if([[vals objectAtIndex:0] isEqualToString:@"album"]) { // 相册 callback = [vals objectAtIndex:1]; [self doAction:UIImagePickerControllerSourceTypeSavedPhotosAlbum]; } else { [webView stringByEvaluatingJavaScriptFromString:@"alert('未定义/lwme.cnblogs.com');"]; } return NO; } return YES; } - (void)doAction:(UIImagePickerControllerSourceType)sourceType { UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; imagePicker.delegate = self; if ([UIImagePickerController isSourceTypeAvailable:sourceType]) { imagePicker.sourceType = sourceType; } else { UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"照片获取失败" message:@"没有可用的照片来源" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles:nil, nil]; [av show]; return; } // iPad设备作额外处理 if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:imagePicker]; [popover presentPopoverFromRect:CGRectMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 3, 10, 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } else { [self presentModalViewController:imagePicker animated:YES]; } } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:@"public.image"]) { // 返回图片 UIImage *originalImage = [info objectForKey:UIImagePickerControllerOriginalImage]; // 设置并显示加载动画 UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"正在处理图片..." message:@"\n\n" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil]; UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; loading.center = CGPointMake(139.5, 75.5); [av addSubview:loading]; [loading startAnimating]; [av show]; // 在后台线程处理图片 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ // 这里能够对图片作一些处理,如调整大小等,不然图片过大显示在网页上时会形成内存警告 NSString *base64 = [UIImagePNGRepresentation(originalImage, 0.3) base64Encoding]; // 图片转换成base64字符串 [self performSelectorOnMainThread:@selector(doCallback:) withObject:base64 waitUntilDone:YES]; // 把结果显示在网页上 [av dismissWithClickedButtonIndex:0 animated:YES]; // 关闭动画 }); } [picker dismissModalViewControllerAnimated:YES]; } - (void)doCallback:(NSString *)data { [self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"%@('%@');", callback, data]]; } @end
以上简单的代码虽然比较粗糙,但也基本实现了功能,若是有更多的需求,能够在这个基础上进行一些封装、扩展。
源代码提供在GitHub:https://github.com/corminlu/UIWebViewCallCamera
固然,这方面也有一些封装的比较好的类库: