iOS中UIWebView與WKWebView糯而、JavaScript與OC交互、Cookie管理看我就夠(下)

原文鏈接:

iOS中UIWebView與WKWebView泊窘、JavaScript與OC交互熄驼、Cookie管理看我就夠(上)
iOS中UIWebView與WKWebView像寒、JavaScript與OC交互、Cookie管理看我就夠(中)
iOS中UIWebView與WKWebView瓜贾、JavaScript與OC交互诺祸、Cookie管理看我就夠(下)

一、前言

在前面的文章中祭芦,我們介紹了UIWebView筷笨、WKWebView一些使用,與JS的交互和一些坑龟劲,相信看過的小伙伴們胃夏,已經(jīng)大概清楚了吧,如果有問題昌跌,歡迎提問仰禀。

本文是本系列文章的最后一篇,主要為小伙伴們分享下Safari調(diào)試蚕愤、與前端的配合以及實際應(yīng)用中一些需求的實現(xiàn)等

關(guān)于文中提到的一些內(nèi)容包竹,這里我準(zhǔn)備了個Demo,有需要的小伙伴可以下載碍庵。

二映企、Safari調(diào)試

在前面的文章中,查看網(wǎng)頁的Cookie静浴,其實已經(jīng)用到了Safari調(diào)試堰氓。筆者覺得Safari調(diào)試功能真的很有用,通過它可以輕松定位問題的所在苹享。也因此双絮,公司中App一旦有問題出現(xiàn),不管是客戶端的問題得问,還是前端的問題囤攀,找問題的重任都落到了筆者的身上呢。這一度是一個困擾??宫纬。想象一下焚挠,h5頁面的一個bug,App端幫忙快速定位漓骚,并且告知h5相關(guān)開發(fā)人員該如何修復(fù)蝌衔,是多么偉大的一件事情榛泛。

下面來簡單講講怎么用Safari調(diào)試。

1. 開啟Safari開發(fā)菜單

在Mac的Safari偏好設(shè)置中噩斟,開啟開發(fā)菜單曹锨。具體步驟為:Safari -> 偏好設(shè)置… -> 高級 -> 勾選在菜單欄顯示“開發(fā)”菜單

2. iPhone開啟Web檢查器

具體步驟為:設(shè)置 -> Safari -> 高級 -> Web 檢查器剃允。

3. 運行App

打開項目沛简,Cmd + R 運行,打開想調(diào)試的Web頁面斥废。


4. 調(diào)試對應(yīng)的頁面

打開Safari -> 開發(fā) -> 設(shè)備 -> URL椒楣。

選中的頁面會變成藍(lán)色,點擊然后打開了如下的界面:

這個頁面就很像Windows 平臺ChromeF12营袜∪龆伲可以打斷點:

查看斷點:

查看Cookie:

打印Cookie或者元素:

比如我在這里Alert頁面的title,輸入 alert(document.title);荚板,你會在模擬器中看到彈窗:

整體十分有用凤壁,操作的體驗跟Xcode很像,小伙伴們自行探索跪另。

三拧抖、與前端配合解決bug

前端有一些問題,在瀏覽器中是無法調(diào)試的免绿,很可能只在App內(nèi)的瀏覽器中才會復(fù)現(xiàn)唧席。這個時候你可以期待前端開發(fā)人員會使用XcodeSafari調(diào)試來解決bug,或者靠自己嘲驾。畢竟大家的目標(biāo)一致淌哟,給用戶提供一個更好的App,解決所有已知問題辽故。

這里我舉個例子徒仓,運用Safari調(diào)試來解決一個前端的bug。

比如新做的h5頁面中誊垢,有一個分享按鈕掉弛,點擊調(diào)用原生的分享,但是發(fā)現(xiàn)喂走,點擊之后沒有反應(yīng)了殃饿,什么問題呢?是Native端實現(xiàn)有問題芋肠,還是前端寫的有問題呢乎芳?如圖

我們來幫忙看下吧,打開Safari Web 檢查器,定位到資源奈惑,并且在share方法中添加斷點谬晕,如圖

會發(fā)現(xiàn),并沒有斷住阶冈,而是頁面直接報錯了错蝴,仔細(xì)查看錯誤描述,share方法里多了一個“/”,因此報錯了落竹。當(dāng)我點擊分享按鈕時

會發(fā)現(xiàn),提示找不到變量share漠另。這里我需要說明一下:

當(dāng)js中報錯的時候餐弱,報錯位置所在的函數(shù)以及報錯位置之后的代碼,都不會執(zhí)行姆坚,所以我點擊分享時澳泵,提示的是找不到方法,因為js的語法不對兼呵,報錯了兔辅,這里解析不出來,所以也就沒有了share击喂、testAddMethod和之后的函數(shù)维苔。

那么當(dāng)我點擊分享下面的按鈕是,調(diào)用share下面定義的方法也就會提示找不到對應(yīng)的函數(shù)了懂昂。



至此介时,問題找到了,只要告之前端開發(fā)人員即可凌彬,讓他修復(fù)即可沸柔。

實際遇到的問題可能要復(fù)雜的多,可以通過斷點铲敛,以及控制臺打印一些js變量的值褐澎,DOM操作來尋找問題,解決問題原探。希望可以幫助到小伙伴們乱凿。

四、實際應(yīng)用中一些需求的實現(xiàn)

1. 自定義瀏覽器UserAgent

這個其實在App開發(fā)中咽弦,比較重要徒蟆。比如常見的微信、支付寶App等型型,都有自己的UserAgent段审,而UA最常用來判斷在哪個App內(nèi),一般App的下載頁中只有一個按鈕”點擊下載”闹蒜,當(dāng)用戶點擊該按鈕時寺枉,在微信中則跳轉(zhuǎn)到應(yīng)用寶抑淫,否則跳轉(zhuǎn)到AppStore。那么如何區(qū)分在哪個App中呢姥闪?就是js判斷UA始苇。

//js中判斷
if (navigator.userAgent.indexOf("MicroMessenger") !== -1) {
   //在微信中
}

關(guān)于自定義UA,這個UIWebView不提供Api筐喳,而WKWebView提供Api催式,前文中也說明過,就是調(diào)用customUserAgent屬性避归。

self.webView.customUserAgent = @"WebViewDemo/1.0.0";    //自定義UA荣月,只支持WKWebView

而有沒有其他的方法實現(xiàn)自定義瀏覽器UserAgent呢?有梳毙。

//最好在AppDelegate中就提前設(shè)置
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    //設(shè)置自定義UserAgent
    [self setCustomUserAgent];
    return YES;
}

- (void)setCustomUserAgent
{
    //get the original user-agent of webview
    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
    NSString *oldAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
    //add my info to the new agent
    NSString *newAgent = [oldAgent stringByAppendingFormat:@" %@", @"WebViewDemo/1.0.0"];
    //regist the new agent
    NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:newAgent, @"UserAgent", newAgent, @"User-Agent", nil];
    [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
}

@end

上面的代碼哺窄,展示了在原有UserAgent的基礎(chǔ)上,添加一些自定義的內(nèi)容账锹。

可以看到原本的UA后面已經(jīng)有我們添加的內(nèi)容了WebViewDemo/1.0.0萌业。

這里需要說明的是:

  1. 通過NSUserDefaults設(shè)置自定義UserAgent,可以同時作用于UIWebViewWKWebView牌废。
  2. WKWebViewcustomUserAgent屬性咽白,優(yōu)先級高于NSUserDefaults,當(dāng)同時設(shè)置時鸟缕,顯示customUserAgent的值晶框。如上圖。

2. Native與H5共享登錄狀態(tài)

這個需求在前面的文章中針對WKWebViewUIWebView分別單獨做過介紹懂从。維持登錄狀態(tài)授段,依賴的是相同的Cookie

UIWebView實現(xiàn)起來基本不需要做額外的操作番甩,只要保證sharedHTTPCookieStorage中的Cookie是沒問題的侵贵。

WKWebView實現(xiàn)起來相對麻煩,有很多坑缘薛,這里不再詳細(xì)描述窍育,小伙伴們可以看下上篇文章中Cookie管理一節(jié)。

3. Native預(yù)覽H5頁面中的image

這個需求宴胧,應(yīng)該是一個比較常見的需求漱抓。在微信中瀏覽網(wǎng)頁時,看到喜歡的圖片恕齐,你會點擊圖片查看大圖乞娄,然后長按圖片保存。

1. 分析

如果你的項目中有這樣的需求的話,可能你需要做如下的分析仪或。

  1. 如果想在Native預(yù)覽H5中的image确镊,最需要的是什么?是圖片的鏈接范删。如果能有縮略圖更好了蕾域。
  2. 只要獲取了鏈接,就可以跳轉(zhuǎn)到一個ViewController中到旦,預(yù)覽圖片束铭,后續(xù)長按保存自然水到渠成。
  3. 那應(yīng)該如何獲取圖片的鏈接呢厢绝?通過JS -> OC 傳遞圖片url。

這里带猴,究竟如何實現(xiàn)獲取圖片鏈接昔汉,取決于你用的是UIWebView還是WKWebView

2. 方案

當(dāng)頁面加載完成后拴清,給html頁面中所有無默認(rèn)點擊事件的<img>添加點擊事件靶病,當(dāng)用戶點擊時,拿到所有參數(shù)口予。

(其實這不是最好的方案娄周,最好的解決方案是,跟前端約定一下沪停,哪些圖片需要預(yù)覽煤辨,哪些img標(biāo)簽的id統(tǒng)一,或者有個特定的屬性木张,這樣客戶端可以根據(jù)id找到這些img標(biāo)簽)

首先众辨,Html中有個img標(biāo)簽

<img src="http://cc.cocimg.com/api/uploads/170425/b2d6e7ea5b3172e6c39120b7bfd662fb.jpg">

我先寫好一個ImgAddClickEvent.js文件,來實現(xiàn)給所有無默認(rèn)點擊事件的<img>添加點擊事件舷礼。

//獲取所有img標(biāo)簽
var imgs = document.getElementsByTagName("img");
//獲取所有的imgUrl
var imgUrls = new Array();
var x = 0;
var y = 0;
var width = 0;
var height = 0;
for (var i = 0; i < imgs.length; i++) {
    var img = imgs[i];
    //如果圖片鏈接存在
    if (img.src || img.getAttribute('data-src')) {
        //添加到圖片鏈接數(shù)組中
        imgUrls.push(img.src || img.getAttribute('data-src'));
        //如果圖片沒有默認(rèn)的onclick事件鹃彻,且父元素不是a標(biāo)簽,則添加onclick事件妻献,當(dāng)用戶點擊時蛛株,把圖片鏈接回傳給Native
        if (!img.onclick && img.parentElement.tagName !== "A") {
            //給圖片添加下標(biāo)的屬性
            img.index = i; //記錄下標(biāo)
            //添加點擊事件,并且回傳選中的圖片鏈接育拨、下標(biāo)谨履、屏幕上的位置、全部的圖片數(shù)組等
            img.onclick = function() {
                x = this.getBoundingClientRect().left;
                y = this.getBoundingClientRect().top;
                x = x + document.documentElement.scrollLeft;
                y = y + document.documentElement.scrollTop;
                width = this.width;
                height = this.height;
                var imgInfo = {
                    imgUrl: this.src || this.getAttribute('data-src'),
                    x: x,
                    y: y,
                    width: width,
                    height: height,
                    index: this.index,
                    imgUrls: imgUrls
                };
                //UIWebView使用
                h5ImageDidClick(imgInfo);
            }
        }
    }
}

function h5ImageDidClick(info) {
    //WKWebView使用
    window.webkit.messageHandlers.imageDidClick.postMessage(info);
}

下面分別介紹UIWebViewWKWebView如何實現(xiàn)至朗。

3. UIWebView實現(xiàn)

UIWebView直接使用JavaScriptCore<img>添加onclick方法為OC的實現(xiàn)即可屉符。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [self convertJSFunctionsToOCMethods];
}

- (void)convertJSFunctionsToOCMethods {
    //獲取該UIWebview的javascript上下文
    //self持有jsContext
    //@property (nonatomic, strong) JSContext *jsContext;
    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

      //先注入給圖片添加點擊事件的js
    //防止頻繁IO操作,造成性能影響
    static NSString *jsSource;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        jsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ImgAddClickEvent" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
    });
    [self.jsContext evaluateScript:jsSource];
    //替換回調(diào)方法
    self.jsContext[@"h5ImageDidClick"] = ^(NSDictionary *imgInfo) {
        NSLog(@"UIWebView點擊了html上的圖片,信息是:%@", imgInfo);
    };
}
4. WKWebView實現(xiàn)

WKWebView實現(xiàn)矗钟,需要使用WKUserScriptscriptMessageHandler唆香,下面簡單介紹下,詳細(xì)實現(xiàn)吨艇,見Demo躬它。

WKWebViewUIViewController中實現(xiàn)如下

/**
 頁面中的所有img標(biāo)簽添加點擊事件
 */
- (void)imgAddClickEvent {
    //防止頻繁IO操作,造成性能影響
    static NSString *jsSource;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        jsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ImgAddClickEvent" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
    });
    //添加自定義的腳本
    WKUserScript *js = [[WKUserScript alloc] initWithSource:jsSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
    [self.webView.configuration.userContentController addUserScript:js];
    //注冊回調(diào)
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"imageDidClick"];
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"imageDidClick"]) {
        //點擊了html上的圖片
        NSLog(@"點擊了html上的圖片东涡,參數(shù)為%@", message.body);
    }
}

當(dāng)我點擊這個標(biāo)簽時冯吓,因為我添加了onclick事件,在OC端我會接收到回調(diào)疮跑。因此打印出log

5. 注意

上面無論是UIWebView還是WKWebView组贺,參數(shù)中的x,y是不包含自定義scrollView的contentInset的祖娘,如果要獲取圖片在手機屏幕上的位置:

x = x + self.webView.scrollView.contentInset.left;
y = y + self.webView.scrollView.contentInset.top;

拿到了這些信息失尖,想必,你可以實現(xiàn)一個十分完美的圖片預(yù)覽效果了渐苏。

4. Native加載并緩存H5頁面中的img

因為頁面中的img標(biāo)簽加載圖片的網(wǎng)絡(luò)請求是由WebView管理的掀潮,所以要想Native接管圖片的下載,只有2條路:

  1. 在頁面加載前琼富,把頁面中img標(biāo)簽的src換成一張native的占位圖或者””仪吧,并且把img.src傳遞到native,在native下載圖片或者讀取緩存完畢后鞠眉,再把相應(yīng)的img標(biāo)簽的src設(shè)置成本地的薯鼠,如img.src =”native cache url”。整體交互是JS->Native, Native -> JS械蹋。
  2. NSURLProtocol攔截WebView的所有圖片請求人断,交由我們自己管理。

比較有可行性的是方法2朝蜘。但也只限于UIWebView恶迈。WKWebView上篇文中說過,雖然有私有Api谱醇,但是筆者不推薦使用暇仲。

先說下,為何方法1不可行副渴。首先奈附,頁面加載前,是在什么時候呢煮剧?如果h5不做修改斥滤,全部交由Native端處理将鸵,是沒有辦法修改html的,因為UIWebViewWKWebView都沒有提供一個Api佑颇,在圖片加載之前告訴你html是什么內(nèi)容顶掉,所以這個方法是走不通的。除非你用loadHTMLString的方法加載挑胸,加載前先替換img的src痒筒。但是loadHTMLString的方法,又加載不到Web端的js和css茬贵,只能用于本地拼接完整HTML String的情況簿透,不適用于一般的場景。So解藻,這條路是走不通的老充,局限性太大了。

方法2的核心思路就是攔截請求螟左,最核心的是在你的NSURLProtocol子類中蚂维,實現(xiàn)這個方法

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    //處理過不再處理
    if ([NSURLProtocol propertyForKey:DAURLProtocolHandledKey inRequest:request]) {
        return NO;
    }
    //根據(jù)request header中的 accept 來判斷是否加載圖片
    /*
    {
     "Accept" = "image/png,image/svg+xml,image/*;q=0.8,*\/*;q=0.5\";
     "User-Agent" = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E269 WebViewDemo/1.0.0";
    }
     */
    NSDictionary *headers = request.allHTTPHeaderFields;
    NSString *accept = headers[@"Accept"];
    if (accept.length >= @"image".length && [accept rangeOfString:@"image"].location != NSNotFound) {
        return YES;
    }
    return NO;
}

當(dāng)攔截到圖片請求時,再做后續(xù)的處理路狮,下面寫一些偽代碼

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
    //這里也可以添加一些自定義的header,看具體需求
    //標(biāo)記該request已經(jīng)處理過
    [NSURLProtocol setProperty:@(YES) forKey:DAURLProtocolHandledKey inRequest:mutableReqeust];

    //這里NSURLProtocolClient的相關(guān)方法都要調(diào)用
    //比如 [self.client URLProtocol:self didLoadData:data];
    .....
}
- (void)stopLoading {
    .....
}

這部分代碼蔚约,Demo中并沒有完全實現(xiàn)奄妨,如果小伙伴們有興趣研究下具體的實現(xiàn),可以參考這篇文章苹祟, 筆者這里就不多說了砸抛。

5. Native分享H5頁面到微信、QQ等

這個需求树枫,其實我在前面的文章中針對UIWebViewWKWebView都已經(jīng)做了很詳細(xì)的介紹直焙。這里,簡單分享下如何獲取分享的內(nèi)容砂轻。

一般分享到微信或者QQ至少需要的參數(shù)是

  1. Title(主標(biāo)題)
  2. Description(副標(biāo)題或者描述)
  3. ThumbnailImage(縮略圖)
  4. WebpageUrl(h5頁面的鏈接)

這些參數(shù)奔誓,都怎么獲取呢?通過OC->JS的方式搔涝,獲取厨喂。當(dāng)然你也可以自定義。

var title = document.title;
var desc = document.getElementsByTagName("article")[0].textContent;     //或者 document.body.innerText; 或者  document.getElementById("yourId").innerText; 
var thumbnailImageUrl = document.getElementsByTagName("img")[0].src;    //或者看需求取哪個
var webpageUrl = location.href;

具體如何用OC調(diào)用JS獲取這些值庄呈,這里就不多說了蜕煌,看過前面文章的小伙伴,可以自行實現(xiàn)诬留。

6. Native為H5提供一套Native Api(微信斜纪、支付寶小程序)

很多時候贫母,Native與H5交互得深了,必定會有一些更深層次的需求盒刚。比如h5想控制頁面的pop腺劣、push、present伪冰,想調(diào)用Native的Share誓酒,想調(diào)用Native的掃描二維碼功能,獲取掃描結(jié)果……

那么近半年比較??的小程序贮聂,微信提供的一些Api(掃碼靠柑、選擇照片等)都是如何實現(xiàn)的呢?很明顯吓懈,native提供的歼冰。

筆者作為支付寶小程序(尚未發(fā)布)的內(nèi)測用戶之一,也接觸了支付寶小程序耻警,其中也有很多Api是native提供的隔嫡。

其實這就涉及到一個完整的Native與JS交互的流程,從JS->Native到Native->JS甘穿。也就是前面介紹過的腮恩,異步回調(diào)結(jié)果。這個不局限于iOS温兼,Android也是同樣的秸滴。

首先,我們?yōu)镠5提供一套Api募判,那自然Api是暴露給js的荡含,所以這些Api也是js的。筆者封裝了一個接口文件:NativeApi.js(在最新的Demo中有)届垫。下面針對一些需求释液,分析下封裝和實現(xiàn)。其中用到了js閉包装处,需要一點js知識误债。

1. 分享

前面的文章中,筆者最常舉的一個例子就是分享妄迁,Native為H5提供原生的分享方法找前,h5調(diào)用后可以獲取分享結(jié)果(成功or失敗)判族。這里針對分享這個如何實現(xiàn)躺盛,就不贅述了。筆者直接貼上適用于WKWebViewjs代碼形帮。

/**
 * Native為H5提供的Api接口
 *
 * @type {js對象}
 */
var DANativeApi = (function() {

    var NativeApi = {
        /**
         * 分享
         * @param  {js對象} shareInfo 分享信息和回調(diào)
         * @return {void}           無同步返回值槽惫,異步返回分享結(jié)果 true or false
         */
        share: function(shareInfo) {
            if (shareInfo == undefined || shareInfo == null || typeof(shareInfo) !== "object") {
                alert("參數(shù)" + JSON.stringify(shareInfo) + "不合法");
            } else {
                alert("分享的參數(shù)為" + JSON.stringify(shareInfo));
            }
            //調(diào)用native端
            _nativeShare(shareInfo);
        }
    }

    //下面是一些私有函數(shù)
    /**
     * Native端實現(xiàn)周叮,適用于WKWebView,UIWebView如何實現(xiàn)界斜,小伙伴自己動腦筋吧~
     * @param  {js對象} shareInfo 分享的信息和回調(diào)
     * @return {void}           無同步返回值仿耽,異步返回
     */
    function _nativeShare(shareInfo) {
        //用于WKWebView,因為WKWebView并沒有辦法把js function傳遞過去各薇,因此需要特殊處理一下
        //把js function轉(zhuǎn)換為字符串项贺,oc端調(diào)用時 (<js function string>)(true); 即可
        //如果有回調(diào)函數(shù),且為function
        var callbackFunction = shareInfo.result;
        if (callbackFunction != undefined && callbackFunction != null && typeof(callbackFunction) === "function") {
            shareInfo.result = callbackFunction.toString();
        }
        //js -> oc 
        // 至于Android端峭判,也可以开缎,比如 window.jsInterface.nativeShare(JSON.stringify(shareInfo));
        window.webkit.messageHandlers.nativeShare.postMessage(shareInfo);
    }

    //閉包,把Api對象返回
    return NativeApi;
})();

/*

//調(diào)用時林螃,分享
DANativeApi.share({
    title: document.title,
    desc: "",
    url: location.href,
    imgUrl: "",
    result: function(res) {
        // body...
        alert("分享結(jié)果為:" + JSON.stringify(res));
    }
});

 */

Native端不貼了奕删,小伙伴們看Demo吧。

2. 從通訊錄選擇聯(lián)系人

這里筆者再舉個從通訊錄選擇聯(lián)系人的例子疗认,從js到native完残,再從native到j(luò)s。

首先js端横漏,添加如下實現(xiàn)

/**
 * Native為H5提供的Api接口
 *
 * @type {js對象}
 */
var DANativeApi = (function() {

    var NativeApi = {
        /**
         * 從通訊錄選擇聯(lián)系人
         * @return {void} 無同步返回值谨设,異步返回選擇的結(jié)果
         */
        choosePhoneContact: function(param) {
            //具體是否需要判斷
            //調(diào)用native端
            _nativeChoosePhoneContact(param);
        }
    }

    //下面是一些私有函數(shù)
    /**
     * Native端實現(xiàn)選擇聯(lián)系人,并異步返回結(jié)果
     * @param  {[type]} param [description]
     * @return {[type]}       [description]
     */
    function _nativeChoosePhoneContact(param) {
        var callbackFunction = param.completion;
        if (callbackFunction != undefined && callbackFunction != null && typeof(callbackFunction) === "function") {
            param.completion = callbackFunction.toString();
        }
        //js -> oc 
        window.webkit.messageHandlers.nativeChoosePhoneContact.postMessage(param);
    }

    //閉包缎浇,把Api對象返回
    return NativeApi;
})();

/*
//選擇聯(lián)系人
DANativeApi.choosePhoneContact({
    completion: function(res) {
        alert("選擇聯(lián)系人的結(jié)果為:" + JSON.stringify(res));
    }
});
 */

OC端依然加載此文件扎拣,并注冊handler

/**
 添加native端的api
 */
- (void)addNativeApiToJS
{
    //防止頻繁IO操作,造成性能影響
    static NSString *nativejsSource;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        nativejsSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"NativeApi" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil];
    });
    //添加自定義的腳本
    WKUserScript *js = [[WKUserScript alloc] initWithSource:nativejsSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    [self.webView.configuration.userContentController addUserScript:js];
    //注冊回調(diào)
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"nativeChoosePhoneContact"];
}

#pragma mark - WKScriptMessageHandler  js -> oc

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
   //選擇聯(lián)系人
   if ([message.name isEqualToString:@"nativeChoosePhoneContact"]) {
        NSLog(@"正在選擇聯(lián)系人");

        [self selectContactCompletion:^(NSString *name, NSString *phone) {
            NSLog(@"選擇完成");
            //讀取js function的字符串
            NSString *jsFunctionString = message.body[@"completion"];
            //拼接調(diào)用該方法的js字符串
            NSString *callbackJs = [NSString stringWithFormat:@"(%@)({name: '%@', mobile: '%@'});", jsFunctionString, name, phone];
            //執(zhí)行回調(diào)
            [self.webView evaluateJavaScript:callbackJs completionHandler:^(id _Nullable result, NSError * _Nullable error) {

            }];
        }];
    }
}

具體回調(diào)方式华畏,在之前的WKWebView中,講過了尊蚁,這里不再贅述亡笑,選擇聯(lián)系人用的是Contacts框架,具體的小伙伴可以看Demo横朋。

整體效果如下:

3. 掃描二維碼

相信看過從通訊錄選擇聯(lián)系人的實現(xiàn)仑乌,小伙伴們可以自行實現(xiàn)掃描二維碼了吧~ 快動手嘗試一下吧~

五、總結(jié)

本文給小伙伴們介紹了下Safari調(diào)試琴锭,以及其具體運用晰甚,并且分享了實際應(yīng)用中一些需求的實現(xiàn)方式。

結(jié)合前面的兩篇文章决帖, 相信現(xiàn)在小伙伴們一定對WebView有相當(dāng)深刻的理解了吧厕九。那么,本系列文章也告一段落了地回,具體有問題的話扁远,歡迎提問俊鱼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市畅买,隨后出現(xiàn)的幾起案子并闲,更是在濱河造成了極大的恐慌,老刑警劉巖谷羞,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帝火,死亡現(xiàn)場離奇詭異,居然都是意外死亡湃缎,警方通過查閱死者的電腦和手機犀填,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雁歌,“玉大人宏浩,你說我怎么就攤上這事】肯梗” “怎么了比庄?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乏盐。 經(jīng)常有香客問我佳窑,道長,這世上最難降的妖魔是什么父能? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任神凑,我火速辦了婚禮,結(jié)果婚禮上何吝,老公的妹妹穿的比我還像新娘溉委。我一直安慰自己,他們只是感情好爱榕,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布瓣喊。 她就那樣靜靜地躺著,像睡著了一般黔酥。 火紅的嫁衣襯著肌膚如雪藻三。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天跪者,我揣著相機與錄音棵帽,去河邊找鬼。 笑死渣玲,一個胖子當(dāng)著我的面吹牛逗概,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忘衍,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仗谆,長吁一口氣:“原來是場噩夢啊……” “哼指巡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起隶垮,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤藻雪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狸吞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勉耀,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年蹋偏,在試婚紗的時候發(fā)現(xiàn)自己被綠了便斥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡威始,死狀恐怖枢纠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情黎棠,我是刑警寧澤晋渺,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站脓斩,受9級特大地震影響木西,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜随静,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一八千、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧燎猛,春花似錦恋捆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至论寨,卻和暖如春星立,著一層夾襖步出監(jiān)牢的瞬間爽茴,已是汗流浹背葬凳。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留室奏,地道東北人火焰。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像胧沫,于是被迫代替她去往敵國和親昌简。 傳聞我的和親對象是個殘疾皇子占业,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

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