Objectif: réaliser une capture d'écran de WKWebView après le chargement du site Web.
Méthode employée:
Création d'une méthode d'extension appelée capture d'écran () qui prend une image de WKWebView
Fait mon UIViewController pour implémenter WKNavigationDelegate
Définissez wkwebview.navigationDelegate = self (dans l'initialisation UIViewController)
Implémentation de la fonction de délégation didFinishNavigation dans UIViewcontroller pour appeler la méthode d'extension de capture d'écran pour WKWebView
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { let img = webView.screenCapture() }
Des questions:
Qu'est-ce que j'oublie ici? J'ai examiné toutes les fonctions de délégation possibles pour WKWebView et rien d'autre ne semble représenter la fin du chargement du contenu dans WKWebView. J'apprécierais l'aide sur s'il y a un travail autour
Mise à jour: Ajout du code de capture d'écran que j'utilise pour prendre une capture d'écran pour l'affichage 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 n'utilise pas la délégation pour vous avertir que le chargement du contenu est terminé (c'est pourquoi vous ne pouvez trouver aucune méthode de délégation qui convienne à votre objectif). Pour savoir si un WKWebView est toujours en cours de chargement, utilisez KVO (observation de la valeur d'une clé) pour surveiller sa propriété loading
. De cette manière, vous recevez une notification lorsque loading
passe de true
à false
.
Voici un gif animé en boucle montrant ce qui se passe lorsque je teste cela. Je charge une vue Web et répond à sa propriété loading
par le biais de KVO pour prendre un instantané. La vue supérieure est la vue Web; la vue inférieure (écrasée) est l’instantané. Comme vous pouvez le constater, l’instantané capture le contenu chargé:
Pour ceux qui cherchent encore une réponse à cette question, la réponse marquée est BS, il s’est forcé à la faire accepter.
"loading" et webView (webView: WKWebView, navigation didFinishNavigation: WKNavigation!) font tous les deux la même chose, indiquent si la ressource principale est chargée. Maintenant, cela ne signifie pas que toute la page Web/site Web est chargée, car cela dépend vraiment de la mise en œuvre du site Web. S'il doit charger des scripts et des ressources (images, polices, etc.) pour se rendre visible, vous ne verrez toujours rien une fois la navigation terminée, car les appels réseau effectués par le site Web ne sont pas suivis par la vue Web. suivi, de sorte qu'il ne sache pas vraiment quand le site Web sera complètement chargé.
Voici comment je l'ai résolu:
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")
}
}
Mettre à jour 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
}
}
Ce n'est pas un bon choix pour vérifier si le contenu de la page chargé depuis Swift ou objective-c est spécialement conçu pour les pages très complexes comportant de nombreux contenus dynamiques.
Un meilleur moyen de vous informer du code ios à partir du javascript de la page Web. Cela le rend très flexible et efficace, vous pouvez notifier le code ios lorsqu'un dom ou la page est chargée.
Vous pouvez consulter mon post ici pour plus d'informations.
Beaucoup de mains abandonnées ici, pour des solutions incomplètes. L'observateur sur "chargement" n'est pas fiable car lorsqu'il passe en mode NON, la mise en page n'a pas encore eu lieu et vous ne pouvez obtenir une lecture précise du format de page.
L'injection de JS dans la vue pour signaler la taille de la page peut également être problématique en fonction du contenu réel de la page.
WKWebView utilise évidemment un scroller (une sous-classe "WKWebScroller" pour être exact). Donc, le mieux est de surveiller le contentSize de ce défilement.
- (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));
}
}
Méfiez-vous de la taille du contenu: cela se déclenche BEAUCOUP. Si votre WebView est intégrée à une autre zone de défilement (comme si vous l'utilisiez comme élément de formulaire), lorsque vous faites défiler la totalité de la vue, cette sous-vue WebView déclenchera les modifications pour les mêmes valeurs. Alors, assurez-vous de ne pas redimensionner inutilement ou provoquer des rafraîchissements inutiles.
Cette solution testée sur iOS 12 sur iPad Air 2 sim via High Sierra XCode 10.