WebView和JS交互

第一種方式

JS傳值給OC

  • 1猬膨、技術方案:使用自定義url方法角撞,每次點擊網(wǎng)頁
  • 2呛伴、使用場景:比如點擊事件方法,點擊網(wǎng)頁的某個方法谒所,將該方法的參數(shù)傳值給OC热康,供OC使用。
  • 3劣领、代碼實現(xiàn)如下:
一姐军、js要實現(xiàn)的
  • 1 、 創(chuàng)建一個.js文件:
;(function() {
    var messagingIframe,
        bridge = 'external',
// wmcall是自定義的協(xié)議頭
        CUSTOM_PROTOCOL_SCHEME = 'wmcall';
    if (window[bridge]) { return }
    function _createQueueReadyIframe(doc) {
        messagingIframe = doc.createElement('iframe');
        messagingIframe.style.display = 'none';
        doc.documentElement.appendChild(messagingIframe);
    }
    window[bridge] = {};
    var methods = [%@];
    for (var i=0;i<methods.length;i++){
        var method = methods[i];
        var code = "(window[bridge])[method] = function " + method + "() {messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + ':' + arguments.callee.name + ':' + encodeURIComponent(JSON.stringify(arguments));}";
        eval(code);
    }
  
    //創(chuàng)建iframe尖淘,必須在創(chuàng)建external之后奕锌,否則會出現(xiàn)死循環(huán)
    _createQueueReadyIframe(document);
    //通知js開始初始化
    //initReady();
})();
二、oc要實現(xiàn)的代碼
  • 2村生、 創(chuàng)建文件WebViewJsBridge.h惊暴, 繼承UIWebViewDelegate
#import <Foundation/Foundation.h>

#define kCustomProtocolScheme @"wmcall"
#define kBridgeName           @"external"

@interface WebViewJsBridge : NSObject<UIWebViewDelegate>

@property (nonatomic, weak) UIWebView *webView;

+ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(NSObject<UIWebViewDelegate>*)webViewDelegate;
+ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(NSObject<UIWebViewDelegate>*)webViewDelegate resourceBundle:(NSBundle*)bundle;

- (void)excuteJSWithObj:(NSString *)obj function:(NSString *)function;

@end
  • WebViewJsBridge.m
#import "WebViewJsBridge.h"
#import <objc/runtime.h>

@interface WebViewJsBridge ()

@property (nonatomic, weak) id webViewDelegate;
@property (nonatomic, weak) NSBundle *resourceBundle;

@end

@implementation WebViewJsBridge

+ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(NSObject<UIWebViewDelegate>*)webViewDelegate {
    return [self bridgeForWebView:webView webViewDelegate:webViewDelegate resourceBundle:nil];
}

+ (instancetype)bridgeForWebView:(UIWebView*)webView webViewDelegate:(NSObject<UIWebViewDelegate>*)webViewDelegate resourceBundle:(NSBundle*)bundle
{
    WebViewJsBridge* bridge = [[[self class] alloc] init];
    [bridge _platformSpecificSetup:webView webViewDelegate:webViewDelegate resourceBundle:bundle];
    return bridge;
}

#pragma mark - init & dealloc

- (void) _platformSpecificSetup:(UIWebView*)webView webViewDelegate:(id<UIWebViewDelegate>)webViewDelegate resourceBundle:(NSBundle*)bundle{
    _webView = webView;
    _webViewDelegate = webViewDelegate;
    _webView.delegate = self;
    _resourceBundle = bundle;
}

- (void)dealloc {
    _webView.delegate = nil;
    _webView = nil;
    _webViewDelegate = nil;
}

#pragma mark - UIWebView Delegate

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if (webView != _webView) { return; }
    //is js insert
    if (![[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"typeof window.%@ == 'object'", kBridgeName]] isEqualToString:@"true"]) {
        //get class method dynamically
        unsigned int methodCount = 0;
        Method *methods = class_copyMethodList([self class], &methodCount);
        NSMutableString *methodList = [NSMutableString string];
        for (int i=0; i<methodCount; i++) {
            NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
            //防止隱藏的系統(tǒng)方法名包含“.”導致js報錯
            if ([methodName rangeOfString:@"."].location!=NSNotFound) {
                continue;
            }
            [methodList appendString:@"\""];
            [methodList appendString:[methodName stringByReplacingOccurrencesOfString:@":" withString:@""]];
            [methodList appendString:@"\","];
        }
        if (methodList.length>0) {
            [methodList deleteCharactersInRange:NSMakeRange(methodList.length-1, 1)];
        }
        free(methods);
        NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle];
        NSString *filePath = [bundle pathForResource:@"WebViewJsBridge" ofType:@"js"];
        NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
        [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:js, methodList]];
    }
    
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
        [strongDelegate webViewDidFinishLoad:webView];
    }
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    if (webView != _webView) { return; }
    
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
        [strongDelegate webView:webView didFailLoadWithError:error];
    }
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (webView != _webView) { return YES; }

    NSURL *url = [request URL];
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    // 拿到網(wǎng)頁的實時url
    NSString *requestString = [[request URL] absoluteString];
//在url中尋找自定義協(xié)議頭"wmcall"
    if ([requestString hasPrefix:kCustomProtocolScheme]) {
// 以":"為中心將url分割成兩部分,放進數(shù)組arr趁桃。辽话。是否取“:”或者“://”需要跟寫交互的確定下
        NSArray *components = [[url absoluteString] componentsSeparatedByString:@":"];
        // 取其后半段
        NSString *function = (NSString*)[components objectAtIndex:1];
        NSString *argsAsString = [(NSString*)[components objectAtIndex:2]
                                  stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSData *argsData = [argsAsString dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *argsDic = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:argsData options:kNilOptions error:NULL];
//以":"為標識將后半段url分割成若干部分,放進數(shù)組arr2卫病,此時arr2[0]為空油啤,arr2[1]為第一個傳參值,arr2[2]為第二個傳參值蟀苛,以此類推
        //convert js array to objc array
        NSMutableArray *args = [NSMutableArray array];
//取出參數(shù)益咬,進行使用
        for (int i=0; i<[argsDic count]; i++) {
            [args addObject:[argsDic objectForKey:[NSString stringWithFormat:@"%d", i]]];
        }
        //ignore warning
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        SEL selector = NSSelectorFromString([args count]>0?[function stringByAppendingString:@":"]:function);
        if ([self respondsToSelector:selector]) {
            [self performSelector:selector withObject:args];
        }
        return NO;
    } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
        return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
    } else {
        return YES;
    }
}

- (void)webViewDidStartLoad:(UIWebView *)webView {
    if (webView != _webView) { return; }
    
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
        [strongDelegate webViewDidStartLoad:webView];
    }
}

#pragma mark - call js

//執(zhí)行js方法
- (void)excuteJSWithObj:(NSString *)obj function:(NSString *)function {
    NSString *js = function;
    if (obj) {
        js = [NSString stringWithFormat:@"%@.%@", obj, function];
    }
    [self.webView stringByEvaluatingJavaScriptFromString:js];
}


@end

三、使用案例
  • 1帜平、創(chuàng)建橋接文件WebViewJsBridge.h
  • .h
#import "WebViewJsBridge.h"

typedef void(^bridge_callback)(NSString* method, NSArray* params);

@interface BeeWebViewBridge : WebViewJsBridge
@property (nonatomic, strong) bridge_callback block_bridge_callback;
- (void)setBlock_bridge_callback:(bridge_callback)block_bridge_callback;
- (void)check_exist;
@end
  • .m
#import "BeeWebViewBridge.h"
@implementation BeeWebViewBridge
//圖片展示
- (void)show_image:(NSArray *)params
{
    if(_block_bridge_callback)
    {
        _block_bridge_callback(@"show_image", params);
    }
}
@end

oc傳值給js

  • 在webviewcontroller里面實現(xiàn)如下代碼:
//通過paramsName础废,匹配需要傳什么值
- (void)callByValueWithParamsName:(NSString *)paramsName
{
    //要傳出去的值
    NSString *value = @"";
    if ([paramsName isEqualToString:@"access_token"]) {
        value = [CMCore get_access_token]?:@"";
    }
    //方法1
    NSString *jsMethode = [NSString stringWithFormat:@"set_params('%@')",value];
    [_web_view stringByEvaluatingJavaScriptFromString:jsMethode];
    //方法2
    //        NSString *jsMethode = [NSString stringWithFormat:@"set_params('%@')",value];
    //        JSContext *context = [_web_view valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //        [context evaluateScript:jsMethode];
    //方法3
    //  [_bridge excuteJSWithObj:value function:paramsName];
}

分割線


第二種:利用第三方庫實現(xiàn)JS與OC的相互傳值。

原作者鏈接

  • 1罕模、 技術方案:使用WebViewJavascriptBridge三方庫
  • 2、 使用場景: 網(wǎng)頁中代碼中的某個方法帘瞭,比如點擊事件方法淑掌,將該方法的參數(shù)傳值給OC,供OC使用蝶念。
  • 3抛腕、代碼實現(xiàn)如下:

oc給js傳值

一、 JS里需要實現(xiàn)的代碼(創(chuàng)建.js文件):
function setupWebViewJavascriptBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }

    //調(diào)用上面定義的函數(shù)
    setupWebViewJavascriptBridge(function (bridge){

        //OC傳值給JS 'testJavascriptHandler'為雙方自定義好的統(tǒng)一方法名媒殉;'data'是OC傳過來的值担敌;'responseCallback'是JS接收到之后給OC的回調(diào)
        bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
                //打印OC傳過來的值
                log('ObjC called testJavascriptHandler with', data)

                var responseData = { 'Javascript Says':'Right back atcha!' }

                log('JS responding with', responseData)

                //給OC的回調(diào)
                responseCallback(responseData)

            })
二、OC里需要實現(xiàn)的代碼:
  • 1廷蓉、導入第三方庫 WebViewJavascriptBridge全封;遵守UIWebViewDelegate協(xié)議;
 //設置第三方Bridge是否可用
    [WebViewJavascriptBridge enableLogging];

    //關聯(lián)webView和bridge
    _bridge = [WebViewJavascriptBridge bridgeForWebView:web];

    [_bridge setWebViewDelegate:self];

    //OC給JS傳值,雙方自定義一個統(tǒng)一的方法名'testJavascriptHandler'刹悴;data里即為要傳過去的值
    [_bridge callHandler:@"testJavascriptHandler" data:@{@"年齡":@"20"}];

js給oc傳值

一行楞、創(chuàng)建js文件,js代碼如下:

//點擊網(wǎng)頁上一個按鈕時
     callbackBt.onclick = function()
     {  
     var str1=document.getElementById("text1").value;
     var str2=document.getElementById("text2").value;

     //JS給OC傳值土匀。'passValue'為雙方自定義的統(tǒng)一方法名子房;'str1'&'str2'為要傳的值; response為OC收到后給JS的回調(diào)
     bridge.callHandler('passValue', {str1,str2}, function(response) {
                                })

     }

二就轧、oc要實現(xiàn)的代碼
  • 導入第三方庫 WebViewJavascriptBridge证杭;遵守UIWebViewDelegate協(xié)議;
//設置第三方Bridge是否可用
    [WebViewJavascriptBridge enableLogging];

    //關聯(lián)webView和bridge
    _bridge = [WebViewJavascriptBridge bridgeForWebView:web];

    [_bridge setWebViewDelegate:self];

    //js給oc傳值.'passValue'為雙方自定義的統(tǒng)一方法名妒御;'data'為JS傳過來的值解愤;'responseCallback'為OC收到值后給JS返回的回調(diào)
    [_bridge registerHandler:@"passValue" handler:^(id data, WVJBResponseCallback responseCallback) {

        //打印js傳過來的值
        NSLog(@"%@", data);

        //返回給js的值
        responseCallback(@"收到了");
    }];
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市携丁,隨后出現(xiàn)的幾起案子琢歇,更是在濱河造成了極大的恐慌,老刑警劉巖梦鉴,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件李茫,死亡現(xiàn)場離奇詭異,居然都是意外死亡肥橙,警方通過查閱死者的電腦和手機魄宏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來存筏,“玉大人宠互,你說我怎么就攤上這事⊥旨幔” “怎么了予跌?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長善茎。 經(jīng)常有香客問我券册,道長,這世上最難降的妖魔是什么垂涯? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任烁焙,我火速辦了婚禮,結(jié)果婚禮上耕赘,老公的妹妹穿的比我還像新娘骄蝇。我一直安慰自己,他們只是感情好操骡,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布九火。 她就那樣靜靜地躺著赚窃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吃既。 梳的紋絲不亂的頭發(fā)上考榨,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音鹦倚,去河邊找鬼河质。 笑死,一個胖子當著我的面吹牛震叙,可吹牛的內(nèi)容都是我干的掀鹅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼媒楼,長吁一口氣:“原來是場噩夢啊……” “哼乐尊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起划址,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤扔嵌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后夺颤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痢缎,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年世澜,在試婚紗的時候發(fā)現(xiàn)自己被綠了独旷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡寥裂,死狀恐怖嵌洼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情封恰,我是刑警寧澤麻养,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站诺舔,受9級特大地震影響鳖昌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜混萝,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萍恕。 院中可真熱鬧逸嘀,春花似錦、人聲如沸允粤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至司光,卻和暖如春琅坡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背残家。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工榆俺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坞淮。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓茴晋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親回窘。 傳聞我的和親對象是個殘疾皇子诺擅,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 有時我們有這樣的需求:需要從app的網(wǎng)頁中點擊調(diào)用軟件內(nèi)部的頁面,又或者是軟件內(nèi)部調(diào)用網(wǎng)頁的js方法啡直。 js代碼調(diào)...
    雞蛋掉了閱讀 585評論 2 8
  • 前言 在開發(fā)IOS應用的過程中烁涌,難免的會遇到和WebView打交道的場景智政,通常為了實現(xiàn)產(chǎn)品經(jīng)理的功能需求還要去和W...
    MadeLife閱讀 453評論 0 1
  • 一沃缘、JS給OC傳值 1. 技術方案:使用JavaScriptCore.framework框架 2. 使用場景: 網(wǎng)...
    love埖落葙緦盡閱讀 496評論 0 4
  • 目錄介紹1.WebView和Js交互方式2.Android調(diào)用JS腳本3.JS調(diào)用Android方法4.Andro...
    楊充211閱讀 1,053評論 0 3
  • Webview和JS交互方式 前言 現(xiàn)在很多App里都內(nèi)置了Web網(wǎng)頁(Hybrid App),比如說很多電商平臺...
    badcyc閱讀 273評論 1 2