WKWebViewの魔改造
福山 慎吾
Shingo Fukuyama
iOS WKWebViewの魔改造 - iOSDC 2018
iOS Web Browser App
2014~
• 高速DOM (Document Object Model) 操作
• WKWebView内動画をAVPlayerでバックグラウンド再生
• WKWebView内ジェスチャへのアクセスと操作
• JavaScript -> Swift Tips
WKWebView
WKWebView
UIWebView
UIWebView
iOS 12で公式に非推奨・廃止予定
•速い: レンダリング、JavaScript実行速度
•安全: プロセスが分離されている
•安定: アプリをクラッシュさせない
WKWebView
WKWebView
Swift JavaScript
WKWebViewにJavaScriptを注入
iOS WKWebViewの魔改造 - iOSDC 2018
WKWebView
と組み合わせると強力な
JavaScript API..
Mutation Observer
JavaScript API
Mutation Observer
Mutation Observer
WKWebView + Mutation Observer
WKWebView + Mutation Observer
• DOM要素の変更(削除,非表示,置換等)をレンダリングの前に行える
WKWebView + Mutation Observer
• DOM要素の変更(削除,非表示,置換等)をレンダリングの前に行える
• 要素がDOMツリーに追加された直後に EventListener をセットでき
る
WKWebView + Mutation Observer
• DOM要素の変更(削除,非表示,置換等)をレンダリングの前に行える
• 要素がDOMツリーに追加された直後に EventListener をセットでき
る
• すべてのDOM要素を監視・非同期操作してもパフォーマンスに大
きな影響は見られない
WKWebView + Mutation Observerの活用例
WKWebView + Mutation Observerの活用例
• 細かく設定できiOS 10以前でも使えるコンテンツブロック
WKWebView + Mutation Observerの活用例
• 細かく設定できiOS 10以前でも使えるコンテンツブロック
• リアルタイムでスタイルを変更
WKWebView + Mutation Observerの活用例
• 細かく設定できiOS 10以前でも使えるコンテンツブロック
• リアルタイムでスタイルを変更
• イベントの即時監視
WKWebView内動画
バックグラウンド再生
WKWebView動画
アプリ起動中のみ
WKWebView動画
アプリ起動中のみ
AVPlayer
WKWebView動画
アプリ起動中のみ アプリ起動中
ホーム画面
他アプリ使用中
デバイスロック中
Picture in Picture (iPad)
AVPlayer
WKWebView動画
アプリ起動中のみ
AVPlayer
URL
アプリ起動中
ホーム画面
他アプリ使用中
デバイスロック中
Picture in Picture (iPad)
動画URLの取得
<video src=“video.mp4”>
<video src=“dummy.mp4”>
ダミーファイル
Playイベント発火時
<video src=“video.mp4”>
or
<video>
<source src=“video.mp4”
type=“video/mp4”>
</video>
本物の動画リンクが現れる
Class WKWebViewConfiguration
var allowsInlineMediaPlayback: Bool { get set }
デフォルト値: false (iPhone), true (iPad)
iOS 10.0 より前への対応は <video> タグにwebkit-playsinlineをつける
WKWebView独自の動画プレイヤーを無効化
WKWebView内の動画をバックグラウンド再生
WKWebView内の動画をバックグラウンド再生
1. Mutation Observerで<video>タグ追加時にすぐ捕まえる
1. Mutation Observerで<video>タグ追加時にすぐ捕まえる
2. EventListenerで<video>タグのplayイベントを監視する
WKWebView内の動画をバックグラウンド再生
1. Mutation Observerで<video>タグ追加時にすぐ捕まえる
2. EventListenerで<video>タグのplayイベントを監視する
3. WKScriptMessageHandlerで本物の動画URLをSwift側へ通知する
WKWebView内の動画をバックグラウンド再生
1. Mutation Observerで<video>タグ追加時にすぐ捕まえる
2. EventListenerで<video>タグのplayイベントを監視する
3. WKScriptMessageHandlerで本物の動画URLをSwift側へ通知する
4. デフォルトプレイヤーの起動を阻止し、バックグラウンド再生や
PIPの設定をしたAVPlayerで再生
WKWebView内の動画をバックグラウンド再生
WKWebView内ジェスチャーの操作
WKWebView内ジェスチャーの操作
WKWebView内ジェスチャーの操作
1. 呼び水としてWKWebViewにpanジェスチャをつける
WKWebView内ジェスチャーの操作
1. 呼び水としてWKWebViewにpanジェスチャをつける
2. UIGestureRecognizerDelegateの
gestureRecognizer(_:shouldRecognizeSimultan
eouslyWith:) で取り出す
WKWebView内ジェスチャーの操作
1. 呼び水としてWKWebViewにpanジェスチャをつける
WKWebView内ジェスチャーの操作
2. UIGestureRecognizerDelegateで取り出す
WKWebView内ジェスチャーの操作
WKWebView内ジェスチャーの操作
活用例: リンク長押し時間の変更
WKWebView内ジェスチャーの操作
活用例: webview上のスクロール領域を認識
WKScriptMessageHandler 活用例
WKScriptMessageHandler 活用例
document.cookieへの変更を監視
WKScriptMessageHandler 活用例
Ajax通信リクエストを監視、すり替え
サンプルアプリ
https://github.com/ShingoFukuyama/BackgroundVideoW
KWebViewSample
WKWebView内の動画をバックグラウンド再生
ありがとうございました

More Related Content

PPTX
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PDF
インタフェース完全に理解した
KEY
やはりお前らのMVCは間違っている
PPTX
JIRA / Confluence の 必須プラグインはこれだ
PDF
私にとってのテスト
PDF
Dockerfileを改善するためのBest Practice 2019年版
PDF
フロー効率性とリソース効率性について #xpjug
PPTX
5分で出来る!イケてるconfluenceページ
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
インタフェース完全に理解した
やはりお前らのMVCは間違っている
JIRA / Confluence の 必須プラグインはこれだ
私にとってのテスト
Dockerfileを改善するためのBest Practice 2019年版
フロー効率性とリソース効率性について #xpjug
5分で出来る!イケてるconfluenceページ

What's hot (20)

PDF
Unityでオニオンアーキテクチャ
PPTX
Universal Links対応をした話
PPTX
SPAセキュリティ入門~PHP Conference Japan 2021
PDF
リッチなドメインモデル 名前探し
PDF
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
PDF
フロー効率性とリソース効率性、再入門 #devlove #devkan
PDF
Linux女子部 systemd徹底入門
PPTX
テストコード入門
PDF
Usb接続するアプリを開発した時に試行錯誤した事
PPTX
はじめてのこんぴゅうとしぇえだあ〜ComputeShaderに入門してみた話〜
PDF
ドメイン駆動設計をゲーム開発に活かす
PPTX
WkWebViewのキャッシュについて調べた
PDF
Unity開発で使える設計の話+Zenjectの紹介
PDF
TDD のこころ
PDF
Machinationの紹介
PDF
Akkaとは。アクターモデル とは。
PDF
テストとリファクタリングに関する深い方法論 #wewlc_jp
PDF
ネットワーク ゲームにおけるTCPとUDPの使い分け
PDF
実装して理解するLINE LoginとOpenID Connect入門
PPTX
GraphQLのsubscriptionで出来ること
Unityでオニオンアーキテクチャ
Universal Links対応をした話
SPAセキュリティ入門~PHP Conference Japan 2021
リッチなドメインモデル 名前探し
【BS4】時は来たれり。今こそ .NET 6 へ移行する時。
フロー効率性とリソース効率性、再入門 #devlove #devkan
Linux女子部 systemd徹底入門
テストコード入門
Usb接続するアプリを開発した時に試行錯誤した事
はじめてのこんぴゅうとしぇえだあ〜ComputeShaderに入門してみた話〜
ドメイン駆動設計をゲーム開発に活かす
WkWebViewのキャッシュについて調べた
Unity開発で使える設計の話+Zenjectの紹介
TDD のこころ
Machinationの紹介
Akkaとは。アクターモデル とは。
テストとリファクタリングに関する深い方法論 #wewlc_jp
ネットワーク ゲームにおけるTCPとUDPの使い分け
実装して理解するLINE LoginとOpenID Connect入門
GraphQLのsubscriptionで出来ること
Ad

iOS WKWebViewの魔改造 - iOSDC 2018

Editor's Notes

  • #2: WKWebViewの魔改造というタイトルで話します。 自己紹介
  • #3: 福山慎吾といいます。 IOSDCに参加するのは2回目ですが、 こういう場で話すことは初めてなのでよろしくお願いします。
  • #4: 今は楽天でROOMというアプリの開発に携わっています。 これは楽天市場のショッピングSNSです。 欲しいものや、購入したものを投稿をして それを見たほかの人がその商品を購入すると、投稿した人も買った人も楽天ポイントがもらえるというアプリです。 最近Texture 旧名AsyncDisplayKitを導入し始めたので、現時点ではメイン画面だけスクロールがぬるぬる動くと思います。よかったら試してみてください。 今回、話す内容はこのアプリではなく、
  • #5: このアプリ。 2014年からiOSのWebブラウザアプリを趣味で作っています。 ちょうどこのとき、iOS 8でWKWebViewも公開されました。 当時のWKWebViewはできないことばかりで、たいへん苦労しました。 今回はその中で、今でも使えるWKWebViewの技術を紹介します。
  • #6: 内容はこちら 高速DOM、Document Object Model 操作。 これによってリアルタイムにコンテンツブロックやスタイル操作を行えるようになります。 WKWebView内の動画をカスタマイズしたAVPlayerでバックグラウンド再生できるようにします。これに関してはサンプルアプリも後ほど公開します。 WKWebView内部のジェスチャへのアクセスと操作。 あることをするとWKWebView内にある独自のUIGestureRecognizerを扱えるようになります。 そして最後に少し、JavaScriptからSwiftへの通知で役立ちそうなサンプルを紹介します。
  • #7: WKWebView ここ最近、再びWKWebViewが注目され始めました。 なんでだと思いますか? それは、、、
  • #8: UIWebView. iOSがまだiPhone OSと呼ばれていた時代、 2008年から10年も存在し続けているAPIです。 それがこのたび iOS 12で、
  • #9: 公式に非推奨・廃止予定となりました。 今までは非推奨となってはいなかったものの、AppleからもWKWebViewへ移行するように促すドキュメントも見られました。 [アンケート] 興味本位に少し聞いてみたいんですけど、 この会場の中で、今取り組んでいるプロジェクトでUIWebViewを使っている、 または移行中というかた。少し手を上げていただけますでしょうか? Result: more than 30%
  • #10: 次にWKWebViewとUIWebViewとの比較を簡単に紹介します。 レンダリング速度、JavaScriptの実行速度が高速化されています。 アプリ自体とWKWebView、ネットワーク処理はそれぞれ別のプロセスで動作しているため、どれかにセキュリティ問題が生じても全てに影響しにくくなっています。 プロセスが分離されているため、WKWebViewのプロセスがクラッシュしたとしても、アプリ自体はクラッシュしません。 iOS Google ChromeがUIWebViewからWKWebViewへ移行した際にクラッシュ率が70%減少したという記事もあります。
  • #11: では、SwiftとJavaScriptを使ってゴリゴリしていきます。 SwiftからWKWebViewへJavaScriptを注入する方法の一つに evaluateJavaScript:completionHandler: というメソッドもありますが、今回は別の方法を使います。
  • #12: Webページのコンテンツ読み込み前、もしくは読み込み後に毎回自動でJavaScriptを実行する WKUserScriptを使います。 コードはこんな感じで WKWebViewConfigurationで設定します。
  • #13: 注入のタイミングは2パターン。 Documentが読み込まれた後でかつコンテンツの読み込み前。 コンテンツの読み込み後かつ画像などのサブリソースのロード前です。
  • #14: ここで何を実行するのか。 それがこれから紹介するもの。 WKWebViewと組み合わせると強力でいろいろできるJavaScript APIがあります。 それが、
  • #15: Mutation Observerというものです。 このAPIはDOMの変更を監視するものです。 通常のWebページで使われることは稀かれもしれませんが、 不特定多数のWebページを扱うWebブラウザで力を発揮します。
  • #16: このように設定ができ、DOM変更に加えて、特定のattributes変更のみを監視することもできます。 Documentを監視対象にすることで<html>タグを含む全ての変更を監視できます。
  • #17: 変更結果はリアルタイムに配列として帰ってきます。 ここで特定の要素をフィルターして、変更を加えていきます。 モダンなJavaScriptの書き方には、 キャッチアップしていないので勘弁してください。
  • #18: WKWebViewとMutation Observerを組み合わせることで得られるメリットは、
  • #19: DOM要素の変更、削除、非表示、置換などをレンダリングの前に行えます。
  • #20: そして、要素がDOMツリーに追加された直後に JavaScript APIのEventListenerを追加でき、 イベントを監視することができます。
  • #21: ベンチマークを取ったわけではありませんが、 すべてのDOM要素を監視・非同期操作してもパフォーマンスに大きな影響は見られませんでした。 同期操作では重たくなるので非同期 setTimeout、最近ではPromiseでしょうか。 を使います。
  • #22: WKWebViewとMutationObserverの活用例
  • #23: iOS 11でコンテンツブロックがWKWebViewにも導入されましたが、 それより前のiOSでも有効な手法です。 もちろんiOS 11のコンテンツブロックと組み合わせることでより強力なコンテンツブロックが可能になります。
  • #24: レンダリングの前にスタイルを操作できるため、 ユーザーから見てもスタイルが変わる瞬間に気づくことはありません。
  • #25: そしてEventListenerを追加してイベントの即時監視ができます。 これは次に話すことに関連してきます。
  • #26: WKWebView内動画のバックグラウンド再生方法について話します。
  • #27: 通常WKWebView内で動画を再生すると、アプリ起動中のみ再生を行えます。 一方
  • #28: AVKitのAVPlayerでは
  • #29: ホーム画面、 ほかアプリ使用中、 デバイスロック中 に動画の音声が継続して再生できます。 さらにiPadではPIP、Picture in Pictureを使って 動画をホーム画面や他のアプリにいるときでも小窓で再生することが可能です。
  • #30: AVPlayerで再生できればなんでもできそうです。 単純にWKWebViewの動画からURLをぽんっと渡せば良さそうですが、 通常の動画サイトはなんらかの対策をとっており、そうはさせてくれません。
  • #31: 動画URLの取得
  • #32: src属性にあるURLをコピーすれば良さそうですが、
  • #33: これは通常ダミーファイルもしくは空となっています。 しかし、本物の動画URLが現れる瞬間があります。
  • #34: それがplayイベント発火時です。 このときのURLをSwift側のAVPlayerへ渡します。 ちなみにAndroidのWebViewはBlob URLでの再生に対応しており、 この方法ではうまくいきません。 そのまえに、
  • #35: WKWebViewのデフォルトプレイヤーが出てくるのを防ぐ必要があります。 WKWebViewConfigurationには allowsInlineMediaPlaybackというプロパティがあり、 初期値はiPhoneではfalse、iPadではtrueとなっています。 この値をtrueにして、インライン再生の設定を行えば、全画面化することなくWebページの上で再生できます。 iOS 10より前への対応は<video>タグにwebkit-playsinlineという属性をつけると大丈夫です。 再生を開始した<video>タグは用済みなので即座に停止させます。
  • #36: WKWebView内の動画バックグラウンド再生 のまとめ
  • #37: Mutation Observerで<video>タグ追加時に捕まえる
  • #38: EventListenerで<video>タグのplayイベントを監視する
  • #39: WKScriptMessageHandlerで本物の動画URLをSwift側へ通知する
  • #40: デフォルトプレイヤーの起動を阻止し、バックグラウンド再生やPIPの設定をしたAVPlayerで再生 サンプルアプリは後で公開します。
  • #41: WKWebView内ジェスチャの操作
  • #42: ->
  • #43: まず、呼び水としてWKWebViewにpanジェスチャをつけます。
  • #44: UIGestureRecognizerDelegate gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) で取り出します。 呼び水にしたジェスチャと衝突した他のWKWebView内ジェスチャがここで姿を現します。
  • #45: WKWebView自体にpanジェスチャをつける
  • #46: UIGestureRecognizerDelegateで取り出す。 そうすると、次のようなジェスチャが網にかかります。
  • #47: 見慣れないものばかりですね。 これらは私達が普段使うジェスチャのサブクラスだったりするので、 親クラスにキャストすることで扱うことができます。 無効にしたり、プロパティをいじったり、特定のジェスチャをなにかの目印にするのもいいと思います。
  • #48: 活用例です。 特定のLongPressGestureを捕まえて WKWebView内リンクの長押し時間を変更したり、
  • #49: WKWebView上のスクロール可能領域を操作中かどうかを判定できます。
  • #50: 次はWKScriptMessageHandlerの活用例を紹介します。 SwiftやObjective-Cで言うところの黒魔術のJavaScript版です。 WKScriptMessageHandlerはJavaScriptからSwiftへ通知を行うものです。
  • #51: Document.cookieにgetterとsetterを生やします。 もともとの機能は保たれており、 Cookieが追加された瞬間にSwift側へ値とともに通知する仕組みです。 Cookieに限らず様々なJavaScriptのプロパティを監視できるようになります。
  • #52: Ajax通信リクエストの監視、すり替え XMLHttpRequestをオーバーライドする形で 既存の働きの前にURLフィルタをかけ、ブロックしたい通信をすり替えています。
  • #53: 最後に こちらが動画再生のサンプルアプリです。 [時間があればデモ] [PR]