参考:http://blog.sina.com.cn/s/blog_693de6100102vhuh.html
本文提供了一个很好解决UIWebView内js和objc 交互的思路。
自然,从oc到js,可以使用 stringByEvaluatingJavaScriptFromString: 来实现。
从js到oc,采用比较巧妙的设计,UIWebView浏览器拦截 url请求,自定义url的方式拦截交互请。
-------------------------------------------------
-------------------------------------------------
UIWebView是IOS SDK中渲染网面的控件,在显示网页的时候,我们可以hack网页然后显示想显示的内容。其中就要用到javascript的知识,而UIWebView与javascript交互的方法就是stringByEvaluatingJavaScriptFromString:
有了这个方法我们可以通过objc调用javascript,可以注入javascript。
首先我们来看一下,如何调用javascript:
[webView stringByEvaluatingJavaScriptFromString:@"myFunction();"];
这儿myFunction()就是我们的javascript方法。
再来看看入何注入javascript,我们先写一个需要注入的javascript:
function showAlert() {
alert('in show alert');
}
保存为test.js,然后拖到xcode 的resource分组下。再用代码在初始化的时候注入这个js(如在viewDidLoad方法里)。
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"js"];
NSString *jsString = [[NSString alloc] initWithContentsOfFile:filePath];
[webView stringByEvaluatingJavaScriptFromString:jsString];
这样就注入了上面的js,那么我们可以随时调用js的方法,如何调用,上面有介绍。
那么我们能不能通过js来调用objc的方法呢。 当然可以,原理就是利用UIWebView重定向请求,传一些命令到我们的UIWebView,在UIWebView的delegate的方法中接收这些命令,并根据命令执行相应的objc方法。这样就相当于在javascript中调用objc的方法。说起来有点抽象,看看代码一下就明白。
首先我们写一个javascript 方法如下:
[javascript]
function sendCommand(cmd,param){
var url="testapp:"+cmd+":"+param;
document.location = url;
}
function clickLink(){
sendCommand("alert","你好吗?");
}
然后在你的html里调用这个js方法 如:
[javascript]
"button" value="Click me!" οnclick="clickLink()" />
最后我们在UIWebVew中截获这个重定向请求:
#pragma mark --
#pragma mark UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
NSArray *components = [requestString componentsSeparatedByString:@":"];
if ([components count] > 1 && [(NSString *)[components objectAtIndex:0] isEqualToString:@"testapp"]) {
if([(NSString *)[components objectAtIndex:1] isEqualToString:@"alert"])
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Alert from Cocoa Touch" message:[components objectAtIndex:2]
delegate:self cancelButtonTitle:nil
otherButtonTitles:@"OK", nil];
[alert show];
}
return NO;
}
return YES;
}
不过有一个开源工程大家可以看看,它允许javascript调用objective_c的方法。叫
jsbridge-to-cocoa http://code.google.com/p/jsbridge-to-cocoa/
还有两个相关工程
WebViewJavascriptBridge 与 GAJavaScript 值得大家慢慢研究。
其他
插入js代码
上面的功能我们可以封装到一个js函数中,将这个函数插入到页面上执行,代码如下:
if ([title compare: @"Google"]==NSOrderedSame ) {
[webView stringByEvaluatingJavaScriptFromString:@"var script = document_createElement_x_x('script');"
"script.type = 'text/javascript';"
"script.text = "function myFunction() { "
"var field = document.getElementsByName('q')[0];"
"field.value='朱祁林';"
"document.forms[0].submit();"
"}";"
"document.getElementsByTagName_r('head')[0].a(script);"];
[webView stringByEvaluatingJavaScriptFromString:@"myFunction();"];
}
看上面的代码:
a、首先通过js创建一个script的标签,type为'text/javascript'。
b、然后在这个标签中插入一段字符串,这段字符串就是一个函数:myFunction,这个函数实现google自动搜索关键字的功能。
c、然后使用stringByEvaluatingJavaScriptFromString执行myFunction函数。
1. 一般调用
将本地数据,封装,直接作为JS的返回值。如:获取软件的APPCode
//获取APPCode
NSArray *_plist_paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *_plist_paths_path=[_plist_paths objectAtIndex:0];
NSArray *_plist_array= [_plist_paths_path componentsSeparatedByString:@"/"];
NSString *_appcode=[[NSString alloc]init];
for (NSString *item in _plist_array) {
if ([item length]==36) {
_appcode=item;
break;
}
}
NSLog(@"current appcode:%@",_appcode);
//注入到js中
NSMutableString *_getApkCode=[[NSMutableString alloc]init];
[_getApkCode appendFormat:@" function _getApkCode(){"];
[_getApkCode appendFormat:@"return '%@';",_appcode];
[_getApkCode appendString:@" }"];
[self.webView stringByEvaluatingJavaScriptFromString:_getApkCode];
[_getApkCode release];
2.需要跟平台进行交互调用
思路:
1.制造含有一定含义的请求如:(location.href="download");
2.在方法:-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType中,拦截:
//testMall:http://192.168.1.20:8083本地测试页面地址
NSString *pre_download=[NSString stringWithFormat:@"%@downLoad",testMall];
if([url hasPrefix:pre_download])
{
//下载代码。。。。
}
3. 注意事项
a.存在Iframe嵌套的页面,js注入
页面注入JS是注入到,浏览器的html中,对于内部嵌套iframe框架的页面,则无法调用到js。此时相当于调用父页面的JS。
可以通过parent+方法名,来调用你注入的JS。parent.parent的使用个数,可以是多个,不影响js的执行,如果少用parent,可能会导致,调不到你注入的JS
b.存在交互的处理方法。推荐使用方法,iphone只负责提供js接口,不调用html内部或其他的js接口
示例:
html
function addDownload()
{
url='www.XXX.XXX.zip';
download(url);//调用iphone提供的js接口
addDownloadTask_ret();//获取iphone下载接口执行的下载结果,此处调的是本地的一个延迟方法
}
//获取iphone下载接口执行的下载结果
function addDownloadTask_ret()
{
var obj=getDownloadTaskResult();//此处为iphone提供的接口,负责返回当前下载执行情况的结果if(''!=obj||undefined!=obj)
{
//调用本地的一些后续处理方法。
}
else
{
setTimeout("addDownloadTask_ret2();",1000);
}
}
-----------------------------
1、UIWebView的 stringByEvaluatingJavaScriptFromString方法
2、UIWebViewDelegate的
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType方法
代码实例
1)加载页面
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- NSString *path = [[NSBundle mainBundle] pathForResource:@"jm/info" ofType:@"html"];
- NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
- [self.webView loadRequest:request];
- }
- #pragma mark - UIWebViewDelegate
- - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- {
- if([request.mainDocumentURL.relativePath isEqualToString:@"/getInfo/name"])
- {
- NSString *info = [[UIDevice currentDevice] name];
- NSString *js = [NSString stringWithFormat:@"showInfo(\"name\",\"%@\")",info];
- [self.webView stringByEvaluatingJavaScriptFromString:js];
- return false;
- }
- if([request.mainDocumentURL.relativePath isEqualToString:@"/getInfo/systemVersion"])
- {
- NSString *info = [[UIDevice currentDevice] systemVersion];
- NSString *js = [NSString stringWithFormat:@"showInfo(\"systemVersion\",\"%@\")",info];
- [self.webView stringByEvaluatingJavaScriptFromString:js];
- return false;
- }
- return true;
- }
<!DOCTYPE html>
<html>
<head>
<title>city</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.0.css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.mobile-1.0.js"></script>
<script>
function getInfo(name)
{
window.location = "/getInfo/"+name;
}
function showInfo(id,info)
{
$("p#"+id).html(info);
}
</script>
</head>
<body>
<div data-role="page">
<div data-role="content">
<h2>Divice Info</h2>
<div data-role="collapsible-set" data-theme="c" data-content-theme="d">
<div data-role="collapsible">
<h3 οnclick="getInfo('name')">name</h3>
<p id="name"></p>
</div>
<div data-role="collapsible">
<h3 οnclick="getInfo('systemVersion')">systemVersion</h3>
<p id="systemVersion"></p>
</div>
</div>
</div>
</div>
</body>
</html>