目標:Webサイトの読み込みが完了した後にWKWebViewのスクリーンショットを撮る
採用された方法:
WKWebViewの画像を取得するscreen capture()という拡張メソッドを作成しました
UIViewControllerを作成してWKNavigationDelegateを実装しました
Wkwebview.navigationDelegate = selfを設定します(UIViewController init内)
UIViewcontrollerにdidFinishNavigation委任funcを実装して、WKWebViewの画面キャプチャ拡張メソッドを呼び出しました。
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { let img = webView.screenCapture() }
質問:
ここで何が欠けていますか? WKWebViewで可能なすべてのデリゲート関数を調べましたが、WKWebViewでのコンテンツの読み込みの完了を表すものは他にありません。回避策があれば助けていただければ幸いです
更新:Webビューのスクリーンショットを撮るために使用しているスクリーンショットコードを追加
class func captureEntireUIWebViewImage(webView: WKWebView) -> UIImage? {
var webViewFrame = webView.scrollView.frame
if (webView.scrollView.contentSize != CGSize(width: 0,height: 0)){
webView.scrollView.frame = CGRectMake(webViewFrame.Origin.x, webViewFrame.Origin.y, webView.scrollView.contentSize.width, webView.scrollView.contentSize.height)
UIGraphicsBeginImageContextWithOptions(webView.scrollView.contentSize, webView.scrollView.opaque, 0)
webView.scrollView.layer.renderInContext(UIGraphicsGetCurrentContext())
var image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
webView.scrollView.frame = webViewFrame
return image
}
return nil
}
WKWebViewは委任を使用してコンテンツの読み込みが完了したことを通知しません(そのため、目的に合った委任メソッドが見つかりません)。 WKWebViewがまだロードされているかどうかを知る方法は、KVO(キー値監視)を使用してloading
プロパティを監視することです。このようにして、loading
がtrue
からfalse
に変更されたときに通知を受け取ります。
これは、これをテストするとどうなるかを示すループアニメーションGIFです。 Webビューをロードし、KVOを介してそのloading
プロパティに応答してスナップショットを取得します。上部のビューはWebビューです。下の(押しつぶされた)ビューはスナップショットです。ご覧のとおり、スナップショットはロードされたコンテンツをキャプチャします。
まだこれに対する答えを探している人にとって、マークされた答えはBSです、彼はそれを受け入れさせるために彼の方法を強要しました。
「ロード」とwebView(webView:WKWebView、didFinishNavigation navigation:WKNavigation!)は両方とも同じことを行い、メインリソースがロードされているかどうかを示します。これは、Webページ/ Webサイト全体がロードされることを意味するものではありません。Webサイトの実装に本当に依存しているからです。スクリプトやリソース(画像、フォントなど)を読み込んで表示できるようにする必要がある場合、ナビゲーションが完了しても何も表示されません。ウェブサイトによって行われたネットワーク呼び出しはウェブビューによって追跡されず、ナビゲーションのみが追跡されているため、いつWebサイトが完全に読み込まれたかはわかりません。
ここに私がそれを解決した方法があります:
class Myweb: WKWebView {
func setupWebView(link: String) {
let url = NSURL(string: link)
let request = NSURLRequest(URL: url!)
loadRequest(request)
addObserver(self, forKeyPath: "loading", options: .New, context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard let _ = object as? WKWebView else { return }
guard let keyPath = keyPath else { return }
guard let change = change else { return }
switch keyPath {
case "loading":
if let val = change[NSKeyValueChangeNewKey] as? Bool {
if val {
} else {
print(self.loading)
//do something!
}
}
default:break
}
}
deinit {
removeObserver(self, forKeyPath: "loading")
}
}
更新Swift 3.1
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let _ = object as? WKWebView else { return }
guard let keyPath = keyPath else { return }
guard let change = change else { return }
switch keyPath {
case "loading":
if let val = change[NSKeyValueChangeKey.newKey] as? Bool {
//do something!
}
default:
break
}
}
不完全なソリューションのために、ここで多くの手を放棄します。 「ロード」のオブザーバーは、NOに切り替えたときにレイアウトがまだ行われておらず、ページサイズの正確な読み取り値を取得できないため、信頼できません。
ページサイズをレポートするためにビューにJSを挿入することも、実際のページコンテンツによっては問題になる可能性があります。
WKWebViewは、明らかに、スクローラー(正確には「WKWebScroller」サブクラス)を使用します。したがって、最善の策は、そのスクローラーのcontentSizeを監視することです。
- (void) viewDidLoad {
//...super etc
[self.webKitView.scrollView addObserver: self
forKeyPath: @"contentSize"
options: NSKeyValueObservingOptionNew
context: nil];
}
- (void) dealloc
{
// remove observer
[self.webKitView.scrollView removeObserver: self
forKeyPath: @"contentSize"];
}
- (void) observeValueForKeyPath: (NSString*) keyPath
ofObject: (id) object
change: (NSDictionary<NSKeyValueChangeKey,id>*) change
context: (void*) context
{
if ([keyPath isEqualToString: @"contentSize"])
{
UIScrollView* scroller = (id) object;
CGSize scrollFrame = scroller.contentSize;
NSLog(@"scrollFrame = {%@,%@}",
@(scrollFrame.width), @(scrollFrame.height));
}
}
ContentSizeに気をつけてください:それはLOTをトリガーします。 webViewが別のスクロール領域に埋め込まれている場合(フォーム要素として使用している場合など)、ビュー全体をスクロールすると、そのサブビューwebViewは同じ値の変更をトリガーします。したがって、不必要にサイズを変更したり、不必要な更新を行わないようにしてください。
このソリューションは、iPad Air 2上のiOS 12でHigh Sierra XCode 10からシミュレーションを行いました。
ページコンテンツがSwift=またはObjective-cから読み込まれたかどうかを確認するのは良い選択ではありません。特に、多くの動的コンテンツを含む非常に複雑なページの場合。
WebページのJavaScriptからiOSコードを通知するより良い方法。これにより、非常に柔軟で効果的になり、domまたはページがロードされたときにiOSコードを通知できます。
詳細については、ここpostで確認できます。