Sending images from an Android keyboard, before Android let you
In 2015 we built a custom emoji keyboard for Android. Keyboards could only type text, so we used share intents, a ContentProvider and the clipboard.
From 2015 · 2 min read · Published August 27, 2026
In mid-2015 our team built an Android emoji keyboard for a TV network: branded stickers and GIFs from the network's shows, organized by show, available from any app's text field. Android's keyboard input system wasn't built for it.
The Android keyboard constraint
A custom Android keyboard is an InputMethodService. It talks to the app you're typing in through an InputConnection, and in 2015 that connection could do one thing: commit text. There was no supported way for a keyboard to insert an image into a chat app. That API (commitContent) didn't arrive until Android 7.1, more than a year later.
So a keyboard full of images had to get them into other apps some other way.
What we did instead
When a user tapped a sticker, the keyboard wrote the image to a file and handed it off with a share intent, typed by MIME type so GIFs stayed animated:
if (object instanceof Bitmap) {
File file = saveToShareableFile((Bitmap) object);
boolean shared = Utils.getSendEmailIntent(this, "", "", "image/png", file);
if (!shared) {
// fall back to something the target app can accept
}
}Around that core, most of the work was making the handoff reliable:
- A custom
ContentProvider, so images could be handed to other apps ascontent://URIs rather than raw file paths those apps might not be allowed to open. - A clipboard path, so the image could be pasted in apps that didn't handle the share intent well.
- Device-specific fixes. One release note in the history reads "adding new emojis and fix for MotoX." Android fragmentation was not theoretical.
- Analytics events on each sticker, because a marketing app that can't report usage doesn't get a second season.
What I learned
The workaround shipped to Google Play, and new show packs kept getting added through the summer. But I came away with a clear rule about platform constraints: when the platform doesn't support what you're doing, every workaround is a feature you now maintain forever, on every OS version and device.
The right time to build a sticker keyboard on Android turned out to be after commitContent existed. We built it before, because the product needed to exist then. That's often the real trade: not "right way versus wrong way," but "ship now with a workaround you'll own, or wait for the platform."
Related: Fastlane for iOS: half my commits were build numbers · Wrapping a native SDK in a React Native native module