本文为您图文演示如何在 OC 中注册或运行 JS 函数,以实现网页与程序的交互。
首先我们创建一个 XCode 项目
将 Webview 拖入 View Controller 中
打开 ViewController.h 新建一个 WebController Interface 继承 NSObject
#import <WebKit/WebKit.h>
@interface WebController : NSObject
{
IBOutlet WebView* webView;
}
@end
在项目中添加 Webkit.framework 的引用
将一个 Object 拖拽至 ViewController 并填写其 Class 属性为 WebController
右键点击 WebController 并将 webView 关联起来
接下来就是关键代码 实现 WebController
@implementation WebController
+(NSString*)webScriptNameForSelector:(SEL)sel
{
if(sel == @selector(Writelog:)) //JS对应的本地函数
return @"log"; // 要注册的JS函数名
else if(sel == @selector(alert:))
return @"alert";
return nil;
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)sel
{
if(sel == @selector(Writelog:))//JS对应的本地函数
return NO;
else if(sel == @selector(alert:))
return NO;
return YES; //返回 YES 表示函数被排除,不会在网页上注册
}
- (void)awakeFromNib //当 WebContoller 加载完成后执行的动作
{
[webView setFrameLoadDelegate:self];
[[webView mainFrame] loadHTMLString:@"<button onclick=\"window.external.alert('This is an alert!!');\">Alert</button> <button onclick=\"window.external.log('lllllaaaa');\">Log</button>" baseURL:nil];
//网页内容,两个按钮 一个弹出消息框,一个在控制台 Log
// webView.mainFrameURL = @"http://someurl"; 加载网页
}
- (void)Writelog:(NSString*) txt
{
NSLog(@"Log:%@",txt);
}
- (void)alert:(NSString*) txt
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:@"来自网页的消息"];
[alert setInformativeText:txt];
[alert runModal];
}
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowScriptObject forFrame:(WebFrame *)frame //网页加载完成后发生的动作
{
[windowScriptObject setValue:self forKeyPath:@"window.external"]; // 注册一个 window.external 的 Javascript 类
}
@end
然后点击运行按钮 出现应用主界面并自动加载网页内容,此时我们点击 Log 就会在控制台输出数据,点击 Alert 按钮就会弹出提示框。
UIWebView是IOSSDK中渲染网面的控件,在显示网页的时候,我们可以hack网页然后显示想显示的内容。其中就要用到javascript的知识,而UIWebView与javascript交互的方法就是stringByEvaluatingJavaSc
有了这个方法我们可以通过objc调用javascript,可以注入javascript。
首先我们来看一下,如何调用javascript:
- [webView
stringByEvaluatingJavaSc riptFromString:@"myFunction();"];
再来看看入何注入javascript,我们先写一个需要注入的javascript:
- function
showAlert() { -
alert('in show alert'); - }
- NSString
*filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"js"]; - NSString
*jsString = [[NSString alloc] initWithContentsOfFile:filePath]; - [webView
stringByEvaluatingJavaSc riptFromString:jsString];
那么我们能不能通过js来调用objc的方法呢。当然可以,原理就是利用UIWebView重定向请求,传一些命令到我们的UIWebView,在UIWebView的delegate的方法中接收这些命令,并根据命令执行相应的objc方法。这样就相当于在javascript中调用objc的方法。说起来有点抽象,看看代码一下就明白。
首先我们写一个javascript 方法如下:
- function
sendCommand(cmd,param){ -
var url="testapp:"+cmd+":"+param; -
document.location = url; - }
- function
clickLink(){ -
sendCommand("alert","你好吗?"); - }
然后在你的html里调用这个js方法如:
- "button"
value="Click me!" οnclick="clickLink()" />
最后我们在UIWebVew中截获这个重定向请求:
- #pragma
mark -- - #pragma
mark UIWebViewDelegate -
- -
(BOOL)webView:(UIWebView *)webView shouldStartLoadWithReque st:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { -
-
NSString *requestString = [[request URL] absoluteString]; -
NSArray *components = [requestString componentsSeparatedByStr ing:@":"]; -
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; - }
jsbridge-to-cocoa
还有两个相关工程
WebViewJavascriptBridge
其他
插入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);"];
[webViewstringByEvaluatingJavaScriptFromString:@"myFunction();"];
}
看上面的代码:
a、首先通过js创建一个script的标签,type为'text/javascript'。
b、然后在这个标签中插入一段字符串,这段字符串就是一个函数:myFunction,这个函数实现google自动搜索关键字的功能。
c、然后使用stringByEvaluatingJavaSc
1.
将本地数据,封装,直接作为JS的返回值。如:获取软件的APPCode
//获取APPCode
NSArray*_plist_paths=NSSearchPathForDirectori esInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*_plist_paths_path=[_plist_paths objectAtIndex:0];
NSArray *_plist_array= [_plist_paths_pathcomponentsSeparatedByStr ing:@"/"];
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=[[NSMutableStringalloc]init];
[_getApkCode appendFormat:@"function _getApkCode(){"];
[_getApkCodeappendFormat:@"return '%@';",_appcode];
[_getApkCode appendString:@" }"];
[self.webViewstringByEvaluatingJavaSc riptFromString:_getApkCode];
[_getApkCode release];
2.需要跟平台进行交互调用
思路:
1.制造含有一定含义的请求如:(location.href="download");
2.在方法:-(BOOL)webView:(UIWebView *)webViewshouldStartLoadWithReque
st:(NSURLRequest *)requestnavigationType:(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
functionaddDownload()
{
url='www.XXX.XXX.zip';
download(url);//调用iphone提供的js接口
addDownloadTask_ret();//获取iphone下载接口执行的下载结果,此处调的是本地的一个延迟方法
}
//获取iphone下载接口执行的下载结果
functionaddDownloadTask_ret()
{varobj=getDownloadTaskResult();//此处为iphone提供的接口,负责返回当前下载执行情况的结果if(''!=obj||undefined!=obj)
{
//调用本地的一些后续处理方法。
}
else
{
setTimeout("addDownloadTask_ret2();",1000);
}