Back to Projects
AndroidAPK ModdingKotlin

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:

Packaging

Package rename

com.google.android.inputmethod.latincom.n810.gboard, label "n810 GBoard", so it installs as its own IME.

Launcher icon removed

Setting show_launcher_icon to false only sets the install-time default — Gboard's ojm code re-enables the LauncherActivity component from the preference on every launch, so the drawer icon comes back. Deleting the MAIN/LAUNCHER intent-filter from the manifest removes the entry regardless of runtime state.

Letters page

Wide “return” key

A gated body (0x7f170892 non-split branch → new ios_letters_body / ios_letters_bottom) widens key_pos_ime_action to ~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 nested ExpandedChildLinearLayout hands that width to the URL period when it's present. The "return" text comes from label-capable softkeys in 0x7f170e9e, since the enter's own layout is icon-only. It keeps keycode=ENTER, so it still emits a newline.

Email @ and period placement

Under ios_layout, the INPUT_TYPE_EMAIL_ADDRESS mapping in 0x7f170dc0 moves @ to A06 (right of the spacebar) and the period to A07, 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 flipping return_to_prime_after_apostrophe to true in strings.xml. It was defaulting off because the renamed clone never receives Google's server flags.

URL “/” key removed

Deleted the INPUT_TYPE_URI override in 0x7f170dc0 that forced a / into the comma slot in address bars, ignoring the comma-key setting and resizing the spacebar.

Symbols 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 ?123 page, via a key_pos_switch_to_next_language slot in the symbols bottom row and a gated mapping.

#+= and 123 labels

The symbol switch keys drop their drawable icons for the text labels #+= and 123.

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.

Numeric keyboards

Restore the stock enter icon

The number, PIN, phone-dial, password, and morse keyboards pull enter from the shared 0x7f170e9a0x7f170e9e include and would otherwise render a bare "return" with no key behind it — only the letters and symbols slots draw a pill behind text. A new ios_num_enter.xml redefines those softkeys back to the stock icon, inline-included right after 0x7f170e9a in each of the eight affected keyboards.

Settings

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 like ios_layout and added to the condition array in ehf.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.

Stability and behavior

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_password defaults on in a clone that gets no server flags, and nxp.smali reacts by force-injecting enable_number_row=true onto the keyboard. Inserting const/4 v13, 0x0 right after the flag is read makes the following if-eqz always 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.

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 ?123123 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.