12

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 
Skye
  • 1,469
  • 3
  • 14
  • 25
  • The error message is not about the minSdk, but the targetSdk. Please check whether your targetSdks match throughout your gradle modules. – Ben Weiss Aug 31 '17 at 11:22
  • @keyboardsurfer targetSdk is 26 in each module (I'm using global parameters). – Skye Aug 31 '17 at 11:28
  • implementation project(':base'), implementation project(':item-details') dependencies are missing in your ‘apk’ gradle. – Julia K Aug 31 '17 at 21:13
  • Your ‘apk’ module dependencies contains implementation project(':shared'), do you have one more feature module named ‘shared’? – Julia K Aug 31 '17 at 21:14
  • @JuliaK module 'shared' is just library (with kotlin extensions, models, utils, config files etc), it's included in every feature. – Skye Sep 01 '17 at 07:31
  • @JuliaK So... should I put ':base' module to 'apk' module even if 'ui' module contains ':base'? – Skye Sep 01 '17 at 08:17
  • Sorry, I overlooked that, you don’t need to add ‘implementation project(':base')’ into ‘apk’ module, but you do need to add ‘implementation project(':item-details')’ to your ‘apk’ module. – Julia K Sep 05 '17 at 17:03
  • Similar issue https://stackoverflow.com/questions/44790614/published-an-instant-app-cant-make-it-to-start-how-do-i-troubleshoot - Do you have any extra permissions in your instant app that are not present in installed app? – Julia K Sep 05 '17 at 17:03
  • @JuliaK I removed base module from apk and added item-details to apk. Base permissions: INTERNET, ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE, WAKE_LOCK. item-details permissions: INTERNET, ACCESS_NETWORK_STATE, WAKE_LOCK. Still not working :( – Skye Sep 05 '17 at 20:12
  • By “Base permissions” do you mean the permissions of your installable app? – Julia K Sep 06 '17 at 21:20
  • WAKE_LOCK is not a supported permission for the instant apps. Please refer to FAQ “Which permissions are available to an instant app?” question for details https://developer.android.com/topic/instant-apps/faqs.html#general – Julia K Sep 06 '17 at 21:20
  • @JuliaK Base module permissions :) I removed it, didn't helped :( – Skye Sep 07 '17 at 08:00
  • Can you link to the installable app on Play Store? And, if you're willing to share, links to the manifests in your instant app? Unfortunately, this minimalist error message hides a very complicated set of validations. In general, your instant app needs to support a subset of the devices and URLs supported by your installed app. (So the instant app needs the same or greater device restrictions, and the same or lesser intent filters.) – philo Sep 08 '17 at 19:16
  • @philo app - https://play.google.com/store/apps/details?id=skyesoftware.blogspace manifests: https://gist.github.com/banaszeknorbert/09ac37b7cb046f42d0734c70296fb9fd – Skye Sep 08 '17 at 22:31

5 Answers5

8

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, run aapt with the dump 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 or ACCESS_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 the android.hardware.location.network or android.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.

Volo
  • 28,673
  • 12
  • 97
  • 125
  • 1. Does it matter? both have the same version code and version name. 2. Every time I do so. 3. minSdkVersion and targetSdkVersion are the same. I will try to upload installable apk with higher version code than instant apk. – Skye Sep 07 '17 at 12:50
  • 1. It was a requirement before Instant Apps public release. Looks like it's not anymore, as I can't find it in the developer docs now (anyway, pls let me know if changing the version code makes any difference). – Volo Sep 07 '17 at 20:59
  • @Skye Also can you please ensure that Default entry point url is defined for one (and only one) activity in the base feature, as described [here](https://developer.android.com/topic/instant-apps/prepare.html#default-url), and the same default url is also the part of the [launcher](https://developer.android.com/reference/android/content/Intent.html#CATEGORY_LAUNCHER) activity's intent filter in the 'installed' app. – Volo Sep 07 '17 at 21:00
  • So I should define entry points only in base feature, right? Changing version code's didn't help :( I have the same entry point for my instant app feature and feature that is not part of instant app. – Skye Sep 07 '17 at 21:11
  • 1
    @Skye I was talking about _default entry point url_ which is specified for the _instant_ app in the meta tag with `android:name="default-url"`. Take a look here for the details: https://developer.android.com/topic/instant-apps/prepare.html#default-url. The same url must be also the part of the launcher activitiy intent filter of the _installed_ app – Volo Sep 08 '17 at 13:57
  • @Skye One more question. Do you by any chance use [APK splits](https://developer.android.com/studio/build/configure-apk-splits.html)? – Volo Sep 08 '17 at 14:00
  • Idolon, I will upload new apks with default entry points :) maybe it will help. Nope, I'm not using apk splits. Should I? – Skye Sep 08 '17 at 14:05
  • @Skye Can you please share your resulting `AndroidManifest.xml` from the instant app apk file as shown in the [APK Analyzer](https://developer.android.com/studio/build/apk-analyzer.html)? Maybe something wrong happens during the manifest merge process. – Volo Sep 09 '17 at 10:47
  • @Skye btw, I receive "This app is incompatible with all of your devices" when I open the Google Play website using the browser, and I can't find your app (i.e. it's filtered) from the Play Store app on the phone. Buut… I downloaded the APK file using the APK downloader, installed and run the app successfully on my Pixel phone. Check your Play Console whether you have device restrictions: https://support.google.com/googleplay/android-developer/answer/7353455?hl=en. And just in case, check the country the restrictions as well: https://support.google.com/googleplay/android-developer/table/3541286 – Volo Sep 09 '17 at 11:03
  • Idolon, app isn't available in all coutries. I'm focusing now on Poland until I make instant app (and I don't have language's versions for now :( ). In Google Play Console instant app is available in the same countries as the installable apk. – Skye Sep 09 '17 at 13:01
  • @Skye And there is no device restrictions? – Volo Sep 09 '17 at 13:12
  • @Skye Ok, it seems clear now - your installable app requires the `ACCESS_COARSE_LOCATION` and `ACCESS_FINE_LOCATION` which implicitly adds requirements of the `android.hardware.location`/`android.hardware.location.gps` features: https://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions – Volo Sep 09 '17 at 14:17
  • @Skye I have updated the answer. This should probably fix the issue finally. – Volo Sep 09 '17 at 14:41
  • Ok, only for installable app manifest? For example to apk manifest or maybe to base module manifest? – Skye Sep 09 '17 at 14:46
  • @Skye yes, add it only to the installable app manifest, since your instant app doesn't uses mentioned permissions and doesn't require those implicit features. – Volo Sep 09 '17 at 14:48
  • @Skye Okey… Then try to add it to the instant app as well. If that doesn't help either, then share please the installable APK details as shown in your `Play Console -> Release management -> Artifact library -> (i) icon` – Volo Sep 09 '17 at 17:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154060/discussion-between-idolon-and-skye). – Volo Sep 10 '17 at 09:31
  • @Skye Can you please expand the features part in the APK info and check what are those 2 features there? I guess that one will be `android.hardware.touchscreen` and the second is `android.hardware.screen.portrait`. If yes please add `` to your installable app manifest and check the upload again. – Volo Sep 10 '17 at 09:48
  • Idolon, there is 2 features - android.hardware.FAKETOUCH android.hardware.screen.PORTRAIT. ok :) – Skye Sep 10 '17 at 10:07
  • @Skye I've updated the answer. It looks like adding `` should finally fix your issue. Please let me know, if it works for you. – Volo Sep 10 '17 at 11:55
  • Idolon, thank you so much!!! :) I would never have thought that it could not working because of something like this. I've released an instant app successfully, but I cannot find it in google search :/ is it normal? (Mobile holdback is 0.00, so all trafic is for instant app). I marked your answer as correct :) – Skye Sep 10 '17 at 22:02
  • 1
    Glad you're unblocked! One nit though: rather than disabling the implied features of the installable app, it would be better to require the features in the instant app. That is, since your app uses e.g. ACCESS_FINE_LOCATION, you do indeed need gps. That's already implied in the installable app, but the instant app should require that feature explicitly. Re instant app not showing in Google search results: you mean there is a search result but it's not badged "instant"? It can take some time to index. Let us know if it's still not working after a few days. – philo Sep 11 '17 at 07:10
  • @Skye I'm glad it worked out! As _philo_ said it can take some time for Google to index the instant app. If that doesn't work please post another question here. – Volo Sep 12 '17 at 15:12
2

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" />

AbePralle
  • 942
  • 1
  • 11
  • 13
0

This message makes a perfect sense. Just look at the features required by your installed app(you can use classyshark for that). If it requires phone, because you ask for dialer permissions or you just manually required it, or you ask for GSL version 2 as minimum for your installed versions, then it makes sense that part of the users who doesn't meet those criteria but have android 6+ will not be able to use your installed version but only the instant one.

Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
0

Looking at your installed app's manifest, and your instant app via the gist in your comment above, you do have an issue with your minSdk. Your installed app has minSdk 18, and your instant app doesn't set a minSdk. Set minSdk 18 on instant app base manifest and see if that takes care of it.

Intuitively, this validator is protecting against a scenario that can't happen: a pre-JB user getting your instant app, and being unable to upgrade to the installed app. Because the instant apps runtime itself doesn't go that far back. The validator is indeed dumb. It's just looking at those minSdk values. But that's probably how we want it to be, since that runtime compatibility is moving steadily back to older devices, and that happens without you republishing. (It's extremely unlikely that we'll ever get as far back as sdk 17. Just preemptively justifying why we wouldn't want to make this validator "smarter".)

philo
  • 3,580
  • 3
  • 29
  • 40
  • I declare minSdk 18 in each gradle file, so the declaration in manifest is ignored. I did it also in instant app gradle file (with plugin declaration: com.android.instantapp). – Skye Sep 09 '17 at 08:29
  • Can you share the generated artifact, the zip file? – philo Sep 09 '17 at 11:49
  • 2 manifests from instant apps and gradle files: https://gist.github.com/banaszeknorbert/9a66de51e204fbb6cece6fc74e80936f Link do zip file: https://skyesoftware-my.sharepoint.com/personal/apps_skyesoftware_pl/_layouts/15/guestaccess.aspx?docid=1cf0a15a4d4c246aeb46c1ebb807b0cb6&authkey=ASSaV2SXqf0XLJZQCnl1wkk – Skye Sep 09 '17 at 12:57
0

Simple answer: It happens if you haven't incremented your version number correctly.

Only those with a "lower" version number can upgrade - those with a higher version number can't upgrade.