Conversation
| ResourceDownloadManager.shared.downloadRawKMP(from: request.url!) { file, error in | ||
| // do something! | ||
| if let error = error { | ||
| let alert = ResourceFileManager.shared.buildSimpleAlert(title: "Error", message: error.localizedDescription) |
There was a problem hiding this comment.
Yes, that "Error" should be localized. Sadly, I noted that there are a couple of other matching, non-localized spots yet to handle... which are actually rather related:
(Lines 268 and 274, in particular.)
May as well address all three together, whether that be within this PR or a separate one.
| let alertController = UIAlertController(title: "Cannot Open Page", | ||
| message: error.localizedDescription, | ||
| preferredStyle: UIAlertController.Style.alert) | ||
| alertController.addAction(UIAlertAction(title: "OK", |
There was a problem hiding this comment.
And probably these, too, which (despite how Git will show it) are unchanged lines.
|
The noted i18n spots have been rounded up as part of #4577. |
…ings fix(ios): adds i18n for some error alerts
| func webView(_ webView: UIWebView, | ||
| shouldStartLoadWith request: URLRequest, | ||
| navigationType: UIWebView.NavigationType) -> Bool { | ||
| if request.url?.lastPathComponent.hasSuffix(".kmp") ?? false { |
There was a problem hiding this comment.
This may not be 100% correct. We should be looking at the content-disposition header if it exists to determine the filename. We cannot assume that a URL will have a .kmp extension (e.g. it might be called something like file-downloader.php)
There was a problem hiding this comment.
When using the keyman.com language search. the initial link is PHP, though that ends up resolving to a .kmp that this can then intercept.
I'm completely unfamiliar with such headers; have any good example ones you could point me at for this?
There was a problem hiding this comment.
Like, for an actual .kmp.
There was a problem hiding this comment.
I don't have one handy, but you could throw this onto a local website together with khmer_angkor.kmp (which you can even rename if you want, e.g. in the script below I renamed the copy I am reading from to example_khmer_angkor.dat just to illustrate). You could save this as download.php.
<?php
$file = './example_khmer_angkor.dat';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=khmer_angkor.kmp');
header('Content-Length: ' . filesize($file));
readfile($file);There was a problem hiding this comment.
I'll test with that shortly, but first I wanted to see what I can get from the keyboard search.
From the keyboard page for sil_ipa, the link seems to process in three stages:
Stage 1:
▿ https://keyman.com/keyboard/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
▿ url : Optional<URL>
▿ some : https://keyman.com/keyboard/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- _url : https://keyman.com/keyboard/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- cachePolicy : 0
- timeoutInterval : 2147483647.0
▿ mainDocumentURL : Optional<URL>
▿ some : https://keyman.com/keyboard/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- _url : https://keyman.com/keyboard/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
▿ httpMethod : Optional<String>
- some : "GET"
▿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
▿ some : 3 elements
▿ 0 : 2 elements
- key : "Accept"
- value : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
▿ 1 : 2 elements
- key : "User-Agent"
- value : "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
▿ 2 : 2 elements
- key : "Referer"
- value : "https://keyman.com/keyboards/sil_ipa"
- httpBody : nil
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : true
Stage 2:
▿ https://keyman.com/keyboards/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
▿ url : Optional<URL>
▿ some : https://keyman.com/keyboards/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- _url : https://keyman.com/keyboards/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- cachePolicy : 0
- timeoutInterval : 2147483647.0
▿ mainDocumentURL : Optional<URL>
▿ some : https://keyman.com/keyboards/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- _url : https://keyman.com/keyboards/download?id=sil_ipa&platform=ios&mode=standalone&cid=760108319.1607477546
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
▿ httpMethod : Optional<String>
- some : "GET"
▿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
▿ some : 5 elements
▿ 0 : 2 elements
- key : "Accept-Encoding"
- value : "gzip, deflate, br"
▿ 1 : 2 elements
- key : "Accept"
- value : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
▿ 2 : 2 elements
- key : "Referer"
- value : "https://keyman.com/keyboards/sil_ipa"
▿ 3 : 2 elements
- key : "User-Agent"
- value : "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
▿ 4 : 2 elements
- key : "Accept-Language"
- value : "en-us"
- httpBody : nil
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : true
Stage 3:
▿ https://downloads.keyman.com/keyboards/sil_ipa/1.8.4/sil_ipa.kmp
▿ url : Optional<URL>
▿ some : https://downloads.keyman.com/keyboards/sil_ipa/1.8.4/sil_ipa.kmp
- _url : https://downloads.keyman.com/keyboards/sil_ipa/1.8.4/sil_ipa.kmp
- cachePolicy : 0
- timeoutInterval : 2147483647.0
▿ mainDocumentURL : Optional<URL>
▿ some : https://downloads.keyman.com/keyboards/sil_ipa/1.8.4/sil_ipa.kmp
- _url : https://downloads.keyman.com/keyboards/sil_ipa/1.8.4/sil_ipa.kmp
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
▿ httpMethod : Optional<String>
- some : "GET"
▿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
▿ some : 5 elements
▿ 0 : 2 elements
- key : "Accept-Encoding"
- value : "gzip, deflate, br"
▿ 1 : 2 elements
- key : "Accept-Language"
- value : "en-us"
▿ 2 : 2 elements
- key : "Referer"
- value : "https://keyman.com/keyboards/sil_ipa"
▿ 3 : 2 elements
- key : "Accept"
- value : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
▿ 4 : 2 elements
- key : "User-Agent"
- value : "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
- httpBody : nil
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : true
There was a problem hiding this comment.
Setting that up under my local keymanweb.com development 'server' setup...
▿ http://keymanweb.com.local/test.php
▿ url : Optional<URL>
▿ some : http://keymanweb.com.local/test.php
- _url : http://keymanweb.com.local/test.php
- cachePolicy : 0
- timeoutInterval : 60.0
▿ mainDocumentURL : Optional<URL>
▿ some : http://keymanweb.com.local/test.php
- _url : http://keymanweb.com.local/test.php
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
▿ httpMethod : Optional<String>
- some : "GET"
▿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
▿ some : 2 elements
▿ 0 : 2 elements
- key : "Accept"
- value : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
▿ 1 : 2 elements
- key : "User-Agent"
- value : "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
- httpBody : nil
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : true
There are no further stages; the next thing that occurs is a "Frame load interrupted" error. So that's all iOS will give me without very significant changes, unless I'm missing something.
|
So... while the solution implemented by this PR isn't optimal, as you've well pointed out... I think something only partly broken is still much better than something entirely broken. We can always implement a follow-up, altering our perspective on this PR from "fixes" to a "mitigates". |
|
Alternatively, if you feel comfortable addressing this, please be my guest; I feel like I'm in over my head with your request. |
mcdurdin
left a comment
There was a problem hiding this comment.
So... while the solution implemented by this PR isn't optimal, as you've well pointed out... I think something only partly broken is still much better than something entirely broken. We can always implement a follow-up, altering our perspective on this PR from "fixes" to a "mitigates".
I did some more research online and it seems like this is an open problem with both WKWebView and UIWebView. All sorts of esoteric ideas on how to work around it but no simple onFileDownload approach such as one would hope for.
Given that, let's go ahead with your implementation as it stands.

FixesMitigates #2197.Seems that the root issue was that the
UIWebViewtype is more restrictive in how links are followed. Since it's an in-app WebView, it doesn't want to perform downloads that good ol' Safari's perfectly happy to perform. So... we need to be more proactive and intercept .kmp links.Then... it turns out that with all the nifty, type-aware KMP installation functionality from earlier in 14.0's development... I accidentally made non-type-aware KMP installation significantly trickier. Ah well.