May I propose the following :
- Prepare your view controller to receive messages from the javascript side of the WKWebView. I usually do that in the view controller's
viewDidLoad
.
- Load and execute a javascript in the web page that will add an onClick event to each
img
tag.
- In that event, you send a message back from javascript to Objective-C / Swift side with a Base64 encoded string of the image data as parameter
- In the Objective-C / Swift handler of the message, you transform that string in data and save it.
Step 1 & 2 :
- (void) viewDidLoad
{
[super viewDidLoad] ;
WKUserContentController *controller = self.webView.configuration.userContentController ;
// Add self as scriptMessageHandler of the webView to receive messages from the scripts
[controller addScriptMessageHandler:self
name:@"imageHasBeenClicked"] ;
// Load script
NSURL *scriptURL = <<... URL of your javascript (can be bundled in your app) ...>> ;
NSString *scriptString = [NSString stringWithContentsOfURL:scriptURL
encoding:NSUTF8StringEncoding
error:NULL] ;
WKUserScript *script = [[WKUserScript alloc] initWithSource:scriptString
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:YES] ;
[controller addUserScript:script] ;
}
Step 3 :
The javascript :
// This function takes an image tab and encodes the image as BAse64
function getBase64Image(img)
{
// Create an empty canvas element
var canvas = document.createElement("canvas") ;
canvas.width = img.width;
canvas.height = img.height;
// Copy the image contents to the canvas
var ctx = canvas.getContext("2d") ;
ctx.drawImage(img,0,0) ;
// Get the data-URL formatted image, use PNG as JPG re-encode the image
var dataURL = canvas.toDataURL("image/png");
// Remove the initial marker so that we directly have NSData compatibility
return dataURL.replace(/^data:image\/(png|jpg);base64,/,"");
}
// Search for all img tags and add an onclick event that will encode the image
// then, send it to the objective-c side
var imgList = document.getElementsByTagName("img") ;
for (var i = 0; i < imgList.length; i++)
{
imgList[i].onclick = function()
{
var txt = getBase64Image(this) ;
window.webkit.messageHandlers["imageHasBeenClicked"].postMessage(txt) ;
} ;
}
Step 4 :
When the "imageHasBeenCLicked" message is received by the view controller, then convert the Base64 string into data and save it as an image file.
- (void) userContentController:(WKUserContentController*)userContentController
didReceiveScriptMessage:(WKScriptMessage*)message
{
if ([message.name isEqualToString:@"imageHasBeenClicked"])
{
NSData *data = [[NSData alloc] initWithBase64EncodedString:message.body
options:0] ;
[data writeToFile:@"/toto.png"
atomically:YES] ;
}
}