JS 调用 OC

参考 http://blog.youkuaiyun.com/lwjok2007/article/details/47058795

添加 框架
这里写图片描述



#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "TestObject.h"

@interface ViewController ()<UIWebViewDelegate>

{
    UIWebView *myWebView;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //初始化webview
    myWebView=[[UIWebView alloc]initWithFrame:CGRectMake(0, 22, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-22)];
    myWebView.delegate=self;
    //添加webview到当前viewcontroller的view上
    [self.view addSubview:myWebView];

    //网址
    NSString *httpStr=@"https://www.baidu.com";
    NSURL *httpUrl=[NSURL URLWithString:httpStr];
    NSURLRequest *httpRequest=[NSURLRequest requestWithURL:httpUrl];
    [myWebView loadRequest:httpRequest];
}

#pragma mark --webViewDelegate
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //网页加载之前会调用此方法

    //retrun YES 表示正常加载网页 返回NO 将停止网页加载
    return YES;
}

-(void)webViewDidStartLoad:(UIWebView *)webView
{
    //开始加载网页调用此方法
}

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
    //网页加载完成调用此方法

    //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
    JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    NSString *alertJS=@"alert('test js OC')"; //准备执行的js代码
    [context evaluateScript:alertJS];//通过oc方法调用js的alert

//    //js调用iOS
//    //第一种情况
//    //其中test1就是js的方法名称,赋给是一个block 里面是iOS代码
//    //此方法最终将打印出所有接收到的参数,js参数是不固定的 我们测试一下就知道
//    context[@"test1"] = ^() {
//        NSArray *args = [JSContext currentArguments];
//        for (id obj in args) {
//            NSLog(@"%@",obj);
//        }
//    };
//    //此处我们没有写后台(但是前面我们已经知道iOS是可以调用js的,我们模拟一下)
//    //首先准备一下js代码,来调用js的函数test1 然后执行
//    //一个参数
//    NSString *jsFunctStr=@"test1('参数1')";
//    [context evaluateScript:jsFunctStr];
//    
//    //二个参数
//    NSString *jsFunctStr1=@"test1('参数a','参数b')";
//    [context evaluateScript:jsFunctStr1];

    //第二种情况,js是通过对象调用的,我们假设js里面有一个对象 testobject 在调用方法
    //首先创建我们新建类的对象,将他赋值给js的对象

    TestObject *testJO=[TestObject new];
    context[@"testobject"]=testJO;

    //同样我们也用刚才的方式模拟一下js调用方法
    NSString *jsStr1=@"testobject.TestNOParameter()";
    [context evaluateScript:jsStr1];
    NSString *jsStr2=@"testobject.TestOneParameter('参数1')";
    [context evaluateScript:jsStr2];
    NSString *jsStr3=@"testobject.TestTowParameterSecondParameter('参数A','参数B')";
    [context evaluateScript:jsStr3];
}

-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    //网页加载失败 调用此方法
}
@end

创建这里写图片描述
.h

#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol TestJSObjectProtocol <JSExport>
//此处我们测试几种参数的情况
-(void)TestNOParameter;
-(void)TestOneParameter:(NSString *)message;
-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2;
@end

@interface TestObject : NSObject <TestJSObjectProtocol>


@end

.m

#import "TestObject.h"

@implementation TestObject
//一下方法都是只是打了个log 等会看log 以及参数能对上就说明js调用了此处的iOS 原生方法
-(void)TestNOParameter
{
    NSLog(@"this is ios TestNOParameter");
}
-(void)TestOneParameter:(NSString *)message
{
    NSLog(@"this is ios TestOneParameter=%@",message);
}
-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2
{
    NSLog(@"this is ios TestTowParameter=%@  Second=%@",message1,message2);
}
@end

测试结果

2016-08-08 17:09:46.452 TestJSOC[36171:2437167] this is ios TestNOParameter
2016-08-08 17:09:46.453 TestJSOC[36171:2437167] this is ios TestOneParameter=参数1
2016-08-08 17:09:46.453 TestJSOC[36171:2437167] this is ios TestTowParameter=参数A  Second=参数B

参考 Demo:https://github.com/shaojiankui/JavaScriptCore-Demo

下载下来看:

有趣的结构:
这里写图片描述

html 放在本地,估计是只是为了让人容易看懂,html丢在服务器才好修改的、本地不如用原生、
然后放出关键代码
1. JS 调用OC
.html

<!doctype html>
<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>JSCallOC</title>

    <style>
        *
        {
            //-webkit-tap-highlight-color: rgba(0,0,0,0);
            text-decoration: none;
        }

        html,body
        {
            -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
            -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
            -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
        }

        #div-a
        {
            background:#FBA;
            color:#FFF;

            border-radius: 25px 5px;
        }


    </style>

    <script type="text/javascript">

        function showResult(resultNumber)
        {
            //alert(resultNumber);
            document.getElementById("result").innerText = resultNumber;
        }

    </script>

</head>

<body style="background:#CDE; color:#FFF">

    <div>
        <font size="3" color="black">输入一个整数:</font>
        <textarea  id="input" style="font-size:10pt;color:black;"></textarea>
    </div>
    <br/>

    <div>
        <font size="3" color="black">结果: <b id="result"> </b> </font>
    </div>
    <br/>

    <div id="div-a">
        <center>

            <br/>
            <input type="button" value="计算阶乘" onclick="native.calculateForJS(input.value);" />
            <br/>
            <br/>


            <input type="button" value="测试log" onclick="log('测试');" />
            <br/>
            <br/>

            <input type="button" value="oc原生Alert" onclick="alert('alert');" />
            <br/>
            <br/>

            <input type="button" value="addSubView" onclick="addSubView('view');" />
            <br/>
            <br/>
            <input type="button" value="多参数调用" onclick="mutiParams('参数1','参数2','参数3');" />
            <br/>
            <br/>
            <a id="push" href="#" onclick="native.pushViewControllerTitle('SecondViewController','secondPushedFromJS');">
                push to second ViewController
            </a>

            <br/>
            <br/>

        </center>
    </div>



</body>

</html>

.h

#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>

@protocol TestJSExport <JSExport>
JSExportAs
(calculateForJS  /** handleFactorialCalculateWithNumber 作为js方法的别名 */,
 - (void)handleFactorialCalculateWithNumber:(NSNumber *)number
 );
- (void)pushViewController:(NSString *)view title:(NSString *)title;
@end



@interface JSCallOCViewController : UIViewController<UIWebViewDelegate,TestJSExport>
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@property (strong, nonatomic) JSContext *context;
@end

.m


#import "JSCallOCViewController.h"
#import "SecondViewController.h"
@interface JSCallOCViewController ()

@end

@implementation JSCallOCViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"js call oc";

    NSString *path = [[[NSBundle mainBundle] bundlePath]  stringByAppendingPathComponent:@"JSCallOC.html"];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
    [self.webView loadRequest:request];
}

#pragma mark - UIWebViewDelegate

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    // 以 html title 设置 导航栏 title
    self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    // 禁用 页面元素选择
    //[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];

    // 禁用 长按弹出ActionSheet
    //[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];

    // Undocumented access to UIWebView's JSContext
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    // 打印异常
    self.context.exceptionHandler =
    ^(JSContext *context, JSValue *exceptionValue)
    {
        context.exception = exceptionValue;
        NSLog(@"%@", exceptionValue);
    };

    // 以 JSExport 协议关联 native 的方法
    self.context[@"native"] = self;

    // 以 block 形式关联 JavaScript function
    self.context[@"log"] =
    ^(NSString *str)
    {
        NSLog(@"%@", str);
    };

    // 以 block 形式关联 JavaScript function
    self.context[@"alert"] =
    ^(NSString *str)
    {
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"msg from js" message:str delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
        [alert show];
    };

    __block typeof(self) weakSelf = self;
    self.context[@"addSubView"] =
    ^(NSString *viewname)
    {
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 500, 300, 100)];
        view.backgroundColor = [UIColor redColor];
        UISwitch *sw = [[UISwitch alloc]init];
        [view addSubview:sw];
        [weakSelf.view addSubview:view];
    };
    //多参数
    self.context[@"mutiParams"] =
    ^(NSString *a,NSString *b,NSString *c)
    {
        NSLog(@"%@ %@ %@",a,b,c);
    };

}

#pragma mark - JSExport Methods

- (void)handleFactorialCalculateWithNumber:(NSNumber *)number
{
    NSLog(@"%@", number);

    NSNumber *result = [self calculateFactorialOfNumber:number];

    NSLog(@"%@", result);

    [self.context[@"showResult"] callWithArguments:@[result]];
}

- (void)pushViewController:(NSString *)view title:(NSString *)title
{
    Class second = NSClassFromString(view);
    id secondVC = [[second alloc]init];
    ((UIViewController*)secondVC).title = title;
    [self.navigationController pushViewController:secondVC animated:YES];
}

#pragma mark - Factorial Method

- (NSNumber *)calculateFactorialOfNumber:(NSNumber *)number
{
    NSInteger i = [number integerValue];
    if (i < 0)
    {
        return [NSNumber numberWithInteger:0];
    }
    if (i == 0)
    {
        return [NSNumber numberWithInteger:1];
    }

    NSInteger r = (i * [(NSNumber *)[self calculateFactorialOfNumber:[NSNumber numberWithInteger:(i - 1)]] integerValue]);

    return [NSNumber numberWithInteger:r];
}



@end

**

发现JS 调用OC 是在完成加载里面
分为1。点击事件。 2.方法传递。
点击事件
.html

 <input type="button" value="测试log" onclick="log('测试');" />

点击到就会传递log(‘测试’);
用上下文以block的形式传递字符串过来。

 // 以 block 形式关联 JavaScript function
    self.context[@"log"] =
    ^(NSString *str)
    {
        NSLog(@"%@", str);
    };

判断是@”log”字符串 处理里面的内容。
方法传递
.html

<a id="push" href="#" onclick="native.pushViewControllerTitle('SecondViewController','secondPushedFromJS');">
                push to second ViewController
 </a>

以代理的形式传递过来,OC 再实现JS的代理功能。


@protocol TestJSExport <JSExport>
JSExportAs
- (void)pushViewController:(NSString *)view title:(NSString *)title;
@end
- (void)pushViewController:(NSString *)view title:(NSString *)title
{
Class second = NSClassFromString(view);
id secondVC = [[second alloc]init];
((UIViewController*)secondVC).title = title;
[self.navigationController pushViewController:secondVC animated:YES];
}
**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值