macOS WebView Baixar um arquivo Blob HTML5
Estou usando o HTML5Blob
API para baixar um arquivo de um cliente JavaScript em umWebView
aplicativo macOS baseado em:
/**
* Save a text as file using HTML <a> temporary element and Blob
* @author Loreto Parisi
*/
var saveAsFile = function(fileName,fileContents) {
if(typeof(Blob)!='undefined') { // using Blob
var textFileAsBlob = new Blob([fileContents], { type: 'text/plain' });
var downloadLink = document.createElement("a");
downloadLink.download = fileName;
if (window.webkitURL != null) {
downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
}
else {
downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
downloadLink.onclick = document.body.removeChild(event.target);
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
}
downloadLink.click();
} else {
var pp = document.createElement('a');
pp.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(fileContents));
pp.setAttribute('download', fileName);
pp.onclick = document.body.removeChild(event.target);
pp.click();
}
}//saveAsFile
Quando oBlob
não é suportado, ele usa a maneira DOM padrão. Quando executo meu aplicativo no MacGap2, executando este código chamado, digamossaveAsFile('out.json',jsonString);
isso levará a este erro:
2018-04-23 19:35:08.270857+0200 sendMessageWithDictionary: Failed to get remote object proxy: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.rtcreportingd" UserInfo={NSDebugDescription=connection to service named com.apple.rtcreportingd}
Então eu configurei oSandbox do aplicativo paraOutgoing Connections (Client)
, Também tentei interceptar o link, clicando noPolicyDelegate
:
- (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener
{
if (WebNavigationTypeLinkClicked == [[actionInformation objectForKey:WebActionNavigationTypeKey] intValue])
{
NSLog(@"CLICKED %@", [request URL]);
}
[[NSWorkspace sharedWorkspace] openURL:[request URL]];
[listener ignore];
}
- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id<WebPolicyDecisionListener>)listener
{
if (WebNavigationTypeLinkClicked == [[actionInformation objectForKey:WebActionNavigationTypeKey] intValue])
{
NSLog(@"CLICKED %@", [request URL]);
}
[listener use]; // Say for webview to do it work...
}
Nesse ponto, posso clicar no URL do Blob no último delegado; portanto, no domínio Objective-C / Cocoa, abordei o seguinte (que atualmente funciona emmacOS High Sierra / Xcode 9.3 / macOS 10.13
NSLog(@"CLICKED %@", [request URL]);
NSString *needle = @"blob:";
if( [[[request URL] absoluteString] hasPrefix:needle] ) {
// create a download link from blob url
NSRange blobRange = [[[request URL] absoluteString] rangeOfString:needle];
NSString * blobURL = [[[request URL] absoluteString] substringFromIndex:blobRange.location + needle.length];
NSURLRequest *downloadURLRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:blobURL]];
NSLog(@"BLOB URL:%@", [[downloadURLRequest URL] absoluteString]);
NSURLSessionDownloadTask *downloadTask = [[NSURLSession sharedSession] downloadTaskWithRequest:downloadURLRequest
completionHandler:^(NSURL *location, __unused NSURLResponse *response, NSError *error) {
if (location) {
// get download folders
NSArray *docDirs = NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory,
NSUserDomainMask, YES);
NSString *destinationFilename = [docDirs objectAtIndex:0];
if (destinationFilename) {
destinationFilename = [destinationFilename stringByAppendingPathComponent:@"out.json"];
NSLog(@"LOCATION %@ DOWNLOAD %@", [location absoluteString], destinationFilename);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *anError = nil;
NSString *fromPath = [location path];
if ([fileManager fileExistsAtPath:destinationFilename])
[fileManager removeItemAtPath:destinationFilename error:&anError];
BOOL fileCopied = [fileManager moveItemAtPath:fromPath toPath:destinationFilename error:&anError];
if (fileCopied == NO) {
} else {
NSLog(@"Downloaded!");
}
}
} else {
NSLog(@"Error:%@", [error description]);
}
}];
[downloadTask resume];
return;
}
Para habilitar o download de arquivos, tive que habilitar adicionalmente oDownload folders read/write
política na caixa de proteção de aplicativos. Basicamente agora eu posso interceptar oblob:
URLs que são um HTML5 típicoBlob
url (blob:https://myserver/BLOB_ID
) e tento fazer o download, mas - é claro que não funciona porque esse URL não parece ser válido, portanto, recebo um erro do servidor de arquivos - é claro
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /57de17ae-92bc-4553-a9d8-ac1b0f1f6c4f</pre>
</body>
</html>
Portanto, apesar do código acima geralmente funcionar bem para arquivos reais (ou seja, ter um URI válido), eu estava errado sobre oBlob
arquivos, como esses arquivos não são arquivos reais, deve haver uma maneira diferente de lidar com os URLs de Blob do lado do cliente em um macOS WebView.
[ATUALIZAR] Parece que existem truques diferentes para fazer isso funcionar via
API XMLHttpRequest mais FileReaderAPI requestFileSystem + FileWriterEntão, eu estou postando aquihttps://gist.github.com/loretoparisi/84df6a7c19f411dbf9d0a0d10505e222