Google Play Console error - Non-upgradable to installed app
I developed an instant app apk basing on google tutorials and samples. When I'm trying to start rollout to production, I see one error: Non-upgradable to installed app
PROBLEM
Some users of this Instant App APKs will not be eligible for any of the APKs in your installed app.
RESOLUTION
Ensure that the targeting of your Instant App APKs matches the targeting of your APKs.
Project structure: There are two scenarios, 1st:
base - baseFeature, minSdk 18, targetSdk 26
application project(':apk')
feature project(':item-details')
item-details feature - minSdk 18, targetSdk 26
api project(':base')
ui - feature not included in instant module, minSdk 18, targetSdk 26, module contains all views
implementation project(':base')
other modules like customcomponents, shared etc
instant - instant app module minSdk 18 or 23, targetSdk 26
implementation project(':base')
implementation project(':item-details')
apk - apk module, minSdk 18, targetSdk 26
implementation project(':ui')
implementation project(':shared')
Second scenario has item-details code in baseFeature.
Instant app is running from Android Studio and from Google Play development and pre-release. Also when I'm trying to upgrade to installed app, everything works fine. In my opinion, targeting is correct but Google Play Console thinks differently.
Do you know any ideas about how to rollout instant apps? Please help :( I've been working on this release for 3 days and I can not rollout app.
UPDATE 10.09.2017 APK Details:
Supported Android devices 8448 devices
API levels 18+
Target SDK 26
Screen layouts 4 screen layouts
Localizations default + 113 languages
Features 2 features
Required permissions 12 permissions
OpenGL ES versions 1.0+
OpenGL textures all textures
Uploaded Sep 9, 2017, 7:57:11 AM PDT
According to the Android documentation:
You can use the
aapt
tool, included in the Android SDK, to determine how Google Play will filter your application, based on its declared features and permissions. To do so, runaapt
with thedump badging
command. This causes aapt to parse your application's manifest and apply the same rules as used by Google Play to determine the features that your application requires.
By running that command on your installable and instant app apks the following info is printed.
Installable app (version 551):
package: name='skyesoftware.blogspace' versionCode='551' versionName='0.3.1.551' platformBuildVersionName=''
sdkVersion:'18'
targetSdkVersion:'26'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
uses-permission: name='android.permission.ACCESS_WIFI_STATE'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED'
uses-permission: name='android.permission.ACCESS_COARSE_LOCATION'
uses-permission: name='android.permission.ACCESS_FINE_LOCATION'
uses-permission: name='android.permission.WAKE_LOCK'
uses-permission: name='com.google.android.providers.gsf.permission.READ_GSERVICES'
uses-permission: name='com.google.android.c2dm.permission.RECEIVE'
uses-permission: name='skyesoftware.blogspace.permission.C2D_MESSAGE'
…
feature-group: label=''
uses-feature: name='android.hardware.faketouch'
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
uses-feature: name='android.hardware.location'
uses-implied-feature: name='android.hardware.location' reason='requested android.permission.ACCESS_COARSE_LOCATION permission, and requested android.permission.ACCESS_FINE_LOCATION permission'
uses-feature: name='android.hardware.screen.portrait'
uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
uses-feature: name='android.hardware.wifi'
uses-implied-feature: name='android.hardware.wifi' reason='requested android.permission.ACCESS_WIFI_STATE permission'
…
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--' 'af' 'am' 'ar' 'az' 'az-AZ' 'be' 'be-BY' 'bg' 'bn' 'bn-BD' 'bs' 'bs-BA' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-GB' 'en-IN' 'es' 'es-ES' 'es-US' 'et' 'et-EE' 'eu' 'eu-ES' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'gl-ES' 'gu' 'gu-IN' 'hi' 'hr' 'hu' 'hy' 'hy-AM' 'id' 'in' 'is' 'is-IS' 'it' 'iw' 'ja' 'ka' 'ka-GE' 'kk' 'kk-KZ' 'km' 'km-KH' 'kn' 'kn-IN' 'ko' 'ky' 'ky-KG' 'lo' 'lo-LA' 'lt' 'lv' 'mk' 'mk-MK' 'ml' 'ml-IN' 'mn' 'mn-MN' 'mr' 'mr-IN' 'ms' 'ms-MY' 'my' 'my-MM' 'nb' 'ne' 'ne-NP' 'nl' 'pa' 'pa-IN' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'si' 'si-LK' 'sk' 'sl' 'sq' 'sq-AL' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'ta-IN' 'te' 'te-IN' 'th' 'tl' 'tr' 'uk' 'ur' 'ur-PK' 'uz' 'uz-UZ' 'vi' 'zh-CN' 'zh-HK' 'zh-TW' 'zu'
densities: '120' '160' '240' '320' '480' '640' '65534'
Instant App base feature:
package: name='skyesoftware.blogspace' versionCode='1' versionName='1.0.0' platformBuildVersionName=''
sdkVersion:'18'
targetSdkVersion:'26'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
uses-permission: name='android.permission.WAKE_LOCK'
uses-permission: name='com.google.android.c2dm.permission.RECEIVE'
uses-permission: name='skyesoftware.blogspace.permission.C2D_MESSAGE'
application: label='' icon=''
feature-group: label=''
uses-feature: name='android.hardware.faketouch'
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
other-activities
other-receivers
other-services
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--' 'af' 'am' 'ar' 'az' 'az-AZ' 'be' 'be-BY' 'bg' 'bn' 'bn-BD' 'bs' 'bs-BA' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-GB' 'en-IN' 'es' 'es-US' 'et' 'et-EE' 'eu' 'eu-ES' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'gl-ES' 'gu' 'gu-IN' 'hi' 'hr' 'hu' 'hy' 'hy-AM' 'in' 'is' 'is-IS' 'it' 'iw' 'ja' 'ka' 'ka-GE' 'kk' 'kk-KZ' 'km' 'km-KH' 'kn' 'kn-IN' 'ko' 'ky' 'ky-KG' 'lo' 'lo-LA' 'lt' 'lv' 'mk' 'mk-MK' 'ml' 'ml-IN' 'mn' 'mn-MN' 'mr' 'mr-IN' 'ms' 'ms-MY' 'my' 'my-MM' 'nb' 'ne' 'ne-NP' 'nl' 'pa' 'pa-IN' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'si' 'si-LK' 'sk' 'sl' 'sq' 'sq-AL' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'ta-IN' 'te' 'te-IN' 'th' 'tl' 'tr' 'uk' 'ur' 'ur-PK' 'uz' 'uz-UZ' 'vi' 'zh-CN' 'zh-HK' 'zh-TW' 'zu'
densities: '120' '160' '240' '320' '480' '640' '65534'
Instant App feature APK:
package: name='skyesoftware.blogspace' versionCode='1' versionName='1.0.0' split='blogspace_item_details' platformBuildVersionName=''
sdkVersion:'18'
targetSdkVersion:'26'
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
application: label='' icon=''
feature-group: label=''
uses-feature: name='android.hardware.faketouch'
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
other-activities
supports-screens: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '160'
As you can see your installable app requests the ACCESS_COARSE_LOCATION
and ACCESS_FINE_LOCATION
permissions which implicitly add a requirement of the android.hardware.location
feature. In the same way the ACCESS_WIFI_STATE
permission implied the android.hardware.wifi
feature. A user who don't have either GPS or WiFi on their device (that sounds odd but such devices exist in the wild) will not be able to upgrade your instant app to the installable one.
One more thing that limits your installable app availability is the android.hardware.screen.portrait
feature, which was implied because:
one or more activities have specified a portrait orientation
To fix all those issues and make you installable app available to the all users of the instant app, add the following block to the manifest of your installable app (on the level below the <manifest>
tag):
<uses-feature
android:name="android.hardware.location"
android:required="false" />
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
The android.hardware.location.network
and android.hardware.location.gps
features are there to comply with the following requirement:
If your app targets Android 5.0 (API level 21) or higher and uses the
ACCESS_COARSE_LOCATION
orACCESS_FINE_LOCATION
permission in order to receive location updates from the network or a GPS, respectively, you must also explicitly declare that your app uses theandroid.hardware.location.network
orandroid.hardware.location.gps
hardware features.
Btw, the other way to figure out what features are required by the installable app is the APK details info screen on the App releases section of the Google Play Console.
I followed Idolon's advice (running aapt dump badging MyApp.apk
on both apks and comparing) and added several permissions I was missing.
However, I still couldn't get it fully working until I added an OpenGLES feature to match my installed app. In my case:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />