如果只有一个webview要想js与ios的本地代码进行通信可以使用现成的phonegap框架,现因项目要求开发ipad版本的应用,页面中有多个需要多个webview所以需要自己编写js代码实现js与本地代码通信。
基本原理是:webview访问特殊的url前缀地址,然后在UIWebViewDelegate的shouldStartLoadWithRequest方法中对url进行过滤就可以达到js与本地代码进行通信了。
1.在MainViewController中实现UIWebViewDelegate,实现shouldStartLoadWithRequest方法:
<p class="p1">#define CALLFUNCTION_PREFIX @<span class="s1">"callfunction://"</span></p>
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
NSString *url = [request.URL absoluteString];
NSLog(@"should url = %@ webView.tag = %d",url,webView.tag);
if ([url hasPrefix:@"http://"] || [url hasPrefix:@"https://"]) {
return [self logoutWithAlertWebView:webView url:url];
}else if([url hasPrefix:CALLFUNCTION_PREFIX]){
NSLog(@"webView.tag = %d",webView.tag);
[[BasicPlugin getInstance]executePluginByUrl:url tag:webView.tag];
return NO;
}
return YES;
}
2.以下代码通过类名和方法名反射执行指定类的指定方法:
-(void)executePluginByUrl:(NSString *)url tag:(NSInteger)tag{
NSRange range = [url rangeOfString:CALLFUNCTION_PREFIX];
NSString *temp = [url substringFromIndex:range.location + range.length];
NSArray *arr = [temp componentsSeparatedByString:@"&"];
NSString *callBackId = @"";
NSString *className = @"";
NSString *methodName = @"";
NSMutableArray *params = [NSMutableArray arrayWithCapacity:0];
if(arr != nil && arr.count > 0){
NSString *tt = [arr objectAtIndex:0];
NSArray *tempArr = [tt componentsSeparatedByString:@"="];
callBackId = [tempArr objectAtIndex:1];
tt = [arr objectAtIndex:1];
tempArr = [tt componentsSeparatedByString:@"="];
className = [tempArr objectAtIndex:1];
tt = [arr objectAtIndex:2];
tempArr = [tt componentsSeparatedByString:@"="];
methodName = [tempArr objectAtIndex:1];
tt = [arr objectAtIndex:3];
tempArr = [tt componentsSeparatedByString:@"="];
NSString *paramStr = [tempArr objectAtIndex:1];
paramStr = [paramStr stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if(paramStr != nil && paramStr.length > 0){
params = [NSMutableArray arrayWithArray:[paramStr componentsSeparatedByString:@"$"]];
}
//反射调用有参方法
NSMutableArray *pp = [NSMutableArray arrayWithCapacity:0];
[pp addObject:[NSString stringWithFormat:@"%d",tag]];
[pp addObject:callBackId];
for(NSString *t in params){
[pp addObject:t];
}
Class cls = NSClassFromString(className);
id a= [[cls alloc] init];
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@%@",methodName,@":"]);
if([a respondsToSelector:selector]){
@try {
[a performSelector:selector withObject:pp];
}
@catch (NSException *exception) {
NSLog(@"BasicPlugin: class:%@'s method:%@ is not found.",className,methodName);
}
}
}
3.js插件编写,使用location.href访问指定的url,这里有一个bug就是,不能同时调用两个插件,因为第二个插件的location.href会覆盖第一个location.href,所以需要等待第一个执行完才可以执行第二个。
//定义插件
$(function(){
//
var js2native_exception_arr = ["HomeViewPluginshowMask","HomeViewPluginunMask","HomeViewPluginalert"];
function pageName(){
var strUrl=location.href;
var arrUrl=strUrl.split("/");
var strPage=arrUrl[arrUrl.length-1];
return strPage;
}
if(!window.plugins){
window.plugins = {};
}
if(!window.js2native){
window.js2native = {
exec : function(className,methodName,params){
var arr = params;
var arrStr = '';
if(arr && arr.length > 0){
for(var tt in arr){
arrStr += '$';
arrStr += arr[tt];
}
arrStr = arrStr.substring(1);
}
var url="callfunction://callbackId=" + className + methodName +"Event&className="+className+"&method="+methodName + "¶ms=" + encodeURIComponent(arrStr);
url += ("¤tPage=" + pageName());
url += ("&tt=" + new Date().getTime());
var temp = className + methodName;
for(var tt in js2native_exception_arr){
var et = js2native_exception_arr[tt];
if(et == temp){
url = "http://" + url;
$.get(url);
return;
}
}
location.href = url;
}
};
}
//------------------------------插件方法------------------------//
//1.InfoPlugin
function InfoPlugin() {
};
/**
* 获取上下文路
*/
InfoPlugin.prototype.getCtx = function() {
js2native.exec("InfoPlugin", "getCtx",[]);
};
window.plugins.infoPlugin = new InfoPlugin();
});@interface LocalSubstitutionCache : NSURLCache<NSURLConnectionDataDelegate>{
NSMutableDictionary *cachedResponses;
}
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request{
//
// Get the path for the request
//
NSString *pathString = [[request URL] absoluteString];
NSString *relativePath=[[request URL] relativePath];
NSString *version = [[request URL] query];
NSLog(@"LocalSubstitutionCache===%@",pathString);
if(pathString != nil && ![@""isEqualToString:pathString] && [pathString hasPrefix:EXCEPTION_CALLFUNCTION_PREFIX]){
pathString = [pathString substringFromIndex:[EXCEPTION_CALLFUNCTION_PREFIX length]];
pathString = [NSString stringWithFormat:@"%@%@",EXCEPTION_CALLFUNCTION_REPLACE,pathString];
[[BasicPlugin getInstance]executePluginByUrl:pathString tag:1];
NSLog(@"cachedResponseForRequest.executePluginByUrl = %@",pathString);
return [super cachedResponseForRequest:request];
}
......
原文:http://blog.csdn.net/coooliang/article/details/39339887