Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
WKWebView とめんどくさいお友達
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Megabits_mzq
February 22, 2022
Programming
770
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
WKWebView とめんどくさいお友達
Swift 愛好会 2022/2/22 登壇資料
Megabits_mzq
February 22, 2022
More Decks by Megabits_mzq
See All by Megabits_mzq
OTP を自動で入力する裏技
megabitsenmzq
0
160
SwiftUI と Shader を活用した楽しいオンボーディング起動画面の作成
megabitsenmzq
0
130
Liquid Glass, どこが変わったのか
megabitsenmzq
0
170
iPhone 16 Camera Control
megabitsenmzq
0
150
240fps で画像処理したい
megabitsenmzq
0
240
Swift 開発が楽になる道具たち
megabitsenmzq
1
780
Animoji を作ってみた
megabitsenmzq
0
210
MainMenu.xib を翻訳してみた
megabitsenmzq
0
300
先週解決した SwiftUI 問題
megabitsenmzq
0
140
Other Decks in Programming
See All in Programming
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
540
ふつうのFeature Flag実践入門
irof
7
3.6k
3Dシーンの圧縮
fadis
1
650
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
2.8k
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.2k
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
630
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
340
関係性から理解する"同一性"の型用語たち
pvcresin
2
640
エージェンティックRAGにAWSで入門しよう!
har1101
7
1.1k
CSC307 Lecture 17
javiergs
PRO
0
310
JavaDoc 再入門
nagise
0
280
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
500
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
140
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
340
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
140
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
570
Mind Mapping
helmedeiros
PRO
1
230
The World Runs on Bad Software
bkeepers
PRO
72
12k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
350
A Modern Web Designer's Workflow
chriscoyier
698
190k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
460
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
250
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
400
Transcript
Jinyu Meng (Megabits Studio) WKWebView とめんどくさいお友達
個⼈紹介 独 ⽴ 開 発 者 で す ! Megabits
⾦⿂
個⼈紹介 Twitter @Megabits_mzq @Megabits_Studio
None
None
“WebKit を触ると、不幸になる” ──マハトマ・ガンディー が⾔ったことがない
None
self.view.window?.level = .floating
None
None
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)
#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
None
None
None
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) }
MIME Type • text/plain • text/xml • Image/png • Audio/mp3
• Video/mp4 • … navigationResponse.canShowMIMEType, navigationResponse.response.mimeType
navigationResponse.isForMainFrame
Blob 👉 WKDownloadDelegate
None
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 ?? "") } } }
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
None
@Megabits_mzq @Megabits_Studio https://menubarx.app