//webview每次加载之前都会调用这个方法,利用该代理方法截取JS的href来调用原生的方法
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
然而这次的交互要求是进行双向通信,即JS调用原生App的方法之后,原生App要讲相关参数信息返回给H5页面,H5页面接受到参数信息后做其他处理。
例:H5页面的发布信息按钮,在点击按钮后要在原生端判断用户是否登录,若没有登录则弹出原生登录页面,登录成功后将用户信息返回给H5页面,继续发布流程。
重点来了!
在这里推荐一个比较好的第三方库即:WebViewJavascriptBridge
地址:https://github.com/marcuswestin/WebViewJavascriptBridge
通过使用该库可以轻松实现JS与原生交互。
//初始化WebViewJavascriptBridge方法
_bridge= [WebViewJavascriptBridge bridgeForWebView:self.BookWebView webViewDelegate:self handler:^(id data,WVJBResponseCallback responseCallback) {
}];
//原生与JS约定接口名为“testObjcCallback”,data是JS传递过来的信息,responseCallback来将信息传递给JS
[_bridge registerHandler:@"testObjcCallback" handler:^(id data,WVJBResponseCallback responseCallback) {
responseCallback("postInfomationToJS")
}];
WebViewJavascriptBridge使用说明(IOS)
由于现在很多产品都是有安卓版跟ios版,就意味着同一样东西要出两套,由两组人去完成,不仅增加了开发成本,也大大加剧了维护成本。聪明的coder想出了跨平台的思路,用html写页面,分别用webview(ios),(安卓)来加载,对某些html无法调用的硬件,通过双方的交互来实现方法的互调和传值。这个过程就是跨平台。
下面来说一下WebViewJavascriptBridge在ios端怎么样使用。
首先确保一份已经配好功能的html文件。(html还在学习阶段,暂时就不卖弄了。。。)
1.初始化一个webview(viewdidload)
UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:webView];
2.将此webview与WebViewJavascriptBridge关联(viewdidload)
if (_bridge) { return; }
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC received message from JS: %@", data);
responseCallback(@"Response for message from ObjC");
}];
ps:此时你的webview就与js搭上桥了。下面就是方法的互调和参数的互传。
(1) js调oc方法(可以通过data给oc方法传值,使用responseCallback将值再返回给js)
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"testObjcCallback called: %@", data);
responseCallback(@"Response from testObjcCallback");
}];
这里注意testObjcCallback这个方法的标示。html那边的命名要跟ios这边相同,才能调到这个方法。当然这个名字可以两边商量着自定义。简单明确即可。
(2)oc调js方法(通过data可以传值,通过response可以接受js那边的返回值)
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
NSLog(@"testJavascriptHandler responded: %@", response);
}];
注意这里的testJavascriptHandler也是个方法标示。
(3)oc给js传值(通过response接受返回值)
[_bridge send:@”A string sent from ObjC to JS” responseCallback:^(id response) {
NSLog(@”sendMessage got response: %@”, response);
}];
(4)oc给js传值(无返回值)
[_bridge send:@”A string sent from ObjC after Webview has loaded.”];
##2 UIWebView页面信息的离线缓存
推荐一个比较好的第三方库RNCachingURLProtocol ,只需要在AppDelegate中加入下面方法即可。
[NSURLProtocolregisterClass:[RNCachingURLProtocolclass]];
地址:https://github.com/rnapier/RNCachingURLProtocol
##3 NSURLConnection小解
NSURLConnection提供对网络异步加载请求的支持,并且将获取的数据返回给代理。提供了简单的接口去创建和取消连接,同时使用delegate方法去支持连接过程的反馈和控制 。在实际开发中直接用的不多,但是有的第三方库却是用它来封装的。
举例一:
1、先创建一个NSURL
2、在通过NSURL创建NSURLRequest,可以指定缓存规则和超时时间
3、创建NSURLConnection实例,指定NSURLRequest和一个delegate对象
如果创建失败,则会返回nil,如果创建成功则创建一个NSMutalbeData的实例用来存储数据
代码:
NSURL *url = [NSURL URLWithString:@”http://192.168.2.128:9090/ssonew/login/UserLogin.action?name=mql&psd=123456“];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
self.theConncetion = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
if (_theConncetion) {
self.receiveData = [[NSMutableData alloc]init];
}
NSURLConnection有3个初始化函数,只有第一个初始化函数可以做到创建连接但是并
不马上开始下载,而是通过start:开始,调用该初始化函数时,startImmediately传NO
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately NS_AVAILABLE(10_5, 2_0);
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
- (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
当收到initWithRequest: delegate:或收到connectionWithRequest: delegate: 消息时,下载会立即开始,在代理(delegate)
收到connectionDidFinishLoading:或者connection:didFailWithError:消息之前
可以通过给连接发送一个cancel:消息来中断下载
connection: willSendRequest: redirectResponse:这个方法在请求将要被发送出去之前会调用
返回值是一个NSURLRequest,就是那个真正将要被发送的请求
第二个参数request就是被重定向处理过后的请求
第三个参数response是触发重定向请求的响应包.默认是支持跳转的。
- (NSURLRequest )connection:(NSURLConnection )connection willSendRequest:(NSURLRequest )request redirectResponse:(NSURLResponse )response
{
NSURLRequest *newRequest = request;
if (response) {
NSLog(@”redirect!!!”); //如,请求google的网站时会有跳转发生
newRequest = nil; //拒绝跳转
}
return newRequest;
}
当服务器提供了足够客户程序创建NSURLResponse对象的信息时,代理对象会收到
一个connection:didReceiveResponse:消息,在消息内可以检查NSURLResponse
对象和确定数据的预期长途,mime类型,文件名以及其他服务器提供的元信息
要注意,一个简单的连接也可能会收到多个connection:didReceiveResponse:消息
当服务器连接重置或者一些罕见的原因(比如多组mime文档),代理都会收到该消息
这时候应该重置进度指示,丢弃之前接收的数据
- (void)connection:(NSURLConnection )connection didReceiveResponse:(NSURLResponse )response
{
//注意这里将NSURLResponse对象转换成NSHTTPURLResponse对象才能使用
NSHTTPURLResponse httpResponse = (NSHTTPURLResponse)response;
if ([response respondsToSelector:@selector(allHeaderFields)]) {
NSDictionary *dictionary = [httpResponse allHeaderFields];
NSLog(@”%@”, dictionary);
}
[self.receiveData setLength:0];
}
当下载开始的时候,每当有数据接收,代理会定期收到connection:didReceiveData:消息
代理应当在实现中储存新接收的数据,下面的例子既是如此
-(void) connection:(NSURLConnection*)connection didReceiveData:
(NSData *) data
{
[receiveData appendData:data];
}
-(void) connection:(NSURLConnection*)connection didReceiveData:
(NSData *) data
{
[receiveData appendData:data];
}
在上面的方法实现中,可以加入一个进度指示器,提示用户下载进度
当下载的过程中有错误发生的时候,代理会收到一个connection:didFailWithError消息
消息参数里面的NSError对象提供了具体的错误细节,它也能提供在用户信息字典里面失败的
url请求(使用NSErrorFailingURLStringKey)
当代理接收到连接的connection:didFailWithError消息后,对于该连接不会再收到任何消息
举例
- (void)connection:(NSURLConnection )connection didFailWithError:(NSError )error
{
}
最后,如果连接请求成功的下载,代理会接收connectionDidFinishLoading:消息,代理不会收到其他的消息
举例:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@”总共请求的数据长度 = %d”, [self.data length]);
}
注:从ios5.0开始,苹果为开发者引入block概念,所以使用NSURLConnection发送一个请求可以如下:
NSURL *url = [NSURL URLWithString:@”http://www.google.com“];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
[ NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil){
NSLog(@"download success");
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *str = [[NSString alloc]initWithData:data encoding:enc];
NSLog(@"%@", str);
}else if(error!=nil){
NSLog(@"error");
}
}];
“`
以上演示的请求都是GET请求,如果没使用NSMutableURLRequest的实例方法setHTTPMethod进行设置,请求都是GET请求。
如要走POST请求,仅需:
1、将上面的NSURLRequest替换成NSMutableURLRequest
2、[request setHTTPMethod:@“POST”];
3、[request setHTTPBody:postData];//postData一般是JSON格式的字符串转换过来的。
4、使用NSURLConnection启动请求。