UIWebView/WKWebView對標籤攔截
在iOS開發中,經常會用到UIWebView/WKWebView來載入Html5。特別是隨著Hybrid開發的流行,有的公司直接砍掉大部分的Native開發,轉而大量採用H5頁面替代Native頁面。這就要多研究研究UIWebView/WKWebView了。本文主要針對Hybrid開發中遇到的一個小問題,提供一個解決方案。
當H5中含有<input type=file>標籤時,點選選擇檔案按鈕會預設彈出Native的檔案選擇選單,包含相機拍照、從相簿選擇兩個選項。這是由於系統對<input type=file>對標籤進行了監聽,並做了處理。
現在專案中不滿足於這兩個選項,如果想自己加一個,或者做任何自己想要的定製,就需要捕獲這個<input type=file>標籤,並在事件裡面實現自己想要實現的功能。那麼如何捕獲這個標籤呢?用UIWebView/WKWebView的代理是不行的,沒有哪個代理方法會回撥這個標籤的監聽事件。下面提供一種解決方案。
主要思路是,雖然攔截不了js發給Native的通知,但是可以通過Runtime攔截Native彈出視窗,因為知道這個視窗是被present出來的。通過斷點,可以看到,對於UIWebView來說,present的的是UIDocumentMenuViewController,並通過其代理UIWebFileUploadPanel完成檔案的上傳。WKWebView也是類似的。
因此可以通過Runtime來hook出UIViewController的presentViewController方法,拿到將要被present的UIViewController,並判斷其型別,如果是UIDocumentMenuViewController型別且其代理為UIWebFileUploadPanel(或者WKFileUploadPanel),將present方法return掉,不讓他彈出來;如果不是這種型別的,才讓present。如下所示:
- (void)gigi_presentViewController:(UIViewController*)viewControllerToPresent animated:(BOOL)flag completion:(void(^)(void))completion {
//如果present的viewcontroller是UIDocumentMenuViewController型別,且代理是WKFileUploadPanel或UIWebFileUploadPanel進行攔截
if([viewControllerToPresent isKindOfClass:[UIDocumentMenuViewController class]]) {
UIDocumentMenuViewController*dvc = (UIDocumentMenuViewController*)viewControllerToPresent;
if([dvc.delegateisKindOfClass:NSClassFromString(@"WKFileUploadPanel")] || [dvc.delegateisKindOfClass:NSClassFromString(@"UIWebFileUploadPanel")]) {
self.isFileInputIntercept=YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self onFileInputIntercept];
});
return;
}
}
//正常情況下的present
[selfgigi_presentViewController:viewControllerToPresentanimated:flagcompletion:completion];
}
並在return之前執行想要自己實現的程式碼,做自己想幹的事。在這裡執行了一個[self onFileInputIntercept]方法,把攔截傳遞出去。這樣就大功告成了嗎?不是的。嘗試一下,發現,第一次點選時,阻止預設視窗彈出來是可以的,但是,第二次時,就不會呼叫present方法了,因此就無法進行攔截。
究其原因,發現預設視窗彈出後,在視窗消失時,呼叫了dismisViewControllerAnimated這個回撥,並執行了它的bolck completion。如果執行了這個block,第二次就能夠正常攔截;如果不執行block,第二次就無法攔截。這個completion到底是怎麼實現的,不得而知,因為是系統內部實現的,看不到原始碼,但是也不需要知道。只需要知道它是一定要執行的就行。那麼怎麼來執行這個block呢。沒錯,可以通過UIDocumentMenuViewController來模擬取消,加上這關鍵的一句:
[dvc.delegate documentMenuWasCancelled:dvc];
來模擬視窗被取消,從而執行那個至關重要的completion block。那麼在dismisViewControllerAnimated也要做一些處理,如下所示:
- (void)gigi_dismissViewControllerAnimated:(BOOL)flag completion:(void(^)(void))completion {
//如果進行了攔截,禁止當前viewcontroller的dismiss
if(self.isFileInputIntercept) {
self.isFileInputIntercept=NO;
completion();
return;
}
//正常情況下viewcontroller的dismiss
[selfgigi_dismissViewControllerAnimated:flagcompletion:^{
if(completion) {
completion();
}
}];
}
至此才大功告成,對<input type=file>進行了有效的攔截。
最後,附上本文的Demo程式碼地址:https://github.com/frog78/Gigi
參考連結:
http://news.91.com/mip/s594a8f1b155c.html
相關文章
- UIWebview 與WKWebviewUIWebView
- 從 UIWebView 到 WKWebViewUIWebView
- iOS UIScrollVIew UITableView UIwebView WKWebView 截全圖,生成全圖方法iOSUIWebView
- WkWebView攔截替換本地音訊,圖片WebView音訊
- iOS UIWebView、WKWebView注入CookieiOSUIWebViewCookie
- iOS 中UIWebView與WKWebViewiOSUIWebView
- 使用WKWebView替換UIWebViewWebViewUI
- iOS與JS互動之UIWebView協議攔截iOSJSUIWebView協議
- iOS下JS與OC互相呼叫(一)--UIWebView 攔截URLiOSJSUIWebView
- Hybrid治理(UIWebView&WKWebView)UIWebView
- wkwebview和UIWebView除錯技巧WebViewUI除錯
- iOS下JS與OC互相呼叫(二)--WKWebView 攔截URLiOSJSWebView
- ios uiwebview wkwebview注意點小記iOSUIWebView
- 【iOS開發】從UIWebView到WKWebViewiOSUIWebView
- DDGScreenShot--iOS 各種截圖,webView wkWebView 生成長圖,加logo,打標籤iOSWebViewGo
- UIWebView攔截圖片請求,SDWebImage下載快取到本地,然後從本地讀取到UIWebView中UIWebView快取
- 比UIWebView更強大好用的WKWebViewUIWebView
- 不攔截Request!基於WKWebView的API實現Hybrid容器WebViewAPI
- 攔截器,攔截器棧總結
- TCP標誌位詳解及tcp攔截配置TCP
- SpringMVC攔截器,設定不攔截的URLSpringMVC
- MyBatis攔截器MyBatis
- Mybatis 攔截器MyBatis
- 導彈攔截
- sql攔截器SQL
- 前端架構之vue+axios 前端實現登入攔截(路由攔截、http攔截)前端架構VueiOS路由HTTP
- vue中用axios攔截器攔截請求和響應VueiOS
- Spring MVC 中的攔截器的使用“攔截器基本配置” 和 “攔截器高階配置”SpringMVC
- win10 microsoft edge網址被攔截如何取消攔截Win10ROS
- iOS 和 H5 互動那些事 (UIWebView、WKWebView 總結篇)iOSH5UIWebView
- axios攔截器iOS
- Mybatis Interceptor 攔截器MyBatis
- Xposed攔截抽象方法抽象
- WKCrashSDK - crash攔截工具
- axios 攔截器iOS
- spring攔截器Spring
- Java interceptor 攔截器Java
- IOS 手勢攔截iOS