UIWebView是iOS开发中常用的一个视图控件,多数情况下,它被用来显示HTML格式的内容。

支持的文档格式

除了HTML以外,UIWebView还支持iWork, Office等文档格式:

  • Excel (.xls)
  • Keynote (.key.zip)
  • Numbers (.numbers.zip)
  • Pages (.pages.zip)
  • PDF (.pdf)
  • Powerpoint (.ppt)
  • Word (.doc)
  • Rich Text Format (.rtf)
  • Rich Text Format Directory(.rtfd.zip)
  • Keynote ‘09 (.key)
  • Numbers ‘09 (.numbers)
  • Pages ‘09 (.pages)

载入这些文档的方法也和html一样:

NSString *path = [[NSBundle mainBundle] pathForResource:"test.doc" ofType:nil];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

 

HTML5技术及框架

移动设备浏览器的功能越来越强大,包括对HTML5、CSS3的支持,提供丰富的JavaScript API用于调用设备各种功能,使得开发出来的Web App非常接近原生App。

HTML5技术有如下优点:

  • 跨平台兼容性:不受移动平台及设备的限制,不需要单独针对iOS或Android平台、不同尺寸的设备编写特定的代码
  • 快速的开发效率、快速更新及发布效率
  • 低技术门槛及维护成本:只需要掌握HTML5/CSS/JavaScript

当然,HTML5也有它的缺点:

  • 访问设备特定功能的API非常有限:局限于浏览器运行环境,可用的API远远少于原生应用
  • 性能低于原生应用导致用户体验较差:特别是某一些绚丽的效果,或者是互动性很强的功能

随着HTML5的流行,出现了许多优秀的HTML5框架,它们可以使开发变得更加简单,进一步提高开发效率:

 

Hybrid开发方式

Native App需要较高的技术水平,虽然性能优越用户体验较好,但跨平台兼容性差,而且开发、维护成本太高,难以适应快速更新的需求变化;而Web App技术门槛低,良好的跨平台兼容性,开发、维护成本低,但是性能低导致用户体验较差。

Native App开发方法适合于游戏等需要良好用户体验的应用,而Web App开发方法适合没有太多交互的应用。这两种方法就像两个极端,而一般性应用并不是特别需要其中一种方法带来的好处,于是就产生了结合这两种开发方法的折中方案:Hybrid开发方法。

针对一般性应用,使用Hybrid开发方法,开发者就能使用跨平台的HTML5技术开发大部分的应用程序代码,又能在需要的时候使用一些设备的功能,充分结合了Native App开发方法和Web App开发方法的长处,在提供良好用户体验的同时,大大降低开发和维护的成本以及提高效率。

Hybrid开发方式也有一些框架/工具:

其中,Xamarin可以采用纯C#代码开发iOS/Android应用。而PhoneGap则是针对不同平台的WebView进行封装和扩展,使开发人员可以通过Javascript访问设备的一些功能。

当然,使用这些框架/工具需要一定的学习成本,如果对Objective-C和HTML5相关技术比较熟悉,也可以完全不用依赖于这些框架进行开发。

 

UIWebView与Javascript交互

UIWebView提供了stringByEvaluatingJavaScriptFromString方法,它将Javascript代码嵌入到页面中运行,并将运行结果返回。

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';"]; // 设置页面某个标记内容

需要注意的是:

  • js的执行时间不能超过10秒,否则UIWebView将停止执行脚本。
  • js分配的内存限制为10M,如果超过此限制,UIWebView将引发异常。

另外需要注意,运行部分脚本时需要确定页面是否加载完成(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:编写相应的代码来实现。

 

在UIWebView中调用摄像头、相册、图库

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>&nbsp;&nbsp;
<a href="js-call://photolibrary/photolibraryCallback">图库</a>&nbsp;&nbsp;
<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

当然,这方面也有一些封装的比较好的类库:

iOS UIWebView中javascript与Objective-C交互、获取摄像头的更多相关文章

  1. iOS UIWebView 中 js调用OC 打开相册 获取图片, OC调用js 将图片加载到html上

    线上html <!DOCTYPE html> <html> <head> <title>HTML中用JS调用OC方法</title> < ...

  2. iOS UIWebView与JavaScript的交互 相关资料

    UIWebView自适应宽度 iOS UIWebView中javascript与Objective-C交互.获取摄像头 iOS中JavaScript和OC交互 iOS与js交互,获取webview完整 ...

  3. asp.net中javascript与后台c#交互

    asp.net中javascript与后台c#交互 作者:熊猫大叔 字体:[增加 减小] 类型:转载 时间:2015-10-23我要评论,出处:http://www.jb51.net/article/ ...

  4. UIWebView中javascript与Objective-C交互、获取摄像头

    UIWebView是iOS开发中常用的一个视图控件,多数情况下,它被用来显示HTML格式的内容. 支持的文档格式 除了HTML以外,UIWebView还支持iWork, Office等文档格式: Ex ...

  5. 【iOS开发】UIWebView与JavaScript(JS) 回调交互

    ------------------------------------------------- 很多关于objc 与 js 交互的文章都比较适用于 mac开发,iOS的webview 还是有所不一 ...

  6. iOS中JavaScript和OC交互

    转载自:http://www.devzeng.com/blog/ios-uiwebview-interaction-with-javascript.html 还可参考的文章:http://blog.c ...

  7. iOS中JavaScript和OC交互 --by 胡 xu

    在iOS开发中很多时候我们会和UIWebView打交道,目前国内的很多应用都采用了UIWebView的混合编程技术,最常见的是微信公众号的内容页面.前段时间在做微信公众平台相关的开发,发现很多应用场景 ...

  8. iOS 利用UIWebView与JavaScript交互的最简单办法

    这里说的是针对iOS的!并且方法很简单!!并且验证可行的!!! 1, UIWebView调用 JavaScript 的函数: NSString* strValue = [webView stringB ...

  9. Hybrid App开发模式中, IOS/Android 和 JavaScript相互调用方式

    IOS:Objective-C 和 JavaScript 的相互调用 iOS7以前,iOS SDK 并没有原生提供 js 调用 native 代码的 API.但是 UIWebView 的一个 dele ...

随机推荐

  1. 单机运行环境搭建之 --CentOS-6.5安装配置Tengine

    一.安装pcre:   cd /usr/local/src wget http://downloads.sourceforge.net/project/pcre/pcre/8.34/pcre-8.34 ...

  2. 一个等待页面加载完毕的loading动画

    1 html 部分 <!DOCTYPE html><html><head><meta http-equiv="Content-Type" ...

  3. pcm跟.wav文件的关系

    PCM(Pulse Code Modulation----脉码调制录音).所谓PCM录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录.PCM信号是由[1].[0]等符号构成的数字信号,而未经过任 ...

  4. Ajax 结构及使用

    AJAX AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 JavaSc ...

  5. A configuration with this name already exists

    进入eclipse的workspace下的目录workspace\.metadata\.plugins\org.eclipse.debug.core\.launches,如实际目录为: D:\work ...

  6. RHEL 7.0 本地配置yum源

    RHEL 7.0 本地配置yum源  yum简介  yum = Yellow dog Updater, Modified 主要功能是更方便的添加/删除/更新RPM包. 它能自动解决包的倚赖性问题. 它 ...

  7. MySQL中如何插入反斜杠,反斜杠被吃掉,反斜杠转义

    问题描述:mysql中带有反斜杠的内容入库后,发现反斜杠无故失踪了(俗话说被吃掉了) 例:插入insert into tb('url') values('absc\eeee'); 结果数据库里的内容是 ...

  8. php SPL常用接口

    在PHP中有好几个预定义的接口,比较常用的四个接口(Countable.ArrayAccess.Iterator.IteratorAggregate(聚合式aggregate迭代器Iterator)) ...

  9. canvas 画六边形边框

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. coredump调试的使用

    一,什么是coredump 跑程序的时候经常碰到SIGNAL 或者 call trace的问题,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满 ...