UIWebView(OC)与JS(JavaScript)交互

  1. 获取UIWebView的JSContext
通过
JSContext* context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
获取的context不能保证新建的webview的context能及时的获取到,导致context调用当前环境的js函数失效。

下面我们通过Apple的私有Api获取JSContext ,这个方法是监控JSContext的创建来获取的。经过测试,经过处理过的私有API是可以上架苹果市场的。

/**
 其实是private api 通过监控这个方法是否调用实时知道jscontext是否创建;这个是依赖web上是否执行script,执行时会检查是否实现了下面的方法

 @param unused class 为WebView
 @param ctx 当前UIWebView运行的JSContext环境
 @param frame  WebFrameLoadDelegate   WebKit的WebFrame
 */
- (void) webView: (id) unused didCreateJavaScriptContext: (JSContext*) ctx forFrame: (id) frame
{
    
    NSString *frameMehtod = [NSString stringWithUTF8String:webFrameBase64Str];
    NSData *frameData = [[NSData alloc]initWithBase64EncodedString:frameMehtod options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSString *frameStr = [[NSString alloc]initWithData:frameData encoding:NSUTF8StringEncoding];
    SEL frameSelector = NSSelectorFromString(frameStr);
    //     only interested in root-level frames
    if ([frame respondsToSelector:frameSelector] && [frame parentFrame] != nil ) {
        return;
    }
    
    void (^didCreateJavaScriptContext)() = ^{
        
        for (UIWebView *webv in webviews) {
            
            NSString *webIdentifier =  [NSString stringWithFormat:@"rain_jsWebView_%lud",(NSUInteger)webv.hash];
            
            NSString *jsAddVariable = [NSString stringWithFormat:@"var %@ = '%@'",webIdentifier,webIdentifier];
            
            [webv stringByEvaluatingJavaScriptFromString:jsAddVariable];//为webView添加个唯一标识符变量
            
            JSValue *identifierJSValue = ctx[webIdentifier];//通过这个获取当前的标识符的值[ctx objectForKeyedSubscript:webIdentifier];
            
            if ([identifierJSValue.toString isEqualToString:webIdentifier]) {
                [webv rainDidCreateJavaScriptContext:ctx];
                return ;
            }
            
        }
        
    };
    
    if ([NSThread isMainThread]) {
        didCreateJavaScriptContext();
    }else {
        dispatch_async(dispatch_get_main_queue(), didCreateJavaScriptContext);
        
    }
    
}
  1. Native调用JS函数

多种方式:

/*第一个方式,我把获取到的JSContext作为webview的一个属性了,方便随时拿来使用*/

- (void)webViewDidFinishLoad:(UIWebView *)webView {
   
 [self.webView.context evaluateScript:@"jsFunction('native调用了js的函数')"];
 
}


/*第二个方式,通过jscontext和jsvalue来调用*/
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    
  JSValue *jsFunctionValue = self.webView.context[@"jsFunction"];
   [jsFunctionValue callWithArguments:@[@"native调用了js的函数"]];

}
/*第三个方式:通过webview调用*/
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    
     [self.webView stringByEvaluatingJavaScriptFromString:@"jsFunction('native调用了js的函数')"];

}

  1. JS调用Native方法
a、通过block设置
self.webview.context[@"jsCallNative"] = ^(NSString *message){
  NSLog(message);
}
在h5里直接调用jsCallNative('我来调用Native方法了')就好了

b、通过JSExport协议调用
某个类作为实现JSExport协议,然后把这个类对象作为JS的对象,通过调用JS对象的相应函数即可调起该类对象的方法


定义继承JSExport的协议
@protocol RainJSExportProtocol

/**
 js 打印日志时调用这个,方便native查看日志

 @param log js打印日志调用的函数名
 @param void js方法映射到native上的方法
 @return void
 */
JSExportAs(log, - (void)debugLog:(NSString *)message);

/**
 js 调用本地定义的一个方法

 @param callNative js 调用的函数名
 @param void js callNative映射到本地的方法名
 @return void
 */
JSExportAs(callNative, - (void)callInterface:(NSString *)interface parameters:(NSString *)jsonStr);


//也可以直接定义方法名,对应js调用的时候去掉冒号:参数第一个字母大写;
//比如 -(void)myName:(NSString *)name age:(NSString *)myage height:(NSString *)myheight; js调用native这个方法时这样调用native.myNameAgeHeight('name','15','172')

@end

以下是实现了RainJSExportProtocol协议的类

#pragma mark-- RainJSExportProtocol

- (void)debugLog:(NSString *)message {
    
#ifdef DEBUG
    
    NSLog(@"%@",message);
    
#endif
    
}

- (void)callInterface:(NSString *)interface parameters:(NSString *)jsonStr {
    
    NSLog(@"interface %@  jsonStr %@",interface,jsonStr);
    
}

比如该类在JS里被定义为native对象:context[@"native"] = self;//把self当做对jscontext对方开放的对象

那js就可以这样调用

native.log('打印日志');
native. callNative('第一个参数','第二个参数');

放出demo地址

更新时间:2018-06-28

你可能感兴趣的:(UIWebView(OC)与JS(JavaScript)交互)