n810 GBoardAn iOS keyboard layout for Gboard
A re-signed build of Gboard that adds a full iOS keyboard layout behind a runtime toggle. It's produced by decompiling the stock APK with apktool, editing the resource XML and smali, and rebuilding under a new package name so it installs as a second keyboard beside the untouched Play Store Gboard. Most of the work was working out how Gboard's layout system resolves — obfuscated file names, no source — and forcing behavior back on that a renamed, re-signed clone otherwise loses.
Base
Gboard 17.7.5
arm64-v8a, nodpi standalone APK
Package
com.n810.gboard
Second IME, stock left intact
Device
OnePlus 15
Android 16
Change set
40 files
28 edited, 12 new vs stock
What it is
A toggle in Preferences switches Gboard's layout to match an iPhone: reordered
iOS symbol pages, a wide "return" key with a text label instead of the arrow
icon, the email @ moved to the right of the spacebar, and #+= / 123 text
labels on the symbol switch keys. Two sub-conditions ride with it —
ios_square_keys (plain square keys instead of accent pills) and
ios_show_question (drop the ? from the 123 key).
It runs under its own package, so it sits alongside the stock Gboard rather than replacing it. The Play Store copy stays signed by Google and works as a fallback.
Why it's a separate app
On the OnePlus 15, Gboard ships as a firmware system app. Android won't let an
APK signed with a different key update a system package, so overwriting the stock
copy is impossible without the platform key. The mod renames the package instead
— com.google.android.inputmethod.latin becomes com.n810.gboard — so Android
registers it as a distinct app rather than a conflicting signature for one it
already trusts. Install beside, don't replace: that's what makes it safe to run
as a daily driver.
What changed
40 files against the stock APK, verified by diffing a fresh decompile. Grouped by area:
- Package rename
com.google.android.inputmethod.latin→com.n810.gboard, label "n810 GBoard", so it installs as its own IME.- Launcher icon removed
Setting
show_launcher_iconto false only sets the install-time default — Gboard'sojmcode re-enables theLauncherActivitycomponent from the preference on every launch, so the drawer icon comes back. Deleting theMAIN/LAUNCHERintent-filterfrom the manifest removes the entry regardless of runtime state.
Packaging
- Wide “return” key
A gated body (
0x7f170892non-split branch → newios_letters_body/ios_letters_bottom) widenskey_pos_ime_actionto ~2 keys without touching the bottom row shared by ~97 layouts. In URL fields it shrinks to ~1.5 keys and shows the stock arrow: a nestedExpandedChildLinearLayouthands that width to the URL period when it's present. The "return" text comes from label-capable softkeys in0x7f170e9e, since the enter's own layout is icon-only. It keepskeycode=ENTER, so it still emits a newline.- Email @ and period placement
Under
ios_layout, theINPUT_TYPE_EMAIL_ADDRESSmapping in0x7f170dc0moves@toA06(right of the spacebar) and the period toA07, outside the enter group, so email keeps a full-width "return." Email "To" fields use the Next IME action, so Next/Previous/Done are relabeled "return" there too; Go/Search/Send keep their own labels, as on iOS.- Apostrophe auto-switch restored
Typing
’on the symbols page jumps back to letters again, by flippingreturn_to_prime_after_apostropheto true instrings.xml. It was defaulting off because the renamed clone never receives Google's server flags.- URL “/” key removed
Deleted the
INPUT_TYPE_URIoverride in0x7f170dc0that forced a/into the comma slot in address bars, ignoring the comma-key setting and resizing the spacebar.
Letters page
- iOS symbol order and 5-key row
Reordered the symbols and reflowed the top row to match iOS (
0x7f170e0f/0x7f170e0d).- Emoji key kept on the symbols page
The emoji/globe key stays on the
?123page, via akey_pos_switch_to_next_languageslot in the symbols bottom row and a gated mapping.- #+= and 123 labels
The symbol switch keys drop their drawable icons for the text labels
#+=and123.- Numpad switch removed
Deleted the "Digit keyboard" switch softkey, set the empty slot's weight to 0, and gave the width to the spacebar so no gap is left.
Symbols page
- Restore the stock enter icon
The number, PIN, phone-dial, password, and morse keyboards pull enter from the shared
0x7f170e9a→0x7f170e9einclude and would otherwise render a bare "return" with no key behind it — only the letters and symbols slots draw a pill behind text. A newios_num_enter.xmlredefines those softkeys back to the stock icon, inline-included right after0x7f170e9ain each of the eight affected keyboards.
Numeric keyboards
- Dedicated iOS Layout sub-page
The single "Use iOS Layout" switch became a sub-page under Preferences holding the master toggle plus "Show ? on the 123 key" and "Square keys." The two sub-options are real keyboard conditions (
ios_show_question,ios_square_keys), registered likeios_layoutand added to the condition array inehf.smali(14 → 16).- Lift the keyboard off the bottom edge
A three-stop slider on the same page — off, half a key, a full key — raises the whole keyboard, leaving a transparent gap below it. It reuses one of Gboard's own slider preference widgets rather than adding a new one, and pads the input view's root in
InputView.onMeasure. The gap is sized from the measured body height, so "a key" means an actual key row at whatever height the keyboard is currently drawn.
Settings
- Signature-check bypass
A re-signed Gboard periodically crashes on its own anti-tamper check — patched in
qvi.smali. Details below; this is what makes the mod usable long-term rather than for a few days.- Password-field number row removed
The password keyboard puts a number row above the letters even with the global "Number row" setting off. It isn't a layout choice:
enable_number_row_in_passworddefaults on in a clone that gets no server flags, andnxp.smalireacts by force-injectingenable_number_row=trueonto the keyboard. Insertingconst/4 v13, 0x0right after the flag is read makes the followingif-eqzalways skip that injection. The global number-row path is untouched. An earlier attempt at the XML conditions did nothing and was reverted — the row is forced in code, not markup.
Stability and behavior
What I learned
Most of the time went into how Gboard resolves its layout and defends its own build, not into writing the edits. The parts worth keeping:
Server flags never reach a renamed clone
A lot of Gboard's behavior is gated on flags Google pushes from the server. The
renamed package doesn't receive them, so those flags fall to their compiled-in
defaults — which is why the apostrophe auto-switch silently stopped working.
Restoring it meant setting the flag by hand in strings.xml. If a stock feature
disappears after renaming, suspect a flag before a bug.
Layout resolves by include order, and the last one wins
Keys are defined in one file and redefined by later includes. Editing the obvious
definition did nothing because a file included further down overrode it. The
?123 → 123 toggle only took effect once the switch-key softkey (0x7f0b249a)
was redefined inside the seam that's included last in the iOS layout. A
redefinition also has to sit in the same view to win — a softkey redefined from
a separate view doesn't take, which is why the numeric-keyboard fix is
inline-included rather than referenced.
A disabled component isn't gone
Setting LauncherActivity to disabled by default doesn't hold: runtime code
re-enables the component from a stored preference on launch, so the app-drawer
icon reappears after a clean install. The durable fix is structural — remove the
MAIN/LAUNCHER intent-filter so there's no launcher entry for any enabled
state to point at.
The pill is a style tag, not a background
The rounded accent pill on the return / 123 keys looked like a drawable to swap.
It was a style tag. Plain square keys came from pointing those keys at the
tagless parent style (0x7f1506eb) in <if ios_square_keys> bottom rows — no
colour or drawable change involved.
One shared row feeds almost every layout
The bottom row is shared by ~97 layouts. Widening it in place for the iOS return key would have deformed all of them. The fix was to gate a separate iOS body that swaps in its own bottom row and leave the shared one alone. When a change looks global, the move is usually a gated copy, not an edit in place.
Some keys have no text slot
The enter key's own layout is icon-only — there's nowhere to put the word "return." The label only rendered after gating the key onto a layout that actually has a text slot. You can't label a key with no room for a label.
Gboard verifies its own signature and crashes if it's wrong
After a few days the keyboard started dying at random with
IllegalStateException: APK is signed by unrecognized certificates. Gboard
re-checks its own signing certificate on a schedule, not just at launch: qvi.a
compares the running cert against three hardcoded Google certificates and a
background thread throws when none match. Any re-signed build fails it. The fix
is to force qvi.a to return true with an early return, leaving the original
body as dead code. Patching the shared validator — rather than the single
if-nez branch in the mg caller — keeps both of its callers consistent, and
blanket-accept is the right call over whitelisting a cert hash, because anyone
applying the patch re-signs with their own key. It disables the check rather than
satisfying it, which is the only option without Google's private key.
How it's built and shared
Decompile the stock APK with apktool, edit the resource and smali files, then
apktool b, zipalign, and apksigner with a throwaway key. The decompiled
tree is the source of truth for edits; the signed APK is the output.
It ships as a patch, not a pre-built APK — the ReVanced model: everyone applies the changes to their own Gboard download, which is cleaner legally and smaller to distribute. Two forms:
- Shell patch — a script plus an overlay of the 40 changed files. It decompiles a stock Gboard, applies the overlay, rebuilds, aligns, and signs. Tested end to end from a stock APK to a valid signed build.
- ReVanced patch — the same mod ported to a ReVanced patches project (Kotlin) and built into a
.rvp. An earlier build was decompiled and diffed against the proven tree: byte-identical apart from harmless attribute reordering. It currently predates the return-key refinements, numeric-keyboard enter, signature-check bypass, launcher-icon removal, password number row, and bottom-gap slider, so it needs re-syncing from the current overlay before it matches the shell patch.
Locked to one Gboard version
The mod replaces obfuscated APKTOOL_RENAMED_0x… files by name and pins specific
resource ids, so it's tied to Gboard 17.7.5.932364120. A Gboard update shifts
those names and breaks the overlay. Only the string-fingerprinted bytecode
patches have a real chance of surviving an update; the resource edits need
re-mapping each time.