Автоматическое сохранение HTML <img>из WKWebView в каталог приложения tmp - PullRequest
0 голосов
/ 29 октября 2018

У меня есть WKWebView, который может посещать произвольные веб-сайты. Когда пользователь нажимает на любой элемент HTML <img>, я бы хотел, чтобы он прозрачно сохранил это изображение (в виде файла) в каталог приложения tmp, в идеале со стандартным заголовком (img.png), и в идеале, чтобы он будет перезаписывать каждый раз.

Учитывая, что клиентский JavaScript не имеет доступа к файловой системе, я ожидаю, что полностью автоматическое решение будет включать FileManager; однако я не знаю, как бы я передавал данные <img> из WKWebView в FileManager экземпляр. Интересно, может ли понадобиться участие JavaScriptCore, чтобы соединить данные между ними.

Я вижу, что полуавтоматические решения существуют , благодаря использованию атрибута HTML download, в котором пользователю предлагается диалог "Сохранить как ...". Это не идеально, Я хотел бы, чтобы действие было прозрачным и не содержало ошибок пользователя. Однако это может оказаться единственным вариантом.

Я реализую это как на MacOS, так и на iOS, поэтому могу принять решение для любой платформы; Я ожидаю, что между ними будет небольшая разница.

1 Ответ

0 голосов
/ 31 октября 2018

Могу ли я предложить следующее:

  1. Подготовьте контроллер представления к получению сообщений со стороны JavaScript WKWebView. Я обычно делаю это в контроллере вида viewDidLoad.
  2. Загрузите и выполните на веб-странице javascript, который добавит событие onClick к каждому тегу img.
  3. В этом случае вы отправляете сообщение обратно из javascript стороне Objective-C / Swift с строкой данных изображения в кодировке Base64 в качестве параметра
  4. В обработчике сообщения Objective-C / Swift вы преобразуете эту строку в данные и сохраняете ее.

Шаг 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] ;
}

Шаг 3:

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) ;
    } ;
}

Шаг 4:

Когда сообщение «imageHasBeenCLicked» получено контроллером представления, преобразуйте строку Base64 в данные и сохраните ее как файл изображения.

- (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] ;
    }
}
...