fix(ios): load host page, keyboards through a consistent WKURLSchemeHandler#16136
Conversation
mcdurdin
left a comment
There was a problem hiding this comment.
I like where this is going, some feedback and thoughts on how to tighten it up.
| // Absolute | ||
| if((p.replace(/^(http)s?:.*/,'$1') == 'http') || (p.replace(/^(file):.*/,'$1') == 'file')) { | ||
| return p; | ||
| if(p.indexOf(this.protocol) == 0) { |
There was a problem hiding this comment.
| if(p.indexOf(this.protocol) == 0) { | |
| if(p.startsWith(this.protocol)) { |
But note that http vs https was catered for here previously whereas this change does not allow for that (so http <--> https will no longer work). This is probably not a big deal, but something to be aware of.
There was a problem hiding this comment.
I am actually more worried about this one now: if a user has a local website running http but sources KeymanWeb from https://s.keyman.com, will it break?
There was a problem hiding this comment.
My local testing on Mac is done via http-server, meaning the local test site is based on http. It still uses https://api.keyman.com and https://s.keyman.com with zero issue.
| } | ||
|
|
||
| updateFromOptions(pathSpec: Required<PathOptionSpec>) { | ||
| const _rootPath = this.sourcePath.replace(/(https?:\/\/)([^\/]*)(.*)/,'$1$2/'); |
There was a problem hiding this comment.
Not exactly sure what it's doing, and I didn't need to change it, so I decided to leave this be.
There was a problem hiding this comment.
I wonder if that will cause subtle issues somewhere given this only works with http[s]: and not with keyman-engine:. It might be good to understand why this is needed.
|
|
||
| // Local function to convert relative to absolute URLs | ||
| // with respect to the source path, server root and protocol | ||
| fixPath(p: string) { |
There was a problem hiding this comment.
Could this whole function be replaced with new URL(p, this.sourcePath)?
There was a problem hiding this comment.
I'd want to test that out more thoroughly as its own PR, rather than rolling it in here.
| // +1: include the ':' that likely exists | ||
| pathComponent = String(components.path.dropFirst(KeymanWebViewController.SCHEME.count + 1)) | ||
| } | ||
|
|
There was a problem hiding this comment.
I'm confused about this piece of code. Surely pathComponent should never include keyman-engine:? That would be components.scheme?
Also, I think this would be a good place to collapse repeated slashes, both at start of string and beyond, because repeated slashes when building paths is a common bug and I think we can be resilient to it without real penalty.
That also removes the need to do that work in pathConfiguration.ts.
pathComponent = components.path.replacingOccurrences(of: "/+", with: "/", options: .regularExpression)
if pathComponent.hasPrefix("/") {
pathComponent = pathComponent.dropFirst()
}
Something like that?
There was a problem hiding this comment.
This was an earlier attempt to work around issues in which URLs like the following appeared: keyman-engine:/keyman-engine:/kmwosk.css
It didn't work, which led to resolving things in Web engine code - the changes to pathConfiguration.ts, oskView.ts, and visualKeyboard.ts.
Will clean up now.
That also removes the need to do that work in pathConfiguration.ts.
pathComponent = components.path.replacingOccurrences(of: "/+", with: "/", options: .regularExpression) if pathComponent.hasPrefix("/") { pathComponent = pathComponent.dropFirst() }
... about that. If there are repeated leading slashes, URLComponents will consider the 'path' as the host, not a path! For most of our resources, this then results in a nil path, which is very much something we don't want. Some of the changes seen in pathConfiguration.ts were made b/c they're the easiest workaround... or were at the time.
There was a problem hiding this comment.
... and fortunately, the fixes in OSK code resolved the cases that were causing this, so we can still knock the pathConfiguration.ts double-slash handling out!
|
One more thought; can we base this on #16132 so that we are looking at a consolidated fix for both platforms? |
Work is still ongoing there, and there's been at least one force-push to that branch since the quoted comment was posted. I'd have to re-force-push this branch every time a force-push happens there. |
2e9568e to
b9a3c11
Compare
b9a3c11 to
1f99b2d
Compare
Pretty much just what the title says; it's been silently missing this whole time. This doesn't fix iOS keyboard's display by itself, but it is a prerequisite for the full solution offered by #16136. Build-bot: skip build:ios Test-bot: skip
Pretty much just what the title says; it's been silently missing this whole time. This doesn't fix iOS keyboard's display by itself, but it is a prerequisite for the full solution offered by #16136. Build-bot: skip build:ios Test-bot: skip
1f99b2d to
08c2f25
Compare
…andler This bypasses any need to modify KMW keyboard loading (say, via .fetch), though it does require a number of collateral changes to be made in order for CORS, etc to be satisfied. Build-bot: skip build:ios
Pretty much just what the title says; it's been silently missing this whole time. This doesn't fix iOS keyboard's display by itself, but it is a prerequisite for the full solution offered by #16136. Build-bot: skip build:ios Test-bot: skip
df26dc4 to
13e154f
Compare
08c2f25 to
b3ee271
Compare
Test Results
Note For the TEST_WEB_KBD_DOCS test, the console has the following error |
Test Results
|
Thanks for catching that! Could you retest and verify that these errors no longer occur? @keyman-test-bot retest TEST_WEB_KBD_DOCS |
| browser?: DeviceSpec.Browser | ||
| } = {}; | ||
|
|
||
| // Device emulation for target documentation. | ||
| device.formFactor = formFactor; | ||
| if (formFactor != 'desktop') { | ||
| device.OS = DeviceSpec.OperatingSystem.iOS; | ||
| device.touchable = true; | ||
| device.browser = DeviceSpec.Browser.Safari; | ||
| } else { | ||
| device.OS = DeviceSpec.OperatingSystem.Windows; | ||
| device.touchable = false; | ||
| device.browser = DeviceSpec.Browser.Chrome; |
There was a problem hiding this comment.
Why these changes? device.browser doesn't appear to be used anywhere else in the PR?
There was a problem hiding this comment.
See the changes at lines 1404 - 1408 - they're needed to complete the requirements of the DeviceSpec type needed for the .hostDevice field of getResourcePath's parameter.
Alternatively, we could mock it out with null, but that could become prone to breakage. Or we could rework the getResourcePath method to use just pathConfig.
There was a problem hiding this comment.
OK, makes sense, long term would be good if getResourcePath didn't require device info
Co-authored-by: Marc Durdin <marc@durdin.net>
We don't actually pass JSON through our scheme handler yet, but just in case... we ensure we detect JSON's MIME type and annotate appropriately
|
TEST_WEB_KBD_DOCS (PASSED):
|
|
We need a user test for FirstVoices Keyboards also |
Added. Also made sure it at least works on my local build. |
|
I can't seem to find the build for FirstVoices. Please help check |
The iOS build is currently disabled due to updates that the FirstVoices team need to make on App Store Connect. Given @jahorton verified that a local build works, we'll move forward with that for now. TEST_FIRSTVOICES PASS |
|
Changes in this pull request will be available for download in Keyman version 19.0.250-alpha |
|
Fixes iOS part of #16096 |

These changes bypass any need to modify KMW keyboard loading (say, via .fetch), instead forcing all engine files and resources to load via the new scheme/protocol in order to accomplish its goal.
Alternate approaches considered:
file://protocol calls to ping Swift for a file load, then pass the results back via JS call that resolves the associated fetch Promise.Build-bot: skip release:ios,web
User Testing
TEST_IOS:
TEST_IOS_CAMEROON:
sil_cameroon_azertykeyboardsil_euro_latin.TEST_FIRSTVOICES:
TEST_WEB:
TEST_WEB_KBD_DOCS: