fix(android): load KMP files from app-external sources - #16392
Conversation
This PR provides two main services: - It allows on-device KMP file providers (such as Chrome downloads or the local Files app) to smoothly pass those KMP files into Keyman for Android for installation. - It also removes wildcard-host http / https deep-links from the app manifest, as these are invalid. Fixes: #14854 Fixes: #10133 Upon my investigation into related documentation, I've determined that with current versions of Android, setting up a general, "anywhere on the web" deep link for KMP files is not supported and should not be attempted. How, then, do we facilitate external apps passing off KMP links or files to Keyman for Android? Turns out... we've already done the work for downloaded files with `file:` and `content:` scheme deep-links. The issue is that some of our permissions-checking code logic was bad. With a little work to correct them - removing the bad checks that never should have existed anyway - the files load nicely! Build-bot: skip release:android
User Test ResultsTest specification and instructions
Results TemplateTest Artifacts |
|
I tested downloading a file from Chrome on my Samsung Galaxy A553 5G on Android 16 (One UI 8.0), Chrome version 151.0.7922.137 (11 Aug 2026). It worked fine -- Keyman appeared on the list of available apps to open the .kmp file, and no errors were encountered. Samsung Files continues to fail with the error as shown above. 'Files by Google' works fine -- so suggest we recommend that as an alternative file manager on Samsung devices. See also: #10967 (comment) |
|
I think we should have a user test for:
We should at some point also test, once we have a stable release build:
|
…ent-filters Fixes: #14122
Would the test be for it to download, then install from download? Or would it be to instantly load into the Keyman app package-install process? |
I think this -- we want to verify that existing package install pathways have not been impacted (not that I think they have -- but for the avoidance of unpleasant surprises...) |
They were, but by other changes - we internationalized keyman.com, which prefixes the language code onto all paths. I'm working on this now. |
Can you open an issue as a first step? |
mcdurdin
left a comment
There was a problem hiding this comment.
The AndroidManifest.xml still seems a bit chaotic. It would be good to review each intent-filter and ensure that the comments make sense, and group them appropriately.
| // No special permissions are needed. | ||
| // - https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE | ||
| // - https://stackoverflow.com/a/73630987 | ||
| } |
There was a problem hiding this comment.
Let's just delete the empty else statement. We can have a note in the commit history for the change.
| <data | ||
| android:mimeType="application/vnd.keyman" | ||
| android:scheme="content" /> |
There was a problem hiding this comment.
This is not a registered mime type.
| <data | |
| android:mimeType="application/vnd.keyman" | |
| android:scheme="content" /> |
| <data | ||
| android:mimeType="application/vnd.keyman.kmp+zip" | ||
| android:scheme="content" /> |
There was a problem hiding this comment.
Repeated
| <data | |
| android:mimeType="application/vnd.keyman.kmp+zip" | |
| android:scheme="content" /> |
| <data | ||
| android:host="keyman-staging.com" | ||
| android:scheme="http" | ||
| android:pathPrefix="/keyboards/install" /> |
There was a problem hiding this comment.
Is the staging server usually https: when live? If so, yeah, I should update that.
I inferred the http:// because of existing entries like this one:
keyman/android/KMAPro/kMAPro/src/main/AndroidManifest.xml
Lines 195 to 198 in 82d5580
Because of how AndroidManifest.xml works, if there was a separate https: host set within the same <intent-filter>, it would also check against AndroidManifest.xml. That's relying on quirky, unintuitive behaviors; I think we'd prefer to be explicit here.
There was a problem hiding this comment.
Is the staging server usually https: when live? If so, yeah, I should update that.
Always https:, yes. And generally always live.
| </intent-filter> | ||
|
|
||
| <intent-filter android:priority="50"> | ||
| <intent-filter android:priority="50" android:autoVerify="true"> |
There was a problem hiding this comment.
https://developer.android.com/training/app-links/verify-applinks
We probably don't need to implement this because we have another <intent-filter> entry that does verify the same domains... but that's a happy accident and shouldn't be what we rely upon.
There was a problem hiding this comment.
Hmm, please make sure you call out changes like this in the PR description because it's definitely not related to the core purpose of the PR, and it is a significant change!
There was a problem hiding this comment.
Actually, can you please split this into a separate PR for test and review? There's a fair bit of detail there that we should be careful about changing and testing.
| <category android:name="android.intent.category.DEFAULT" /> | ||
|
|
||
| <data android:scheme="file" /> | ||
| <data android:scheme="content" /> |
There was a problem hiding this comment.
Matches both file:/// and content:// URIs. Often times, what we get between apps appears to be the content:// one.
It's an OR, not an AND - allowing us to share the host and pathPattern entries for both protocols.
There was a problem hiding this comment.
I am not sure what this is fixing though -- does this impact the underlying reported issue?
Test ResultsGROUP_API_28:Test Specs
GROUP_API_30:Test Specs
GROUP_API_33:Test Specs
|
|
Hello, @jahorton. Could you help confirm the steps for the TEST_INSTALL_VIA_FILES are the same as TEST_DOWNLOAD_AND_INSTALL? |
Sorry about that. I've updated the instructions for that test now. |

This PR provides two main services:
Relates-to: #14854
Upon my investigation into related documentation, I've determined that with current versions of Android, setting up a general, "anywhere on the web" deep link for KMP files is not supported and should not be attempted.
How, then, do we facilitate external apps passing off KMP links or files to Keyman for Android? Turns out... we've already done the work for downloaded files with
file:andcontent:scheme deep-links. The issue is that some of our permissions-checking code logic was bad. With a little work to correct them - removing the bad checks that never should have existed anyway - the files load nicely!Build-bot: skip release:android
Notes: upon reviewing #10133 and #14122, it sounds like there may be variance among devices. Samsung is likely to be trickier to handle, while Google devices using plain Chrome may be more straightforward. I may need to alter the user tests accordingly.
User Testing
GROUP_API_28: Perform these tests on devices with Android API 28 (Android 9).
GROUP_API_30: Perform these tests on devices with Android API 30 (Android 11).
GROUP_API_33: Perform these tests on devices with Android API 33+ (Android 13).
TEST_DOWNLOAD_AND_INSTALL: Using Keyman for Android, download a KMP from within the Chrome app, then install it from Chrome's download section.
TEST_INSTALL_VIA_FILES: Using Keyman for Android, download a KMP from within the Chrome app, then install it from the device's Files app.