1. 程式人生 > >OC與JS互動 初體會

OC與JS互動 初體會

第一篇部落格,有點小緊張、小期待,會不會有人看?有也好,沒有也罷,權當自己圖個樂兒,記錄近來學到的知識。閒話少說,進入正題!

OC與JS互動的方式:1、使用UIWebView通過攔截Request完成JS調取OC,通過stringByEvaluatingJavaScriptFromString注入JS函式或者取資料完成OC調取JS

2、使用WKWebView通過- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler完成OC調取JS,通過- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name攔截完成JS調取OC,還可以通過- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name完成JS呼叫OC

3、蘋果有提供JavaScriptCore庫,可以完成互動

4、第三方庫WebViewJavascriptBridge

 

一、使用UIWebView

攔截Request完成JS調取OC

 1 #pragma mark - UIWebViewDelegate
 2 
 3 /**
 4  這些都是JS響應的樣式
 5  UIWebViewNavigationTypeLinkClicked,        點選
 6  UIWebViewNavigationTypeFormSubmitted,      提交
 7  UIWebViewNavigationTypeBackForward,        返回
8 UIWebViewNavigationTypeReload, 重新整理 9 UIWebViewNavigationTypeFormResubmitted, 重複提交 10 UIWebViewNavigationTypeOther 其他 11 12 */ 13 // 載入所有請求資料,以及控制是否載入 14 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
15 16 NSLog(@"%@",request.URL.scheme); // 標識 我們自己協議 17 NSLog(@"%@",request.URL.host); // 方法名 18 NSLog(@"%@",request.URL.pathComponents); // 引數 19 20 // JS 呼叫OC 的原理就是 攔截URL 21 NSString *scheme = request.URL.scheme; 22 if ([scheme isEqualToString:@"custom"]) { 23 NSLog(@"來了,我們自定義的協議"); 24 25 NSArray *args = request.URL.pathComponents; 26 NSString *methodName = args[1]; 27 28 29 SEL methodSel = NSSelectorFromString(methodName); 30 if ([self respondsToSelector:methodSel]) { 31 32 [self performSelector:methodSel withObject:args[2]]; 33 34 } 35 36 return NO; 37 } 38 39 return YES; 40 }

通過stringByEvaluatingJavaScriptFromString注入JS函式或者取資料完成OC調取JS

// 載入完成
- (void)webViewDidFinishLoad:(UIWebView *)webView{
    //獲取title
    NSString *titlt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    self.title = titlt;
    
}

//呼叫JS函式
NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:@"showAlert('HELLO')"];

 

二、使用WKWebView

攔截Request

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURL *URL = navigationAction.request.URL;
    NSString *scheme = [URL scheme];
    if ([scheme isEqualToString:@"tzedu"]) {
        
        NSString *host = [URL host];
        if ([host isEqualToString:@"jsCallOC"]) {
            NSMutableDictionary *temDict = [self decoderUrl:URL];
            NSString *username = [temDict objectForKey:@"username"];
            NSString *password = [temDict objectForKey:@"password"];
            NSLog(@"%@---%@",username,password);
            
        }else{
            NSLog(@"不明地址 %@",host);
        }

        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    self.title = webView.title;
}

MessageHandler:

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeOC"];
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    //注意迴圈引用
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeOC"];
}
#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    
    NSLog(@"message == %@ --- %@",message.name,message.body);
    
}

OC調取JS:

 NSString *jsStr2 = @"showAlert('messageHandle:OC-->JS')";
    [self.webView evaluateJavaScript:jsStr2 completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];

三、JavaScriptCore

 

 JSContext:給JavaScript提供執行的上下文環境
 JSValue:JavaScript和Objective-C資料和方法的橋樑
 JSManagedValue:管理資料和方法的類
 JSVirtualMachine:處理執行緒相關,使用較少
 JSExport:這是一個協議,如果採用協議的方法互動,自己定義的協議必須遵守此協議
- (void)webViewDidFinishLoad:(UIWebView *)webView{
    
    NSString *titlt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    self.title = titlt;
    
    //JSContext就為其提供著執行環境 H5上下文
    JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext = jsContext;
    __weak typeof(self) weakSelf = self;

    // 異常處理
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        context.exception = exception;
        NSLog(@"exception == %@",exception);
        NSLog(@"%@",context);
    };
    
    // 提供給JS全域性變數
    [self.jsContext evaluateScript:@"var arr = [3, 'Hello', 'abc'];"];
    
    self.jsContext[@"showMessage"] = ^() {
        
        JSValue *thisValue = [JSContext currentThis];
        NSLog(@"thisValue = %@",thisValue);
        JSValue *cValue = [JSContext currentCallee];
        NSLog(@"cValue = %@",cValue);
        NSArray *args = [JSContext currentArguments];
        NSLog(@"來了:%@",args);
        
        NSDictionary *dict = @{@"name":@"cooci",@"age":@18};
        
        [[JSContext currentContext][@"ocCalljs"] callWithArguments:@[dict]];
    };
    
    // 因為是全域性變數 可以直接獲取
    JSValue *arrValue = self.jsContext[@"arr"];
    NSLog(@"arrValue == %@",arrValue);
    
    //糾正用法
//    JSValue *value = [JSValue valueWithObject:@"test“ inContext:context];
//    JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:value andOwner:self];

    
    self.jsContext[@"showDict"] = ^(JSValue *value) {
        //注意執行緒問題
        NSArray *args = [JSContext currentArguments];
        JSValue *dictValue = args[0];
        NSDictionary *dict = dictValue.toDictionary;
        NSLog(@"%@",dict);
        
        // 模擬用
        int num = [[arrValue.toArray objectAtIndex:0] intValue];
        num += 10;
        NSLog(@"arrValue == %@   num == %d",arrValue.toArray,num);
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.showLabel.text = dict[@"name"];
        });
    };
    
    
    //異常收集
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        weakSelf.jsContext.exception = exception;
        NSLog(@"exception == %@",exception);
    };
    
    
    // JS 操作物件
    KC_JSObject *kcObject = [[KC_JSObject alloc] init];
    self.jsContext[@"kcObject"] = kcObject;
    

    // 開啟相簿
    self.jsContext[@"getImage"] = ^() {
        
        weakSelf.imagePicker = [[UIImagePickerController alloc] init];
        weakSelf.imagePicker.delegate = weakSelf;
        weakSelf.imagePicker.allowsEditing = YES;
        weakSelf.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        [weakSelf presentViewController:weakSelf.imagePicker animated:YES completion:nil];
    };
    
}


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

@protocol KCProtocol <JSExport>

- (void)letShowImage;
JSExportAs(getSum, -(int)getSum:(int)num1 num2:(int)num2);

@end

@interface KC_JSObject : NSObject<KCProtocol>
@end



#import "KC_JSObject.h"

@implementation KC_JSObject

- (void)letShowImage{
    
    NSLog(@"開啟相簿,上傳圖片");
}

- (int)getSum:(int)num1 num2:(int)num2{
    return num1+num2;
}

@end

四、WebViewJavascriptBridge

https://github.com/marcuswestin/WebViewJavascriptBridge