美文网首页
iOS与js交互

iOS与js交互

作者: 代江波 | 来源:发表于2019-03-07 16:04 被阅读0次

1.UIWebview的js交互

iOS7之后苹果推出了JavaScriptCore这个框架,从而让web页面和本地原生应用交互起来非常方便,而且使用此框架可以做到Android那边和iOS相对统一,web前端写一套代码就可以适配客户端的两个平台,从而减少了web前端的工作量。

JavaScriptCore有如下几个类
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"
1>JSContext代表一个JavaScript的执行环境的一个实例。

创建方法

JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
2>JSValue的主要作用就是用来接收JSContext执行后的返回结果
<script type="text/javascript">
      var myObject = "myObject";
  </script>
JSValue *myObject = self.context[@"myObject"]; 
NSLog(@"%@",[myObject toString]);
3>JSManagedValue JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。
4>JSVirtualMachine JS运行的虚拟机,有独立的堆空间和垃圾回收机制。
5>JSExport 一个协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。

iOS调用js方法

#pragma mark  js代码
// 有参数
function numAddMethod(num1,num2){
    alert(num1 + num2);
    return num1 + num2;
}
// 无参数
function numAddMethod2(){
    alert('调用numAddMethod2');
}
#pragma mark  iOS方法
- (void)iOSMethod{
     //创建上下文
    JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //调用有参数的js方法
    JSValue *value = [context[@"numAddMethod"] callWithArguments:@[@(5),@(6)]];
    //调用无参数的js方法
    JSValue *value2 = [context[@"numAddMethod2"] callWithArguments:@[]];

    NSLog(@"有参数返回值=%d === 无参数返回值",value.toInt32,value2.toInt32);
     //打印结果,有参数返回值=11===无参数返回值0
}

js调用iOS方法

#pragma mark  js代码
<head>
    <script type = "text/javascript">
         function viewClicked(){
             share('1','2','3');
         }
     </script>
</head>
<body>
     <button type="button" onclick="viewClicked()">Click Me!</button>
</body>
#pragma mark  iOS代码
-(void)viewDidLoad{
    [super viewDidLoad];
    JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"share"] = ^(){
        NSArray *args = [JSContext currentArguments];
        for (JSValue *jsValue in args) {
            NSLog(@"%@",jsValue.toString);
        }
    };
    //arguments保存js传入的参数,打印结果为1,2,3.
}

WKWebView的js交互

首先来一段代码,来创建一个WKWebView


@interface WKWebViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>
    
@property (nonatomic, strong) WKWebView *webView;

@property (nonatomic, strong) WKUserContentController *userContent;

@end

@implementation WKWebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    self.userContent = [[WKUserContentController alloc] init];
   
    [self.userContent addScriptMessageHandler:self name:@"ocMethod"];
    
    config.userContentController = self.userContent;
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
}
    

特别关注WKUserContentController的addScriptMessageHandler:name:方法


/*! @abstract Adds a script message handler.
  //添加一个js要调用的方法
 @param scriptMessageHandler The message handler to add.
 //添加消息处理界面
 @param name The name of the message handler.
 //js要执行的方法名称
 @discussion Adding a scriptMessageHandler adds a function
 window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all
 frames.
  //需要js执行的方法规则
  //window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
 */
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

这个方法可能会引起内存泄漏,解决方法百度上有很多,这里不做说明。

1>iOS原生方法调用js方法
#pragram mark -- js代码
function jsMethod(obj){
    return obj;
}

#pragram mark -- iOS代码
- (void)iOSMethod{
    NSDictionary *dict = @{@"key1":@"value1",@"key2":@"value2"};
    NSData *dictData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
    NSString *dictStr = [[NSString alloc] initWithData:dictData encoding:NSUTF8StringEncoding];
    NSString *jsStr = [NSString stringWithFormat:@"jsMethod(%@)",dictStr];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"return == %@",result);
    }];
    //iOS给js传入多个参数可以通过转成字符串的方法传给js
    //打印结果为@{@"key1":@"value1",@"key2":@"value2"},说明js方法返回值都在result里面
}
    
2>js调用iOS原生方法
#pragram mark -- js代码
<head>
    <script type = "text/javascript">
         function viewClicked(){
             //固定写法,方法名为iOS原生要执行的方法(这里的方法名为ocMethod,上面已经注册过),参数放在()中
             window.webkit.messageHandlers.ocMethod.postMessage({'key':'value'});
         }
     </script>
</head>
<body>
     <button type="button" onclick="viewClicked()">Click Me!</button>
</body>

#pragram mark -- iOS代码
#pragram mark -- WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    NSString *messageName = message.name;
    if ([@"ocMethod" isEqualToString:messageName]) {
        id messageBody = message.body;
        NSLog(@"%@",messageBody);
        //当js调用ocMethod时,就可以来到这里,然后就可以在这里写iOS原生代码了,js所传的参数都在message.body里面了
    }
}

UIWebView和WKWebView与js交互的方法不能通用,项目在换webView时,会造成一点的麻烦。

使用WebViewJavascriptBridge可以适配两种webView

相关文章

网友评论

      本文标题:iOS与js交互

      本文链接:https://www.haomeiwen.com/subject/cdjcpqtx.html