UIWebView 使用浅析

苹果官方对UIWebView的介绍

You can use the UIWebView class to embed web content in your application. To doso, you simply create a UIWebView object, attach it to a window, and send it a request to load web content. You can also use this class to move back and forward in the history of webpages, and you can even set some web content properties programmatically.

UIWebViewiOS内置的浏览器控件,UIWebView用于在App中嵌入网页,通常是html网页,也可以是PDFtxt文档等。苹果在发布iOS8的时候,新增了一个WKWebView组件,如果你的APP只考虑支持iOS8及以上版本,那么你就可以使用这个新的浏览器控件了。

本文只是探讨UIWebView的使用方法。

属性

@property (nonatomic) BOOL scalesPageToFit;

自动适应屏幕尺寸

@property (nonatomic) BOOL detectsPhoneNumbers NS_DEPRECATED_IOS(2_0, 3_0);

自动检测网页上的电话号码,单击可以拨打,iOS4之后被下面的属性所代替。

@property (nonatomic) UIDataDetectorTypes dataDetectorTypes NS_AVAILABLE_IOS(3_0);

自动检测电话、网址和邮箱。枚举见下方代码。

1
2
3
4
5
6
7
8
typedef NS_OPTIONS(NSUInteger, UIDataDetectorTypes) {
UIDataDetectorTypePhoneNumber = 1 << 0, // Phone number detection
UIDataDetectorTypeLink = 1 << 1, // URL detection
UIDataDetectorTypeAddress NS_ENUM_AVAILABLE_IOS(4_0) = 1 << 2, // Street address detection
UIDataDetectorTypeCalendarEvent NS_ENUM_AVAILABLE_IOS(4_0) = 1 << 3, // Event detection
UIDataDetectorTypeNone = 0, // No detection at all
UIDataDetectorTypeAll = NSUIntegerMax // All types
} __TVOS_PROHIBITED;

@property (nonatomic) BOOL allowsInlineMediaPlayback NS_AVAILABLE_IOS(4_0);
// iPhone Safari defaults to NO. iPad Safari defaults to YES

UIWebView中用html5video方式播放视频时,在iPad上是默认原来大小的,而在iPhone上是默认全屏播放的。
HTMLvideo必须加上webkit-playsinline属性

@property (nonatomic) BOOL mediaPlaybackRequiresUserAction NS_AVAILABLE_IOS(4_0);
// iPhone and iPad Safari both default to YES

是否可以自动播放html5中的视频。

@property (nonatomic) BOOL mediaPlaybackAllowsAirPlay NS_AVAILABLE_IOS(5_0);
// iPhone and iPad Safari both default to YES

是否可以使用Air Play。 在iPhoneiPad上默认使YES

@property (nonatomic) BOOL suppressesIncrementalRendering NS_AVAILABLE_IOS(6_0);
// iPhone and iPad Safari both default to NO

是否网页内容下载完毕才开始渲染web视图,默认为NO

@property (nonatomic) BOOL keyboardDisplayRequiresUserAction NS_AVAILABLE_IOS(6_0); // default is YES

是否在web页面响应用户输入弹出键盘,默认为YES

iOS7增加了分页功能
@property (nonatomic) UIWebPaginationMode paginationMode NS_AVAILABLE_IOS(7_0);

设置分页模式

1
2
3
4
5
6
7
typedef NS_ENUM(NSInteger, UIWebPaginationMode) {
UIWebPaginationModeUnpaginated,//不使用翻页效果
UIWebPaginationModeLeftToRight,//将网页超出部分分页,从左向右进行翻页
UIWebPaginationModeTopToBottom,//将网页超出部分分页,从上向下进行翻页
UIWebPaginationModeBottomToTop,//将网页超出部分分页,从下向上进行翻页
UIWebPaginationModeRightToLeft//将网页超出部分分页,从右向左进行翻页
};

@property (nonatomic) UIWebPaginationBreakingMode paginationBreakingMode NS_AVAILABLE_IOS(7_0);

设置分页打破模式

1
2
3
4
typedef NS_ENUM (NSInteger, UIWebPaginationBreakingMode ) {
UIWebPaginationBreakingModePage, // 页模式
UIWebPaginationBreakingModeColumn //列模式
};

@property (nonatomic) CGFloat pageLength NS_AVAILABLE_IOS(7_0);

每一页的长度

@property (nonatomic) CGFloat gapBetweenPages NS_AVAILABLE_IOS(7_0);

每一页的间距

@property (nonatomic) BOOL allowsPictureInPictureMediaPlayback NS_AVAILABLE_IOS(9_0);

画中画模式页面中返回 iOS9新增属性

@property (nonatomic) BOOL allowsLinkPreview NS_AVAILABLE_IOS(9_0); // default is NO

使用3DTouch显示链接预览 iOS9新增属性

方法

1
2
3
4
5
6
7
- (void)reload; //重新加载(刷新)
- (void)stopLoading; //停止加载
- (void)goBack;//回退
- (void)goForward; //前进
- (void)loadRequest:(NSURLRequest *)request;
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;

代理方法

1
2
3
4
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;

UIWebView 的高级用法

隐藏上下滚动时出边界的后面的黑色的阴影
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for (UIView *_aView in [webView subviews]){

if ([_aView isKindOfClass:[UIScrollView class]]){

[(UIScrollView *)_aView setShowsVerticalScrollIndicator:NO];
//右侧的滚动条
[(UIScrollView *)_aView setShowsHorizontalScrollIndicator:NO];
//下侧的滚动条
[(UIScrollView *)_aView setAlwaysBounceHorizontal:NO];//禁止左右滑动

for (UIView *_inScrollview in _aView.subviews){
if ([_inScrollview isKindOfClass:[UIImageView class]]){

_inScrollview.hidden = YES; //上下滚动出边界时的黑色的图片
}
}
}
}
禁用拖拽时的反弹效果
[(UIScrollView *)[[webView subviews] objectAtIndex:0] setBounces:NO];
判断用户点击类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
switch (navigationType) {
//点击连接
case UIWebViewNavigationTypeLinkClicked:
{
NSLog(@"clicked");
}
break;
//提交表单
case UIWebViewNavigationTypeFormSubmitted:
{
NSLog(@"submitted");
}
default:
break;
}
return YES;
}
UIWebViewJavaScript的交互
Objective-C调用JavaScript

Objective-C调用JavaScript会相对简单些,在UIWebView加载完成之后调用UIWebViewstringByEvaluatingJavaScriptFromString:方法就行了。参数中的NSString字符串就是js的代码,可以是js函数,也可以是js代码。如下所示:

[myWebView stringByEvaluatingJavaScriptFromString:@"javascriptFunction()"];

Javascript调用Objective-C的函数

通过UIWebView的重定向,通过在UIWebView的代理函数webView:shouldStartLoadWithRequest:navigationType:来监听URL的变化,这个函数会在webview加载URL时回调,我们可以return YES来让webview继续加载内容,return NO来停止继续加载新的内容。事先可以约定好几个虚假的URL(比如tool://goToHomePage),我们拿到定义好的URL之后做对应的Objective-C函数调用。在iOS7中会出现代理方法无法调用的情况,具体原因不明。

实例

比如我们在javascript文件里添加点击响应的函数

1
2
3
4
function clickButton() {

window.location = "tool://goToHomePage"
}

然后在webview的代理函数中监听,如果是事先定义好的虚假URL,就进行对应的处理

1
2
3
4
5
6
7
8
9
10
11
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

NSURL *url = request.URL;

if ([[url scheme] isEqualToString:@"tool"] && [[url host] isEqualToString:@"goToHomePage"]) {
//添加跳转到HomePage的逻辑
[self jumpToHomePage];
return NO;
}
return YES;
}
UIWebView 捕获 404, 403
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
static BOOL isRequestWeb = YES;

if (isRequestWeb) {
NSHTTPURLResponse *response = nil;

NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

if (response.statusCode == 404) {
// code for 404
return NO;
} else if (response.statusCode == 403) {
// code for 403
return NO;
}

[webView loadData:data MIMEType:@"text/html" textEncodingName:nil baseURL:[request URL]];

isRequestWeb = NO;

return NO;
}

return YES;
}