WKWebKit與JavaScript交互

WKWebKit與JavaScript交互

JS調(diào)用Native

WKWebKit支持JavaScript的3個彈窗函數(shù),WKUIDelegate提供3個代理方法與之對應(yīng)處理

  • alert()

js示例代碼

alert('你的操作有誤')

WKUIDelegate代理方法:

- (void)webView:(WKWebView *)webView 
runJavaScriptAlertPanelWithMessage:(NSString *)message 
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler 
{
    //message == “你的操作有誤”
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
   [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:
                      UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                          completionHandler();//用戶點擊“確定”通知js回調(diào)
                      }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
}
  • confirm()

js示例代碼

var userOperation = confirm('你確定要刪除嗎赃泡?') 
//confirm()的返回值是一個布爾值

WKUIDelegate代理方法:

- (void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(BOOL result))completionHandler 
{
    //message == "你確定要刪除嗎来农?"
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:
                                @"警告" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"是"
                                              style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
                                                  completionHandler(YES);//回調(diào)給js鞋真,通知用戶點擊了“是”。
                                              }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"否"
                                              style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                                                  completionHandler(NO);//回調(diào)給js沃于,通知用戶點擊了“否”灿巧。
                                              }]];
    [self presentViewController:alert animated:YES completion:NULL];
}

  • prompt()

js示例代碼

var text = prompt('提示','請輸入你的真實姓名') 
//prompt()的返回值是一個字符串

WKUIDelegate代理方法:

- (void)webView:(WKWebView *)webView
 runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt 
 defaultText:(nullable NSString *)defaultText 
 initiatedByFrame:(WKFrameInfo *)frame 
 completionHandler:(void (^)(NSString * _Nullable result))completionHandler 
{
    //prompt == "提示", defaultText == "請輸入你的真實姓名"
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:
                                    prompt message:defaultText
                                                                preferredStyle:UIAlertControllerStyleAlert];
   [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            textField.textColor = [UIColor redColor];
        }];
   [alert addAction:[UIAlertAction actionWithTitle:@"完成"
                                                  style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                                                      completionHandler([[alert.textFields lastObject] text]);
                                                      //用戶輸入的文本回調(diào)給js
                                                  }]];
        
   [self presentViewController:alert animated:YES completion:NULL];
}

JavaScript調(diào)用Navtive自定義類的接口

WKWebView中的js runtime里事先注入了一個window.webkit.messageHandlers.{NAME}.postMessage()方法揽涮,我們可以使用這個方法直接向Native層傳一個消息對象抠藕。其中{NAME}是一個WKScriptMessageHandler對象的名稱,WKWebView事先注冊這個名稱蒋困,Native接收到JS傳來的消息盾似,可以用這個名稱進行區(qū)別處理。

JS給Native發(fā)送消息對象

var message = {'methodName':methodName,'params':params,'callBackName':callBackName};
window.webkit.messageHandlers.TDWebKit.postMessage(message);
//TDWebKit是iOS客戶端與web端約定好的一個消息處理對象名稱
//message對象具體字段也需要客戶端與web端約定好

js如果需要得到客戶端返回的消息,需要一個寫一個callBack回調(diào)函數(shù)

callBackName:function(data){
    //to do something...
},

客戶端創(chuàng)建一個WKScriptMessageHandler對象來處理JS發(fā)過來的消息對象

TDMessageHandler.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
#import "FMMacros.h"

extern NSString *const TDWebKit;

@interface TDMessageHandler : NSObject<WKScriptMessageHandler>
SINGLETON_DECLARE()
- (void)joinWebView:(WKWebView *)webView;
@end

TDMessageHandler.m

#import "TDMessageHandler.h"

NSString *const TDWebKit = @"TDWebKit";

@interface TDMessageHandler ()
@property (nonatomic,   weak) WKWebView *webView;
@end

@implementation TDMessageHandler

SINGLETON_IMPL(TDMessageHandler)

- (void)joinWebView:(WKWebView *)webView {
    self.webView = webView;
}

#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    
    if ([message.name isEqualToString:TDWebKit]) {
        NSString *methodName = message.body[@"methodName"];
        NSDictionary *params = message.body[@"params"];
        NSString *callBackName = message.body[@"callBackName"];
        if (callBackName) {
            
            WeakSelf()
            [self interactWitMethodName:methodName params:params callBack:^(id response) {
                //native調(diào)用js零院,web端需要有一個回調(diào)函數(shù)callBackName(response);
                NSString *js = [NSString stringWithFormat:@"%@('%@');",callBackName,response];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.webView evaluateJavaScript:js completionHandler:^(id _Nullable data, NSError * _Nullable error) {
                        
                        if (error) {
                            NSLog(@"native調(diào)用js失敻仍尽: %@",[error localizedDescription]);
                        }
                        
                    }];
                });
            }];
        }
        else{
            
            [self interactWitMethodName:methodName params:params callBack:nil];
        }
    }
}

- (void)interactWitMethodName:(NSString *)methodName params:(NSDictionary *)params callBack:(void(^)(id response))callBack{
    
    if (params) {
        methodName = [methodName stringByAppendingString:@":"];
        if (callBack) {
            methodName = [methodName stringByAppendingString:@"callBack:"];
            SEL selector = NSSelectorFromString(methodName);
            NSArray *paramArray =@[params,callBack];
            if ([self respondsToSelector:selector]) {
                [self performSelector:selector withObjects:paramArray];
            }
        }
        else {
            SEL selector = NSSelectorFromString(methodName);
            NSArray *paramArray =@[params];
            if ([self respondsToSelector:selector]) {
                [self performSelector:selector withObjects:paramArray];
            }
        }
    }
    else{
        
        if (callBack) {
            methodName = [methodName stringByAppendingString:@":"];
            SEL selector = NSSelectorFromString(methodName);
            NSArray *paramArray =@[callBack];
            if ([self respondsToSelector:selector]) {
                [self performSelector:selector withObjects:paramArray];
            }
        }
        
        else {
            SEL selector = NSSelectorFromString(methodName);
            if ([self respondsToSelector:selector]) {
                [self performSelector:selector withObjects:nil];
            }
            
        }
        
    }
}

- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
    NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:self];
    [invocation setSelector:aSelector];
    
    NSUInteger i = 1;
    
    for (id object in objects) {
        id tempObject = object;
        [invocation setArgument:&tempObject atIndex:++i];
    }
    [invocation invoke];
    
    if ([signature methodReturnLength]) {
        id data;
        [invocation getReturnValue:&data];
        return data;
    }
    return nil;
}

@end

這里建一個TDMessageHandler的分類,在分類里提供JS發(fā)送消息處理的接口

TDMessageHandler+WebKit.h

#import "TDMessageHandler.h"

@interface TDMessageHandler (WebKit)

- (void)todo;

- (void)share:(NSDictionary *)params callBack:(void(^)(BOOL success))callBack;

- (void)getPhoto:(void(^)(UIImage *image))callBack;

@end

TDMessageHandler+WebKit.m

#import "TDMessageHandler+WebKit.h"

@implementation TDMessageHandler (WebKit)

- (void)todo {
    NSLog(@"to do something...");
}

- (void)share:(NSDictionary *)params callBack:(void(^)(BOOL success))callBack {
    //params 分享所需要的參數(shù)
    if (callBack) {
         //分享是否成功回調(diào)給JS
        callBack(true);
    }
}

- (void)getPhoto:(void(^)(UIImage *image))callBack {

    //TODO 調(diào)用系統(tǒng)相機或者相冊
    if (callBack) {
       //選出的相片回調(diào)給JS
        callBack([UIImage new]);
    }
}

@end

WKWebView注冊一個名稱為TDWebKitTDMessageHandler對象

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
[config.userContentController addScriptMessageHandler:[TDMessageHandler sharedInstance] name:TDWebKit];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];

Native調(diào)用JS

WKWebView可以事先注入一段JS

NSString JSString = @"js string...";
WKUserScript *usrScript = [[WKUserScript alloc] initWithSource:JSString injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init]; 
config.userContentController = [[WKUserContentController alloc] init]; 
[config.userContentController addUserScript:usrScript];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];

Native調(diào)用JS

[self.webView evaluateJavaScript:@"js.aFunction()" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
                        
       if (error) {
           NSLog(@"native調(diào)用js失敻娉: %@",[error localizedDescription]);
       }
                        
 }];

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撰茎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子打洼,更是在濱河造成了極大的恐慌龄糊,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募疮,死亡現(xiàn)場離奇詭異炫惩,居然都是意外死亡,警方通過查閱死者的電腦和手機阿浓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門他嚷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人芭毙,你說我怎么就攤上這事筋蓖。” “怎么了退敦?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵纹因,是天一觀的道長舆驶。 經(jīng)常有香客問我摧玫,道長泡躯,這世上最難降的妖魔是什么房交? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任挠日,我火速辦了婚禮诵棵,結(jié)果婚禮上舶胀,老公的妹妹穿的比我還像新娘两蟀。我一直安慰自己网梢,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布赂毯。 她就那樣靜靜地躺著战虏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪党涕。 梳的紋絲不亂的頭發(fā)上烦感,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音膛堤,去河邊找鬼手趣。 笑死,一個胖子當(dāng)著我的面吹牛肥荔,可吹牛的內(nèi)容都是我干的绿渣。 我是一名探鬼主播朝群,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼中符!你這毒婦竟也來了姜胖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤淀散,失蹤者是張志新(化名)和其女友劉穎右莱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吧凉,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡隧出,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阀捅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胀瞪。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饲鄙,靈堂內(nèi)的尸體忽然破棺而出凄诞,到底是詐尸還是另有隱情,我是刑警寧澤忍级,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布帆谍,位于F島的核電站,受9級特大地震影響轴咱,放射性物質(zhì)發(fā)生泄漏汛蝙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一朴肺、第九天 我趴在偏房一處隱蔽的房頂上張望窖剑。 院中可真熱鬧,春花似錦戈稿、人聲如沸西土。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽需了。三九已至,卻和暖如春般甲,著一層夾襖步出監(jiān)牢的瞬間肋乍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工敷存, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留住拭,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像滔岳,于是被迫代替她去往敵國和親杠娱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容