iOS中UIWebView與WKWebView、JavaScript與OC互動、Cookie管理看我就夠(下)
前言
在前面的文章中,我們介紹了UIWebView
、WKWebView
一些使用,與JS的互動和一些坑,相信看過的小夥伴們,已經大概清楚了吧,如果有問題,歡迎提問。
本文是本系列文章的最後一篇,主要為小夥伴們分享下Safari除錯、與前端的配合以及實際應用中一些需求的實現等:
關於文中提到的一些內容,這裡我準備了個Demo,有需要的小夥伴可以下載。
本文目錄
- 前言
- Safari除錯
- 開啟Safari開發選單
- iPhone開啟Web檢查器
- 執行App
- 除錯對應的頁面
- 與前端配合解決bug
- 實際應用中一些需求的實現
- 自定義瀏覽器UserAgent
- Native與H5共享登入狀態
- Native預覽H5頁面中的image
- 分析
- 方案
- UIWebView實現
- WKWebView實現
- 注意
- Native載入並快取H5頁面中的img
- Native分享H5頁面到微信、QQ等
- Native為H5提供一套Native Api(微信、支付寶小程式)
- 分享
- 從通訊錄選擇聯絡人
- 掃描二維碼
- 總結
Safari除錯
在前面的文章中,檢視網頁的Cookie,其實已經用到了Safari除錯。筆者覺得Safari除錯功能真的很有用,通過它可以輕鬆定位問題的所在。也因此,公司中App一旦有問題出現,不管是客戶端的問題,還是前端的問題,找問題的重任都落到了筆者的身上呢。這一度是一個困擾。想象一下,h5頁面的一個bug,App端幫忙快速定位,並且告知h5相關開發人員該如何修復,是多麼偉大的一件事情。
下面來簡單講講怎麼用Safari除錯。
開啟Safari開發選單
在Mac的Safari偏好設定中,開啟開發選單。具體步驟為:Safari -> 偏好設定… -> 高階 -> 勾選在選單欄顯示“開發”選單。
iPhone開啟Web檢查器
具體步驟為:設定 -> Safari -> 高階 -> Web 檢查器。
執行App
開啟專案,Cmd + R 執行,開啟想除錯的Web頁面。
除錯對應的頁面
開啟Safari -> 開發 -> 裝置 -> URL。
選中的頁面會變成藍色,點選然後打開了如下的介面。
這個頁面就很像Windows
平臺Chrome
的F12
。可以打斷點:
檢視斷點
檢視Cookie
列印Cookie或者元素
比如我在這裡Alert頁面的title,輸入 alert(document.title);
,你會在模擬器中看到彈窗
整體十分有用,操作的體驗跟Xcode
很像,小夥伴們自行探索。
與前端配合解決bug
前端有一些問題,在瀏覽器中是無法除錯的,很可能只在App內的瀏覽器中才會復現。這個時候你可以期待前端開發人員會使用Xcode
和Safari
除錯來解決bug,或者靠自己。畢竟大家的目標一致,給使用者提供一個更好的App,解決所有已知問題。
這裡我舉個例子,運用Safari除錯來解決一個前端的bug。
比如新做的h5頁面中,有一個分享按鈕,點選呼叫原生的分享,但是發現,點選之後沒有反應了,什麼問題呢?是Native端實現有問題,還是前端寫的有問題呢?如圖
我們來幫忙看下吧,開啟Safari Web 檢查器,定位到資源,並且在share方法中新增斷點,如圖
會發現,並沒有斷住,而是頁面直接報錯了,仔細檢視錯誤描述,share方法裡多了一個“/”
,因此報錯了。當我點選分享按鈕時
會發現,提示找不到變數share
。這裡我需要說明一下:
當js中報錯的時候,報錯位置所在的函式以及報錯位置之後的程式碼,都不會執行,所以我點選分享時,提示的是找不到方法,因為js的語法不對,報錯了,這裡解析不出來,所以也就沒有了
share
、testAddMethod
和之後的函式。那麼當我點選分享下面的按鈕是,呼叫share下面定義的方法也就會提示找不到對應的函數了。
至此,問題找到了,只要告之前端開發人員即可,讓他修復即可。
實際遇到的問題可能要複雜的多,可以通過斷點,以及控制檯列印一些js變數的值,DOM操作來尋找問題,解決問題。希望可以幫助到小夥伴們。
實際應用中一些需求的實現
自定義瀏覽器UserAgent
這個其實在App開發中,比較重要。比如常見的微信、支付寶App等,都有自己的UserAgent
,而UA最常用來判斷在哪個App內,一般App的下載頁中只有一個按鈕"點選下載",當用戶點選該按鈕時,在微信中則跳轉到應用寶,否則跳轉到AppStore。那麼如何區分在哪個App中呢?就是js判斷UA。
//js中判斷
if (navigator.userAgent.indexOf("MicroMessenger") !== -1) {
//在微信中
}
關於自定義UA,這個UIWebView
不提供Api,而WKWebView
提供Api,前文中也說明過,就是呼叫customUserAgent
屬性。
self.webView.customUserAgent = @"WebViewDemo/1.0.0"; //自定義UA,只支援WKWebView
而有沒有其他的方法實現自定義瀏覽器UserAgent呢?有。
//最好在AppDelegate中就提前設定
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//設定自定義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
的基礎上,新增一些自定義的內容。
可以看到原本的UA後面已經有我們新增的內容了WebViewDemo/1.0.0
。
這裡需要說明的是:
- 通過
NSUserDefaults
設定自定義UserAgent,可以同時作用於UIWebView
和WKWebView
。WKWebView
的customUserAgent
屬性,優先順序高於NSUserDefaults
,當同時設定時,顯示customUserAgent
的值。如上圖。
Native與H5共享登入狀態
這個需求在前面的文章中針對WKWebView
和UIWebView
分別單獨做過介紹。維持登入狀態,依賴的是相同的Cookie
。
UIWebView
實現起來基本不需要做額外的操作,只要保證sharedHTTPCookieStorage
中的Cookie
是沒問題的。
WKWebView
實現起來相對麻煩,有很多坑,這裡不再詳細描述,小夥伴們可以看下上篇文章中Cookie管理一節。
Native預覽H5頁面中的image
這個需求,應該是一個比較常見的需求。在微信中瀏覽網頁時,看到喜歡的圖片,你會點選圖片檢視大圖,然後長按圖片儲存。
分析
如果你的專案中有這樣的需求的話,可能你需要做如下的分析。
- 如果想在Native預覽H5中的image,最需要的是什麼?是圖片的連結。如果能有縮圖更好了。
- 只要獲取了連結,就可以跳轉到一個
ViewController
中,預覽圖片,後續長按儲存自然水到渠成。- 那應該如何獲取圖片的連結呢?通過JS -> OC 傳遞圖片url。
這裡,究竟如何實現獲取圖片連結,取決於你用的是UIWebView
還是WKWebView
。
方案
當頁面載入完成後,給html頁面中所有無預設點選事件的
<img>
新增點選事件,當用戶點選時,拿到所有引數。(其實這不是最好的方案,最好的解決方案是,跟前端約定一下,哪些圖片需要預覽,哪些img標籤的id統一,或者有個特定的屬性,這樣客戶端可以根據id找到這些img標籤)
首先,Html中有個img標籤
![](xxx.jpg)
我先寫好一個ImgAddClickEvent.js
檔案,來實現給所有無預設點選事件的<img>
新增點選事件。
//獲取所有img標籤
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')) {
//新增到圖片連結陣列中
imgUrls.push(img.src || img.getAttribute('data-src'));
//如果圖片沒有預設的onclick事件,且父元素不是a標籤,則新增onclick事件,當用戶點選時,把圖片連結回傳給Native
if (!img.onclick && img.parentElement.tagName !== "A") {
//給圖片新增下標的屬性
img.index = i; //記錄下標
//新增點選事件,並且回傳選中的圖片連結、下標、螢幕上的位置、全部的圖片陣列等
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);
}
下面分別介紹UIWebView
和WKWebView
如何實現。
UIWebView實現
UIWebView
直接使用JavaScriptCore
給<img>
新增onclick
方法為OC的實現即可。
- (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];
//替換回調方法
self.jsContext[@"h5ImageDidClick"] = ^(NSDictionary *imgInfo) {
NSLog(@"UIWebView點選了html上的圖片,資訊是:%@", imgInfo);
};
}
WKWebView實現
而WKWebView
實現,需要使用WKUserScript
和scriptMessageHandler
,下面簡單介紹下,詳細實現,見Demo。
WKWebView
的UIViewController
中實現如下
/**
頁面中的所有img標籤新增點選事件
*/
- (void