OC与JS混合开发

随着iOS开发的成本增大,越来越多的公司开始使用html5混合开发软件了,因为使用原生的开发花费的成本跟时间都很大,而使用html5来搭建界面会方便很多,效率相对而言也提高了。虽然使用UIWebView实现的交互效果与原生效果相比还是会大打折扣,这类界面通常没有复杂的交互效果,所以现在主流应用大多采用混合开发。花了几天时间,把JS的基础全部看了一遍,又研究了一下巧神的书,写了一个iOS7以前的JS与OC混合开发的demo。

既然是html5页面搭建的布局,那么肯定是得有html5页面的,所以首先我们得先写一个html5的页面。既然我们做的是App,所以我们针对的是手机页面,需要加入针对移动端页面优化的viewport,然后在body里面加入一个按钮,绑定一个点击事件,在JS里面实现这个方法,通过location.href = ""; 方法进行跳转网页,里面的地址是自己自定义的,然后在OC里面解析。

<html>
    <head>
        <meta charset = "UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"/>
        <title>测试网页</title>
        <script type="text/javascript">
            function sum(){
                location.href = ‘jsoc://call_?100‘; // 自己写的跳转网址
            }

            function ocCallJsNoParamsFunction(){
                alert("OC调用JS中的无参方法");
            }

            function ocCallJsHasParamsFunction(name, food){
                alert(name+"喜欢吃:"+url);
            }
        </script>
    </head>
    <body>
        <button style = "backgroud:red; width:100px; height:30px;" onclick = "click();">点我一下试试</button>
        <br>
        <a href = "http://www.baidu.com">百度一下,你就知道</a>
    </body>
</html>

  写完了一个简单的html5页面,接下来就要写JS调用OC以及OC调用JS了。首先,使用storyboard来搭建布局,当然你得拖约束。然后把刷新的Item的设置为Refresh。

  把webView拖为属性,把Refresh拖成方法,当点击这个按钮的时候刷新webView。

  - (IBAction)refresh:(id)sender{
      [self.webView reload];
  }

  接下来就可以设置webView的属性了。 使用webView加载网页,可以加载网络上的,也可以加载本地的,如果你需要加载的是网页上面的,那么你就需要在 info.plist 里面添加一个配置。

 

  加载本地的,你只需要得到本地html5页面的路径,就能在webView上面展示了。

    // 系统可以自动检测电话、链接、地址、日历、邮箱
    self.webView.dataDetectorTypes = UIDataDetectorTypeAll;
    self.webView.delegate = self;
    // 根据资源名,扩展名获取该资源对应的 URL
    NSURL *htmlUrl = [[NSBundle mainBundle] URLForResource:@"info.html" withExtension:nil];
    [self.webView loadRequest:[NSURLRequest requestWithURL:htmlUrl]];

    设置好了webView,现在运行起来,你应该是能看到效果的,如下图所示。

  先来讲一个OC调用JS方法,通过  - (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;  方法,我们就可以调用JS里面我们写好的方法了。这里呢,我把调用的方法放在     - (void)webViewDidFinishLoad:(UIWebView *)webView;    当webView加载完页面后调用JS里面的方法。实现OC调用JS。我写了两个方法,第一种是不带任何参数的,所以直接调用方法就可以,而第二种是带参数的,所以第二种方法写法会不一样,stringByEvaluatingJavaScriptFromString 只能带字符串,所以需要先通过stringWithFormat: 拼接字符串,然后把字符串传进去。

- (void)webViewDidFinishLoad:(UIWebView *)webView{
//   NSString *js = [webView stringByEvaluatingJavaScriptFromString:@"ocCallJsNoParamsFunction();"];
    NSString *js = [NSString stringWithFormat:@"ocCallJsHasParamsFunction(‘%@‘,‘%@‘)",@"哈哈",@"苹果"];
    // webView调用JS代码,等webView全部加载html界面之后调用
    [webView stringByEvaluatingJavaScriptFromString:js];
}

  OC调用JS的代码很简单,但是JS调用OC就有点困难了,因为这是iOS7以前的,那个时候没有出JavaScriptCore,所以开发起来有难度。下面来讲讲JS如何调用OC的代码。JS调用OC,并没有现成的API,可以使用"曲线救国"的方法,间接达到。在UIWebView内发起的所有网络请求,都可以通过delegate函数在原生界面得到通知。所以在html5页面发起一个特殊的网络请求,请求加载的网址内容通常不是真实的地址,OC中判断这个特殊的网络请求来实现不同的功能。

/**
 *  每当webview发送请求之前就会调用这个方法(js调用oc)
 */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //获得url全路径
    NSString *url = request.URL.absoluteString;
    NSString *protocol = @"jsoc://";

    // 判断url是否以protocol开头
    if([url hasPrefix:protocol]){
        //获得协议后面的路径,substringFromIndex:表示从指定位置开始截取字符串到最后,所截取位置包含该指定位置
        NSString *path = [url substringFromIndex:protocol.length];
        //利用占位符进行切割
        NSArray *subpaths =[path componentsSeparatedByString:@"?"];
        //获得方法名 jsoc://call_?100
        NSString *methodName = [[subpaths firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":"];
        NSArray *params = nil;
        if (subpaths.count == 2) {
            params = [[subpaths lastObject] componentsSeparatedByString:@"&"];
        }

        //调用方法
        SEL sel = sel_registerName([methodName UTF8String]);
        [self jsoc_performSelector:sel withObjects:params];

        return NO;
    }

    return YES;

}

  sel_registerName([xxx UTF8String]);  和 jsoc_performSelector:withObjects: 用到了runtime,所以还需要具备一些runtime的知识,sel只是一个指向方法的指针,一个根据方法名hash化了的KEY值,能唯一代表一个方法,它的存在只是为了加快方法的查询速度。然后通过自己定义的 jsoc_performSelector:withObjects: 来调用通过sel找到的这个方法。这里我们用了自定义的performSelector,是因为系统给的只能带一个或者两个参数,如果我想要带多个参数,那就只能通过自定义了。通过 sel 指向了一个方法,所以我们得把这个方法实现,这里我就简单的实现。

- (void)call:(NSString *)number{
    NSLog(@"参数:%@",number);
    NSLog(@"调用了oc的%s方法",__func__);
}

  下面就来讲讲自定义的 performSelector怎么实现。给NSObject添加一个Category,然后把jsoc_performSelecor:withObjects:实现以下。这里我们会用到 NSMethodSignature 和 NSInvocation,废话不多说,直接上代码。

- (id)jsoc_performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
    //NSInvocation 利用一个NSInvocation对象包装一次方法调用(方法调用者,方法名,方法参数,方法返回值)
    // 通过选择器获取方法签名
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if(signature == nil){
       NSString *reason = [NSString stringWithFormat:@"** The method[%@] is not find **",NSStringFromSelector(aSelector)];
       @throw [NSException exceptionWithName:@"错误!" reason:reason userInfo:nil];

    }
    // iOS中可以直接调用某个对象的消息方式有两种,其中一种就是NSInvocation(对于>2个的参数或者有返回值的处理) 另一种performSelector:withObject
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = aSelector;
    NSInteger paras = signature.numberOfArguments - 2;
    paras = MIN(paras, objects.count);

    for(NSInteger i=0;i<paras;i++){
        id object = objects[i];
        if([object isKindOfClass:[NSNull class]]) continue;
        // index从2开始 ,原因为:0 1 两个参数已经被target 和selector占用
        [invocation setArgument:&object atIndex:i+2];
    }
    //调用方法
    [invocation invoke];

    id returnValue = nil;
    if(signature.methodReturnLength){
        [invocation getReturnValue:&returnValue];
    }
    return returnValue;
}

  NSMethodSignature 是方法签名,官方定义该类为对方法的参数、返回类似进行封装,协同NSInvocation实现消息转发。

时间: 2024-10-24 09:30:17

OC与JS混合开发的相关文章

怎么让一个项目里swift与OC可以兼容混合开发?

在苹果推出了swift语言之后,很多人担心OC很快会被取代,但是苹果方面表示2年内不会摒弃OC.但现在也快了啊.有的开发团队已经开始基于swift开发,但是有很多旧的框架还没来得及用swift写出来,并且某些swift的功能你还不会写,想用OC写.因此在swift开发的程序中时不时会用到OC的类,怎么让两门语言在一个程序里无缝衔接? 其实很方便 如果你不是在董铂然博客园看到本文请 点击查看原文 如图这是一个新建的swift项目,里面直接拖入了一个SVProgressHUD框架 因为swift语言

关于混合开发,oc与js互相通信的方法总结:

最近做公司的几个项目,主要以为h5为主,不能实现的功能用oc来写,这样就经常牵扯到oc调用js,或者js调用oc.先插嘴一句,对于目前而言,我对H5包装下的app的用户体验是极其的不满,真的没法和原生比较.对注重用户体验的公司还是比较倾向与混合开发. 根据个人长期摸索,和开发踩过的坑,在这稍微总结一下下..网上有的基本都很零散,对于开发在使用还需要具体根据项目情况来使用. oc与js互相调用目前我知道的时主要有4种直接的方式: 1. 苹果的javascriptcore.framework框架;

浅谈混合开发与Android,JS数据交互

本文是作者原创,如转载请注明出处! 一.概论 现在时代已经走过了移动互联网的超级火爆阶段,市场上移动开发人员已经趋于饱和,显然,只会原生APP的开发已不能满足市场的需求,随着H5的兴起与火爆,H5在原生APP中的使用越来越广泛,也就是我们常说的混合开发(Hybrid APP).最新很火的微信小程序相信大家都是知道的,实际上微信小程序加载的界面就是一个HTML5的界面,HTML5界面在一些电商类的APP中主要承担展示数据的作用,但是他的作用并不仅限于此,最起码js调用原生方法和原生调用js的方法是

android混合开发,webview的java与js互操作

android原生应用,用webview加载应用中的网页,并且java代码与js代码可以互相操作. 这是混合开发的基石,最基本也最重要的东西,实验代码在这里. 概括说说—— java调js:调用webView.load("javascript:someFunction()"); 这样可以调用webView里页面上的全局方法.这不是什么新鲜东西,你在网页中也可以这么做,试试在浏览器地址栏输入javascript:alert("427studio");也可以在浏览器地址

iOS开发——网络开发OC篇&amp;OC与JS交互简单案例

OC与JS交互简单案例 网页开发中三个重要的知识,这里就不详细介绍了! Html:页面代码 Css:样式 javascript:响应 先来看一段html的简单代码,里面涉及了上面的三个部分(很简单) 1 <html> 2 <!--描述网页信息--> 3 <head> 4 <meta charset="UTF-8"/> 5 <title>hello world</title> 6 <script> 7 f

混合开发Js bridge新秀-DSBridge iOS篇

这个DSBridge 和我之前开发做的混合开发 用的方式 很相似,所以觉得很是不错,推荐给你大家. DSBridge-IOS:https://github.com/wendux/DSBridge-IOS DSBridge-Android:https://github.com/wendux/DSBridge-Android 与WebViewJavascriptBridge的对比请移步 DSBridge VS WebViewJavascriptBridge. 原文链接:http://www.jian

混合开发

1.混合开发概述 Hybrid App主要以JS+Native两者相互调用为主,从开发层面实现"一次开发,多处运行"的机制,成为真正适合跨平台的开发.Hybrid App兼具了Native App良好用户体验的优势,也兼具了Web App使用HTML5跨平台开发低成本的优势. 目前已经有众多Hybrid App开发成功应用,比如美团.爱奇艺.微信等知名移动应用,都是采用Hybrid App开发模式. 2.移动应用开发的三种方式比较 移动应用开发的方式,目前主要有三种: Native A

OC与JS的交互详解

事情的起因还是因为项目需求驱动.折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾. 我要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img > 标签自动加载,并把下载图片的操作放在native端来处理,并通过JS将图片在Cache中的地址返回给UIWebview. 之所以要把图片操作放在

Object-C与Swift混合开发

Object-C作为Apple的iOS App开发语言服务了许多个年头,2014年Apple推出了新的编程语言Swift,更高效更安全的口号再次吸引了一大批非iOS开发程序员进入,小编认为Swift取代Object-C只是时间问题,在神州这片土地上,毕竟技术普及有些落后,但再有两年左右时间Swift产品链将形成,第三方支持框架逐步完善,Swift必将成为iOS开发主流.目前来看,激进派的现状Swift与Object-C混合开发. Object-C中调用Swift 下面就给大家分享下Object-