项目中需要用到与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;
}