WKWebView加載問題
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request; - (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0)); - (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL; - (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));
baseURL需要注意
- 其中2個方式是ios9以后提供的
- 方法參數baseURL,此參數是html加載的資源是基於的基礎路徑,也可以理解為資源加載引入的相對路徑,一般為[[NSBundle mainBundle] bundleURL], 如果設置的是bundleURL那么html中使用的資源引用相對路徑,相對路徑相對於bundle路徑 比如:<img src="base.png">,base.png就會在bundle資源中查找;
- 如果baseURL設置的為bundleURL,也可以寫絕對路徑,絕對路徑為bundle資源的絕對路徑. 比如html中引入了一些Js. css,png文件,如:
<script type="text/javascript" src="/Users/HJiang/Library/Developer/CoreSimulator/Devices/BFE72029-56CE-4768-8312-05CA50250212/data/Containers/Bundle/Application/02F79F9E-AE1C-4BCA-9F2F-F9B253113E2C/xxxx.app/jquery.js">
baseURL設置為bundleURL后,引入資源方式
- 相對路徑
<img src="tab.png">
- 絕對路徑
<img src="/Users/HJiang/Library/Developer/CoreSimulator/Devices/BFE72029-56CE-4768-8312-05CA50250212/data/Containers/Bundle/Application/02F79F9E-AE1C-4BCA-9F2F-F9B253113E2C/xxxx.app/tab.png">
WebKit訪問沙盒資源問題
baseURL設置為bundleURL
如果資源訪問的是沙盒中的資源,如:
模擬器目錄
<body isAutoLoadImage ='1' background = '/Users/HJiang/Library/Developer/CoreSimulator/Devices/BFE72029-56CE-4768-8312-05CA50250212/data/Containers/Data/Application/6CD99493-3C89-40F0-A7C4-353DBA7893F3/Documents/waterfile/6005001463_2025.jpg'>
真機路徑
<body isAutoLoadImage ='1' background = '/var/xxxx/Library//Devices/BFE72029-56CE-4768-8312-05CA50250212/data/Containers/Data/Application/6CD99493-3C89-40F0-A7C4-353DBA7893F3/Documents/waterfile/6005001463_2025.jpg'>
使用的是沙盒中絕對路徑,經測試此方式在模擬器上資源可以正常訪問,真機無法訪問資源
因webkit框架訪問沙盒資源存在bug,無法加載通過絕對路徑訪問到資源.
本人是通過以下方式解決的
webkit可以通過路徑為服務器方式就可以加載
GitHub上有個神器:GCDWebServer,這次就用的這個
通過pod集成
pod "GCDWebServer", "~> 3.0"
,直接上代碼
// 官方給的示例是在AppDelegate里啟動本地服務器,但是我這個並沒有必要在APP啟動時就啟動本地服務器,所以我放在了核心功能控制器的viewDidLoad方法內 // 1.導入頭文件 #import <GCDWebServer/GCDWebDAVServer.h> // 2.定義全局屬性 @property (nonatomic,strong) GCDWebServer *webSever; // 3. 主要代碼 _webSever = [[GCDWebServer alloc] init]; [_webSever addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:3600 allowRangeRequests:YES]; [_webSever startWithPort:8007 bonjourName:nil]; // 說明:上面代碼就會在沙盒的根目錄中建立服務,端口為8007;通過startWithPort就已經創建了服務 // 好了,這就結束了!WTF,這就完了,是的,可以這么說 // 比方說文件存在Library下有一個123的文件 NSString *basePath = @"http://localhost:8007/Library/water"; // 這樣就可以訪問到這個文件了,我只需要把我的文件名拼上localhost路徑然后傳給前端,他們拿到這個鏈接直接訪問就可以拿到這個文件了
.這樣就可以訪問沙盒中的任何資源,填寫好路徑就OK 比如訪問Library目錄下water文件夾下的123.jpg,那么路徑可以為<img src="http://localhost:8007/Library/water/123.jpg" .如果想把服務的根路徑修改為沙盒的Documents目錄可以修改directoryPath:參數路徑 [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
這樣就模擬器和真機都可以訪問沙盒中的資源.
在不用的時候需要停止服務
[[ZTELocalResourceServer sharedLocalResourceServer] stop];
抽取了一個管理類
/** 本地資源服務 */ @interface LocalResourceServer : ZTEManagerBase + (instancetype)sharedLocalResourceServer; - (void)start; - (void)stop; @end
#import "LocalResourceServer.h" #import <GCDWebServer/GCDWebServer.h> #import "LocalResourceDefine.h" @interface LocalResourceServer () @property (nonatomic,strong) GCDWebServer *webSever; @end @implementation LocalResourceServer + (instancetype)sharedLocalResourceServer{ static LocalResourceServer *localResourceServer = nil; static dispatch_once_t predicatemail; dispatch_once(&predicatemail, ^{ localResourceServer = [[LocalResourceServer alloc] init]; }); return localResourceServer; } - (void)start{ // 3. 啟動服務 self.webSever = [[GCDWebServer alloc]init]; // NSHomeDirectory() or [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] [self.webSever addGETHandlerForBasePath:@"/" directoryPath:kDocumentsPath indexFilename:nil cacheAge:3600 allowRangeRequests:YES]; [self.webSever startWithPort:kLocalServerPort bonjourName:nil]; } - (void)stop{ // 停止服務 [self.webSever stop];
self.webSever = nil; }
WKWebView創建方法
+ (instancetype)sharedWebView:(CGRect)frame configuration:(WKWebViewConfiguration *)config{ ZTEWebView *webView = nil; if(config == nil){ // 禁止選擇CSS NSString *css = @"body{-webkit-user-select:none;}"; // CSS選中樣式取消 此方式可能會影響dataDetectorTypes屬性 NSMutableString *javascript = [NSMutableString string]; [javascript appendString:@"var style = document.createElement('style');"]; [javascript appendString:@"style.type = 'text/css';"]; [javascript appendFormat:@"var cssContent = document.createTextNode('%@');", css]; [javascript appendString:@"style.appendChild(cssContent);"]; [javascript appendString:@"document.body.appendChild(style);"]; // javascript注入 WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; WKUserContentController *userContentController = [[WKUserContentController alloc] init]; // [userContentController addUserScript:noneSelectScript]; WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.userContentController = userContentController; // if(greaterIOS10){ // configuration.dataDetectorTypes = WKDataDetectorTypePhoneNumber | WKDataDetectorTypeLink | WKDataDetectorTypeCalendarEvent; // } WKPreferences *preferences = [[WKPreferences alloc] init]; preferences.javaScriptCanOpenWindowsAutomatically = YES; // 不通過用戶交互,是否可以打開窗口 preferences.javaScriptEnabled = YES; //是否支持JavaScript preferences.minimumFontSize = 15.0; // 最小字體大小 configuration.preferences = preferences; // 偏好設置 webView = [[self alloc] initWithFrame:frame configuration:configuration]; }else{ webView = [[self alloc] initWithFrame:frame configuration:config]; } return webView; }
WebView調試
打開通用設置->Safari->高級->Web 檢查器 (模擬器和真機都一樣)

然后打開Mac Safari 偏好設置->高級

運行app,打開webView,然后打開safari開發菜單,選擇模擬器還是iPhone,選擇對應的app就可以跳出Html調試界面,此處就不調試截圖.

