IOS中js与本地通信手记

如果只有一个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();

});

4.其中js2native_exception_arr是为了异步访问后台,需要与NSURLCache一同使用。

@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];
    }

......
时间: 2024-10-26 08:28:38

IOS中js与本地通信手记的相关文章

iOS中JS的操作

获取所有html:NSString *lJs = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.innerHTML"]; 获取body: [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.innerText"]; 去除某个属性: [webView stringByE

转载:ios中objective-c与js的交互

原始出处:http://mkhgg.blog.51cto.com/1741572/752962 iOS中js与objective-c的交互 因为在iOS中没有WebKit.Framework这个库的,所以也就没有 windowScriptObject对象方法了.要是有这个的方法的话 就方便多了,(ps:MacOS中有貌似) 现在我们利用其他方法去达到js与objective-c的交互效果. 首先是objective-c调用js中的代码,可以用uiwebview中的一个方法 stringByEva

iOS中UIWebView使用JS交互

iOS中偶尔也会用到webview来显示一些内容,比如新闻,或者一段介绍.但是用的不多,现在来教大家怎么使用js跟webview进行交互. 这里就拿点击图片获取图片路径为例: 1.测试页面html <!doctype html> <html> <head> </head> <body> <div> <img src="test.png"/> </div> </body> <

iOS中UIWebView使用JS交互 - 机智的新手

iOS中偶尔也会用到webview来显示一些内容,比如新闻,或者一段介绍.但是用的不多,现在来教大家怎么使用js跟webview进行交互. 这里就拿点击图片获取图片路径为例: 1.测试页面html <!doctype html> <html> <head> </head> <body> <div> <img src="test.png"/> </div> </body> <

Ios开发中UILocalNotification实现本地通知实现提醒功能

这两天在做一个日程提醒功能,用到了本地通知的功能,记录相关知识如下: 1.本地通知的定义和使用: 本地通知是UILocalNotification的实例,主要有三类属性: scheduled time,时间周期,用来指定iOS系统发送通知的日期和时间: notification type,通知类型,包括警告信息.动作按钮的标题.应用图标上的badge(数字标记)和播放的声音: 自定义数据,本地通知可以包含一个dictionary类型的本地数据. 对本地通知的数量限制,iOS最多允许最近本地通知数

IOS中NSUserDefaults的用法(轻量级本地数据存储)

iOS数据保存 IOS中NSUserDefaults的用法(轻量级本地数据存储) IOS中NSUserDefaults的用法(轻量级本地数据存储),布布扣,bubuko.com

iOS中UIWebView执行JS代码(UIWebView)

iOS中UIWebView执行JS代码(UIWebView) 有时候iOS开发过程中使用 UIWebView 经常需要加载网页,但是网页中有很多明显的标记让人一眼就能看出来是加载的网页,而我们又不想被人卡出来. 如网页中的这个导航 通常我们不需要WebView中的 导航栏,也不需要里面的返回上一级的交互.. 对WebView常用的另外一种功能就是对某个点击添加对用function实现JS调用OC的交互功能. 下面一一介绍: 1. UIWebView 调用JS代码 OC调用JS通常是,在webVi

【转载】iOS中delegate,notification,KVO三种模式实现通信的优缺点

原帖地址:http://blog.csdn.net/yangxt/article/details/8176636 在开发iOS中,有三种模式来实现controller之间的通信: 1.委托delegation: 2.通知中心Notification Center: 3.键值观察key value observing,KVO 因此,那为什么我们需要这些模式以及什么时候用它以及什么时候不用它. 1.delegate 基本特征: 一 个controller定义了一个协议(即一系列的方法定义).该协议描

CeF3开发者系列之外篇——IE中JS与C++交互

使用IE内核开发客户端产品,系统和前端页面之间的交互,通常给开发和维护带来很大的便利性.但操作系统和前端之间的交互却是比较复杂的.具体来说就是脚本语言和编译语言的交互.在IE内核中html和css虽然不兼容,但是IE编程接口是完全一样的,这得益于微软的COM组件的结构化设计和实现.所以与IE交互,必须得先说一下COM,COM全称组件对象模型(Component Object Model). COM的基本思想很简单,所有的组件模块都提供一个最根本的接口, IUnkown,它有三个方法,AddRef