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
780
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
170
SwiftUI と Shader を活用した楽しいオンボーディング起動画面の作成
megabitsenmzq
0
130
Liquid Glass, どこが変わったのか
megabitsenmzq
0
180
iPhone 16 Camera Control
megabitsenmzq
0
160
240fps で画像処理したい
megabitsenmzq
0
240
Swift 開発が楽になる道具たち
megabitsenmzq
1
780
Animoji を作ってみた
megabitsenmzq
0
210
MainMenu.xib を翻訳してみた
megabitsenmzq
0
300
先週解決した SwiftUI 問題
megabitsenmzq
0
150
Other Decks in Programming
See All in Programming
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
170
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
0
160
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
410
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1k
AIを活用したE2Eテスト実装効率化のあゆみ / ebisu-mobile-14-kotetu
kotetuco
0
140
これからAgentCoreを触る方へトレンドはGatewayです
har1101
2
310
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.3k
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
280
AIで効率化できた業務・日常
ochtum
0
150
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
310
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
8.5k
Agentic UI
manfredsteyer
PRO
0
200
Featured
See All Featured
Paper Plane
katiecoart
PRO
1
52k
Embracing the Ebb and Flow
colly
88
5.1k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
470
New Earth Scene 8
popppiees
3
2.4k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Unsuck your backbone
ammeep
672
58k
A Modern Web Designer's Workflow
chriscoyier
698
190k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
210
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Between Models and Reality
mayunak
4
350
What does AI have to do with Human Rights?
axbom
PRO
1
2.2k
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