有时候我们在内嵌的webview中希望点击一个链接之后,触发iOS原生事件,而不是webview内页面跳转(因为webview的跳转很生硬,而ajax+js模拟则不如原生segue平滑)。

有时候我们希望在页面内consloe.log('log something')的时候在控制台里看到输出,但手机里没有控制台,所以我们希望可以利用xcode的控制台输出信息。

因为iOS没有提供API让我们直接用html或者js来跟外部交互,所以我们必须用另外一种巧妙的办法来实现这两个功能。这种方法可以满足我们两种需求。

console.log

在html页面中重新定义console.log:

<script>
// Debug
console = new Object();
console.log = function(log) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "ios-log:#iOS#" + log);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
console.debug = console.log;
console.info = console.log;
console.warn = console.log;
console.error = console.log;
</script>

然后在需要捕获的viewController.m中实现协议:

- (BOOL)webView: (UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *requestString = [[[request URL] absoluteString] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
//NSLog(requestString);
if ([requestString hasPrefix:@"ios-log:"]) {
NSString* logString = [[requestString componentsSeparatedByString:@":#iOS#"] objectAtIndex:];
NSLog(@"UIWebView console: %@", logString);
return NO;
}
return YES;
}

当然前提是webView需要把委托设定为当前控制器:

self.webView =[[UIWebView alloc] initWithFrame:CGRectMake(0.0f,0.0f,self.view.bounds.size.width,self.view.bounds.size.height-)];
self.webView.delegate=self;

原理很简单,我们重新定义了console.log函数,还有console.debugconsole.infoconsole.warnconsole.error。当我们在页面js中调用console.log的时候,就会创建一个iframe发出请求,请求的协议为ios-log:,路径就是我们的log字符串。发出请求之后,迅速把这个iframe清理掉。

这样,在webview中我们发出了一个请求,然后就没了。外部我们用objective-c实现了一个协议,就是webview开始发出请求之前就会调用的函数。在这个函数中我们过滤所有的请求(因为除了ios-log,还有一些“正常”的请求比如http和mailto),当前缀为ios-log的时候,我们就NSLog即可。

if最后的return NO的意思是该webview的请求被捕获,不再请求(这个实际上不存在的页面)。我们希望一些合法请求(比如http、mailto等)不被捕获,所以最后if外面丢了一个return YES

webview中的代码:

<a href="myapp://somepagename">一个按钮</a>

非常简单,myapp这个协议你可以自己随便命名,稍后我们会在objective-c中捕获它。

还是要实现该webview的委托controller的协议方法,如果你已经定义这个方法了(就像上面那个例子),你只需要在方法体里加入方法体里面的内容,否则会提醒你重复定义。

- (BOOL)webView: (UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSURL *url = [request URL];
if ( [[url scheme] isEqualToString:@"myapp"] )
{
NSString *slug = [url path];
[self performSegueWithIdentifier:@"heroSegue" sender:slug];
return NO;
}
return YES;
}

另外我在interface builder中已经拖拽了一个新的控制器,在新的控制器跟导航控制器之间,我直接拖了一个segue,命名id为heroSegue,所以这里可以用performSegueWithIdentifier来调用segue。

现在,还是在本controller中,我们实现另一个委托方法:

/*
* 页面转换时触发
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"heroSegue"]) {
NSLog(@"%@",sender);
[self.webView stopLoading];
YUGHeroDetailViewController *destViewController = segue.destinationViewController;
destViewController.heroSlug = (NSString *)sender;
}
}

也就是说,发生segue变化之前,就会执行这一方法,首先判断identifier是不是等于heroSegue,如果是,自己的webview不再载入,目标控制器(也就是即将切换过去的子页面的控制器)中设置公有属性heroSlug的值。

然后,我们在目标页面的controller的H中定义:

@property (strong) NSString *heroSlug;

最后,在目标页面中,我们定义的congroller中的M能拿到heroSlug这个参数。

NSLog(@"%@",self.heroSlug);

这样就可以了,拿到slug之后,我们实际上就可以调用一个本地页面,带上slug参数,然后通过ajax的方式读取远程页面或者json数据,这个就不属于本文内容了。

如果你是新手,在做上面的这些操作的时候可能会漏掉一两个步骤,编辑器会报错,这时候仔细阅读并校对你的代码。如果实在不行,说明清楚操作和报错信息,再给我留言。

练习题:原生title的好处是它在字符数较短时是居中的,而字符更长一点时会偏右显示,更长一些时显示省略号。那么webview载入一个ajax数据的页面的时候,如何在页面载入成功时,设置原生title?

提示,还是自定义协议。

iOS Webview 与 app交互的更多相关文章

  1. iOS webView与js交互在文本空格上输入文字

    项目要求:webview加载html网址,内容为填空题型文本,需要在横线上添加答案,并点击提交按钮后再将答案进行回显 正常加载的效果图片: 这个是用js交互后的效果图: 点击空格,输入想输入的答案,如 ...

  2. andriod/ios webview与js交互 html_demo

    <html> <head> <title>测试</title> </head> <body> <h3>Android ...

  3. iOS与JS开发交互总结

    hybrid.jpg 前言 Web 页面中的 JS 与 iOS Native 如何交互是每个 iOS 猿必须掌握的技能.而说到 Native 与 JS 交互,就不得不提一嘴 Hybrid. Hybri ...

  4. h5 与原生 app 交互的原理

    现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次就来捋 ...

  5. 客户端相关知识学习(二)之h5与原生app交互的原理

    前言 现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次 ...

  6. h5与app交互

    现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次就来捋 ...

  7. webview和H5交互

    由于H5的灵活多变,动态可配的特点,也为了避免冗长 的审核周期,H5页面在app上的重要性正日益突显. iOS应用于H5交互的控件主要是UIWebView及WKWebView WKWebView是14 ...

  8. Android混合开发之WebView与Javascript交互

    前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...

  9. 分分钟解决iOS开发中App启动广告的功能

    前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏 ...

随机推荐

  1. java 获取音频文件时长

    需要导入jar包:jave 1.0.2 jar 如果是maven项目,在pom.xml文件中添加: <dependency> <groupId>it.sauronsoftwar ...

  2. cf891a Pride

    倘若存在 1,那么答案是 \(n-cnt_1\). 否则,设最短的公约数为 1 的区间长度为 \(minlen\),答案是 \(minlen-1+n-1\). #include <iostrea ...

  3. bean容器能力

    bean容器能力 对bean容器的最简单的述求 能生产bean 能注入组装bean: 字段,构造函数 spring bean容器(3.0版本)的能力列表 能生产bean 能注入组装bean:字段,构造 ...

  4. Masonry练习

    tableView的cell自动适应,scrollview自动适应,自定义自动布局控件 demo链接:http://pan.baidu.com/s/1jHsrGwQ

  5. 【Luogu】P2158仪仗队(欧拉函数)

    题目链接 首先来介绍欧拉函数. 设欧拉函数为f(n),则f(n)=1~n中与n互质的数的个数. 欧拉函数有三条引论: 1.若n为素数,则f(n)=n-1; 2.若n为pa,则f(n)=(p-1)*(p ...

  6. 【Luogu】P1516青蛙的约会(线性同余方程,扩展欧几里得)

    题目链接 定理:对于方程\(ax+by=c\),等价于\(a*x=c(mod b)\),有整数解的充分必要条件是c是gcd(a,b)的整数倍. ——信息学奥赛之数学一本通 避免侵权.哈哈. 两只青蛙跳 ...

  7. 刷题总结——shortest(ssoi)

    题目: 题目背景 SOURCE:NOIP2015-SHY-3 题目描述 给定一张 n 个点的有向带权完全图,和一个数组 a[] ,请按顺序删除数组中的点,请求出在删除点 a[i] 以前,所有未删除点对 ...

  8. Vue && Angular 双向绑定检测不到对象属性的添加和删除

    由于ES5的限制 Vue  && Angular 双向绑定检测不到对象属性的添加和删除  还有数组增加索引.这些改变不会触发change事件.Vue是因为实例化的时候已经把各个属性都s ...

  9. readonly和disabled的异同

    好久木有写博客了,今来逛逛 话说今天搞form表单的时候,主管让俺把手机号设成只读的.当时我就...咳咳,然后我就问了下万能的百度君,果断还是有解决方法的嘛,那么,今就谈谈readonly和disab ...

  10. hdu 4778 Gems Fight! 状压dp

    转自wdd :http://blog.csdn.net/u010535824/article/details/38540835 题目链接:hdu 4778 状压DP 用DP[i]表示从i状态选到结束得 ...