So there isn’t an Android Smart App Banner like the one for iOS but there is the Native App Install Prompt, which is about as much as we get natively on Android. Sorry for the bait-and-switch, there…
It looks like this.
Tapping the banner brings up a dialog like this.
Tapping install in that dialog takes you to the Play Store.
So, How Do You Implement It?
Unfortunately, the documentation for the prompt isn’t very good. It skips over important information and talks about a very similar prompt for PWAs without ever clarifying which bits matter to what prompts.
To get this banner working for Native Android Apps all you have to do is add a manifest file with the following properties:
short_name
: The name of your app/brand/company/whatever. It’s shown on the initial banner.name
: A longer form name for your app/brand/company/whatever. It’s shown on the dialog.icons
: An array of objects describing the icons to show on the banner and dialog."prefer_related_applications": true
. If this key is missing or not set totrue
, the banner won’t show up.related_applications
: A list of objects that describe the app to get the user to install. To get the banner to show up on Android, the list must contain an object with a key calledplatform
set toplay
and a key calledid
, which is set to the ID of the app in the Play Store.
You then have to ensure that the manifest is declared in your HTML.
<link rel="manifest" href="/manifest.json" />
That’s it, the prompt will now show up. You don’t need to listen for events or show buttons or anything. I repeat:
All you need to do to get the banner to show up is to add a manifest file with the required properties.
Example
{
"short_name": "Cool App",
"name": "Cool App - You're going to love it",
"icons": [
{
"src": "/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"prefer_related_applications": true,
"related_applications": [
{
"platform": "play",
"id": "com.example.cool_app"
}
]
}
I Don’t See the Prompt
Unfortunately, even if you do this, the prompt still will not likely show up. As noted in the documentation, there are several other factors that Chrome uses before it will trigger the prompt. This includes:
- The user needs to not have the app already installed (obviously…otherwise you’d just add a static banner in your HTML, right?)
- The page must be served over HTTPS (I hope your production traffic is already doing this)
- The user needs to be on a mobile device. I haven’t seen this listed anywhere, but I’ve only ever gotten it to trigger using mobile Chrome. It feels kind of obvious when you think about it.
- The user needs to meet some kind of interaction requirement. This is pretty vague and basically means the prompt won’t show up the first time (probably not the second or third time either) the user visits your site. They will only see it if they are interacting with the domain quite often.
These requirements can make testing whether you’ve set up your manifest correctly quite difficult. Fortunately, there are a couple of Chrome flags you can use to make things easier.
Bypass User Engagement Checks
If you enable #bypass-app-banner-engagement-checks, then the banner will show up on the first (and every) visit to your site, as long as the other criteria are met.
Insecure Origins Treated As Secure
Since you need to be on a mobile device, it might be hard to visit your site running in local development mode without paying for a service like ngrok. On Mac OS, at least, you can visit your site running locally from a mobile device on the same WiFi network by simply visiting the IP for your Mac (found in the wifi settings panel). You can then tell Chrome to treat that IP address as secure by adding it to the #unsafely-treat-insecure-origin-as-secure flag.
Advanced Usage
You don’t have to serve your manifest file as a static file. If you want to make use of asset helpers or translations, you can back your manifest file with an endpoint. This example is ruby based, but the same approach works wherever.
<link rel="manifest" href="/webapp_manifest" />
# routes.rb
resource :webapp_manifest, only: :show
# app/controllers/webapp_manifests_controller.rb
class WebappManifestsController
def show
render json: {
name: I18n.t("long_app_name"),
short_name: I18n.t("short_app_name"),
prefer_related_applications: true,
related_applications: {
id: AppIds::PLAY_STORE_APP_ID,
platform: "play"
},
icons: [
{
src: asset_url("app_store_icon_512")
type: "image/png",
sizes: "512x512"
},
{
src: asset_url("app_store_icon_192")
type: "image/png",
sizes: "192x192"
},
]
}
end
end
Conclusion
I hope you find this post useful and less confusing than the official documentation.
I’ve now implemented this for three different sites for three different companies over the last 5 years and each time I wished for a post like this.
So, this time, I wrote it down. This has mainly been for me more than anything 😉