iOS通过JavaScriptCore与JS交互

2016-05-10  本文已影响714人  来宝

项目中需要用到与H5端的JS交互,总结一下用法:
ios的 js 交互分为两块:
一、OC调用JS
这一块实现起来比较简单,一句代码搞定:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//首先创建JSContext对象、获取当前JS运行环境
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

 //无参的情况
    NSString *js1 = @"appMethod1()";
    [context evaluateScript:js1];
//只有一个参数的情况
   NSString *js2 = @"appMethod2('参数')"; 
   [context evaluateScript:js2];
//多个参数的情况
   NSString *js = [NSString stringWithFormat:@"appMethod3('%@','%@')",参数A,参数B];
   [context evaluateScript:js3];

//注:[webView stringByEvaluatingJavaScriptFromString:js]
与 [context evaluateScript:js]的功能的一样的;
}

后来项目中用到OC调用JS方法并传参的时候,发现上面的方法并不起作用,原因至今未找到,后来又找到了下面的方法可行:
-(void)webViewDidFinishLoad:(UIWebView *)webView{

//首先创建JSContext对象、获取当前JS运行环境
 JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
 JSValue *value = context[@"uploadPortrait"];
 [value callWithArguments:@[self.base64Image,self.imageName]];//两个参数
 [value callWithArguments:@[nil]];//无参的情况
}

注:OC调用JS的代码不一定写在webViewDidFinishLoad里面,可根据需要,写在所需的位置

二、JS调用OC

第一种情况: js端直接调用方法(block)

//其中test1就是js的方法名称,赋给是一个block 里面是iOS代码
    //此方法最终将打印出所有接收到的参数,js参数是不固定的 我们测试一下就知道
-(void)webViewDidFinishLoad:(UIWebView *)webView{
//首先创建JSContext对象、获取当前JS运行环境
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

//将我们的context对象与js方法建立桥接联系,
    context[@"test1"] = ^() {
        NSArray *arguments = [JSContext currentArguments];
        for (id obj in arguments) {
            NSLog(@"%@",obj);
        }
      };
  }
    //首先准备一下js代码,来调用js的函数test1 然后执行
    NSString *jsFunctStr=@"test1('参数1')";
    [context evaluateScript:jsFunctStr];
}

第二种情况:JS端通过对象调用(常用方法)
1、说到对象调方法我们首先肯定得有个对象,所以我们首先需要在OC端创建一个js交互类,并声明和实现相应的交互方法,
2、需要在这个自定义交互类里面导入JavaScriptCore框架
3、声明一个遵从于JSExport协议的协议(有点绕,看图),在这个协议里声明我们的交互方法(需要与JS端商定好方法名)

JSObjectUtil.h文件

#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h> //引入头文件
#import "JXPayViewVC.h"//支付

#pragma mark - 声明JS交互的协议,遵从于JSExport协议
//JSObjectDelegate为协议名
@protocol JSObjectDelegate <JSExport>

#pragma mark - JS调用OC的方法,此方法名与网页端沟通 必须名字相同
 //payOrder...这个方法没有,这个方法的作用是当js端的方法有两个或两个以上参数时,
//我们需要让- (void)payOrder:(NSString*)str appID:(NSString*)appID这个方法代替 “payForApp”这个方法,因为oc端的方法名必须和js端的保持一致,不然就不会被调用,如下:
 JSExportAs(payForApp, - (void)payOrder:(NSString*)str appID:(NSString*)appID); 
//此外,也可以自己拆分方法名,如:payForApp---->pay:xxx For:xxx App:xxx

//调用支付宝、微信支付(下面为OC端方法)
-(void)pay:(NSString *)params For:(NSString *)backParams App:(NSString *)payOrg;
@end

#pragma mark - 让我们创建的类实现上边的协议
@interface JSObjectUtil : NSObject<JSObjectDelegate>
//这里的payMoney可以用来直接调用JXPayViewVC类里面的任何方法
@property(nonatomic,strong)JXPayViewVC *payMoney;

@end

JSObjectUtil.m文件

#import "JSObjectUtil.h"
@implementation JSObjectUtil
//支付
//1、payForApp()是OC端的方法名,含有三个参数,因此需要对payForApp进行拆分加参数
//2、是通过OC端调用JS端的appMethod方法,同时JS端在appMethod方法里面套入需要调用OC端的方法名进行调用
//3、OC 端可以在被JS端调用的方法里面,让遵从交互协议类的对象调用此类里面的方法
-(void)pay:(NSString *)params For:(NSString *)payID App:(NSString *)payOrg
{
    NSLog(@"JS调用了OC的payForApp方法");
   //self.payMoney对象调用JXPayViewVC类的方法
    [self.payMoney sendPay:params payID:payID payOrder:payOrg];
}
@end

加载webView页面类的.m文件

-(void)webViewDidFinishLoad:(UIWebView *)webView{
    //加载JS交互
    [self loadJSObject:webView];
}
-(JSContext *)loadJSObject:(UIWebView *)webView{
    //1、首先创建JSContext对象、获取当前JS运行环境
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    //2、创建模型来调用方法
    JSObjectUtil *jsUtil = [JSObjectUtil new];
    jsUtil.payMoney = self;//让我们的交互类遵从协议

    //3、注入JS对象,其中"AppFunLoader"是JS的对象名,需要与JS端商定好名称,用它来调用下面的pay的appMethod方法
    context[@"AppFunLoader"] = jsUtil;

   //4、开始调用JS端的appMethod方法
    NSString *pay = @"appMethod()";
    [context evaluateScript:pay];
    
    return context;
}

上一篇下一篇

猜你喜欢

热点阅读