Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WKWebView とめんどくさいお友達

2028fcf9065b3e34d2732587b6ac7bc5?s=47 Megabits_mzq
February 22, 2022

WKWebView とめんどくさいお友達

Swift 愛好会 2022/2/22 登壇資料

2028fcf9065b3e34d2732587b6ac7bc5?s=128

Megabits_mzq

February 22, 2022
Tweet

More Decks by Megabits_mzq

Other Decks in Programming

Transcript

  1. Jinyu Meng (Megabits Studio) WKWebView とめんどくさいお友達

  2. 個⼈紹介 独 ⽴ 開 発 者 で す ! Megabits

    ⾦⿂
  3. 個⼈紹介 Twitter @Megabits_mzq @Megabits_Studio

  4. None
  5. None
  6. “WebKit を触ると、不幸になる”  ──マハトマ・ガンディー が⾔ったことがない

  7. None
  8. self.view.window?.level = .floating

  9. None
  10. None
  11.      let width = view.frame.width let height = view.frame.height -

    toolbarView.frame.maxY let script1 = """ Object.defineProperty(window, "screenTop", { get: function(){ return 0; }}); Object.defineProperty(window, "outerWidth", { get: function(){ return \(width); }}); Object.defineProperty(window, "outerHeight", { get: function(){ return \(height); }}); """ let userScript1 = WKUserScript(source: script1, injectionTime: .atDocumentStart, forMainFrameOnly: true) webView.configuration.userContentController.addUserScript(userScript1)
  12. #import <AppKit/AppKit.h> #import <objc/runtime.h> static void HookMessage(Class cls, SEL selName,

    IMP replaced, IMP *orig) { Method origMethod = class_getInstanceMethod(cls, selName); if (!origMethod) {return;} *orig = method_setImplementation(origMethod, replaced); } static NSRect (*original_NSScreen_frame)(NSScreen *self, SEL _cmd); static NSRect replaced_NSScreen_frame(NSScreen *self, SEL _cmd) { //https://stackoverflow.com/questions/1451342/objective-c-find-caller-of-method NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"]; NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]]; [array removeObject:@""]; NSString *framework = [array objectAtIndex:1]; NSRect origFrame = original_NSScreen_frame(self, _cmd); if (![framework isEqualTo:@"WebCore"] { return origFrame; } return CGRectMake(0, 0, 0, 0); } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" __attribute__((constructor)) static void makeMyMagicWork() { HookMessage( objc_getClass("NSScreen"), NSSelectorFromString(@"frame"), (IMP)&replaced_NSScreen_frame, (IMP *)&original_NSScreen_frame ); } #pragma clang diagnostic pop
  13. None
  14. None
  15. None
  16. func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy)

    -> Void) { if navigationResponse.canShowMIMEType, let mimeType = navigationResponse.response.mimeType { let mainType = mimeType.components(separatedBy: "/")[0] // print(mainType, mimeType, navigationResponse.isForMainFrame) if !["image", "audio", "video"].contains(mainType) { if !(["text/plain", "text/xml"].contains(mimeType) && navigationResponse.isForMainFrame){ decisionHandler(.allow) return } } else if !navigationResponse.isForMainFrame { decisionHandler(.allow) return } } if let fileName = navigationResponse.response.suggestedFilename, let url = navigationResponse.response.url { webView.configuration.websiteDataStore.httpCookieStore.getAllCookies() { cookies in print(fileName) self.createNewDownload(url: url, fileName: fileName, cookies: cookies) } } decisionHandler(.cancel) }
  17. MIME Type • text/plain • text/xml • Image/png • Audio/mp3

    • Video/mp4 • … navigationResponse.canShowMIMEType, navigationResponse.response.mimeType
  18. navigationResponse.isForMainFrame

  19. Blob 👉 WKDownloadDelegate

  20. None
  21. override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) { super.willOpenMenu(menu,

    with: event) for (index, menuItem) in menu.items.enumerated() { switch menuItem.identifier?.rawValue { case "WKMenuItemIdentifierCopyImage": menu.removeItem(menuItem) default: break // print(menuItem.identifier?.rawValue ?? "") } } }
  22. window.oncontextmenu = (event) => { var target = event.target var

    href = target.href var parentElement = target while (href == null && parentElement.parentElement != null) { parentElement = parentElement.parentElement href = parentElement.href } if (href == null) { parentElement = null; } window.webkit.messageHandlers.oncontextmenu.postMessage({ nodeName: target.nodeName, id: target.id, src: target.src, hrefNodeName: parentElement?.nodeName, hrefId: parentElement?.id, href }); } """ https://stackover fl ow.com/a/66836354/1711103
  23. None
  24. @Megabits_mzq @Megabits_Studio https://menubarx.app