apache / cordova-android

Apache Cordova Android
https://cordova.apache.org/
Apache License 2.0
3.67k stars 1.54k forks source link

[+use case: auto-reset of permissions] Overriding compileSDK version has been removed #1373

Closed shankari closed 2 years ago

shankari commented 3 years ago

Bug Report

Problem

Overriding compileSDK version has been removed in cordova-android@10.x https://github.com/apache/cordova-android/issues/1310#issuecomment-892802205

I see that this was an intentional change, but @breautek said that

The stance that we took is "We'll make the change, release it, and if it becomes a problem, then we'll bring back the independent settings". So I'd like to understand your use case better.

Here's the use case. I wasn't sure if this was a bug since the change was intentional, but it is arguably a regression, and is inconsistent with the documentation, so I went ahead and chose "bug" instead of "feature request".

What is expected to happen?

I can include

+    <framework src="androidx.core:core:$ANDROIDX_CORE_VERSION"/>
+    <preference name="ANDROIDX_CORE_VERSION" default="1.7.0"/>

in my plugin

What does actually happen?

When I add that plugin and compile the app, I get the error

Execution failed for task ':app:checkDebugAarMetadata'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
   > The minCompileSdk (31) specified in a
     dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
     is greater than this module's compileSdkVersion (android-30).
     Dependency: androidx.core:core:1.7.0.
     AAR metadata file: /Users/kshankar/.gradle/caches/transforms-3/553b5caab8c99faefbf90799c7dc70a3/transformed/core-1.7.0/META-INF/com/android/build/gradle/aar-metadata.properties.

Information

Starting in December, android will start resetting permissions of apps that have not been brought into the foreground "for a while". This will happen irrespective of the phone's android version (https://developer.android.com/topic/performance/app-hibernation).

It only applies to apps whose target SDK is Android 11+ (API 30+), but the google play min API requirements are 30+ now for new apps and will be 30+ for app updates in November (https://developer.android.com/distribute/best-practices/develop/target-sdk)

If such a new or updated app reads location in the background, even if it is installed on an Oreo phone, it will stop working "soon after" December. https://developer.android.com/topic/performance/app-hibernation#effects

If the app use case requires background location access, it can ask users to explicitly authorize such access. The recommended authorization method involves using new functionality in PackageManagerCompat and IntentCompat (https://developer.android.com/topic/performance/app-hibernation#handle-hibernation-android10-lower).

This new functionality is introduced in version 1.7.0 of the androidx core libraries https://developer.android.com/jetpack/androidx/releases/core#1.7.0

However, it looks like v1.7.0 of the core libraries have a minCompileSdk of 31. The default cordova SDK_VERSION is 30. https://github.com/apache/cordova-android/blob/5db850890d5c94f5fc3c0b90a02bfb0b251c0da1/framework/cdv-gradle-config-defaults.json#L3

So, when I compile my app after upgrading the androidx dependency in my plugin, I get

Execution failed for task ':app:checkDebugAarMetadata'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
   > The minCompileSdk (31) specified in a
     dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
     is greater than this module's compileSdkVersion (android-30).
     Dependency: androidx.core:core:1.7.0.
     AAR metadata file: /Users/kshankar/.gradle/caches/transforms-3/553b5caab8c99faefbf90799c7dc70a3/transformed/core-1.7.0/META-INF/com/android/build/gradle/aar-metadata.properties.

Command or Code

  1. To any plugin.xml add
+    <framework src="androidx.core:core:$ANDROIDX_CORE_VERSION"/>
+    <preference name="ANDROIDX_CORE_VERSION" default="1.7.0"/>
  1. add the plugin to a cordova app
  2. cordova build android

I could not find a way to override the compileSDK version. Per the cordova documentation, using cdvCompileSdkVersion should work, but it doesn't seem to.

$ npx cordova run android -- --gradleArg=-PcdvCompileSdkVersion=31
...
* What went wrong:
Execution failed for task ':app:checkDebugAarMetadata'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
   > The minCompileSdk (31) specified in a
     dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
     is greater than this module's compileSdkVersion (android-30).
     Dependency: androidx.core:core:1.7.0.
     AAR metadata file: /Users/kshankar/.gradle/caches/transforms-3/553b5caab8c99faefbf90799c7dc70a3/transformed/core-1.7.0/META-INF/com/android/build/gradle/aar-metadata.properties.
...
BUILD FAILED in 790ms

I'm going to try and workaround this by mucking around with gradle files, but as the documentation says "In general, it is discouraged that you edit the contents of this folder because it is easy for those changes to be lost or overwritten."

Environment, Platform, Device

Version information

Output of cordova info ``` Cordova Packages: cli: 10.0.0 common: 4.0.2 create: 3.0.0 lib: 10.1.0 common: 4.0.2 fetch: 3.0.1 serve: 4.0.0 Project Installed Platforms: android: 10.1.0 ios: 6.2.0 Project Installed Plugins: @havesource/cordova-plugin-push: 2.0.0 cordova-plugin-advanced-http: 3.2.2 cordova-plugin-androidx-adapter: 1.1.3 cordova-plugin-app-version: 0.1.12 cordova-plugin-badge: 0.8.8 cordova-plugin-customurlscheme: 5.0.2 cordova-plugin-device: 2.0.3 cordova-plugin-em-datacollection: 1.6.0 cordova-plugin-em-jwt-auth: 1.6.4 cordova-plugin-em-server-communication: 1.2.3 cordova-plugin-em-serversync: 1.2.5 cordova-plugin-em-settings: 1.2.2 cordova-plugin-em-transition-notify: 1.2.6 cordova-plugin-em-unifiedlogger: 1.3.3 cordova-plugin-em-usercache: 1.1.3 cordova-plugin-email-composer: 0.9.2 cordova-plugin-file: 6.0.2 cordova-plugin-inappbrowser: 5.0.0 cordova-plugin-ionic-keyboard: 2.2.0 cordova-plugin-ionic-webview: 5.0.0 cordova-plugin-ionic: 5.5.1 cordova-plugin-local-notification: 0.9.0-beta.3 cordova-plugin-x-socialsharing: 6.0.3 es6-promise-plugin: 4.2.2 phonegap-plugin-barcodescanner: 8.1.0 Environment: OS: macOS 11.6 (20G165) (darwin 20.6.0) x64 Node: v14.18.1 npm: 6.14.15 android Environment: android: ERROR: Command failed with ENOENT: android list target spawn android ENOENT ios Environment: xcodebuild: Xcode 13.1 Build version 13A1030d Project Setting Files: config.xml: emission A commute pattern tracker and carbon footprint estimator. E-Mission Team package.json: --- Start of Cordova JSON Snippet --- { "platforms": [ "android", "ios" ], "plugins": { "@havesource/cordova-plugin-push": { "ANDROID_SUPPORT_V13_VERSION": "28.0.0", "FCM_VERSION": "18.+", "IOS_FIREBASE_MESSAGING_VERSION": "~> 6.32.2" }, "cordova-plugin-ionic-keyboard": {}, "cordova-plugin-app-version": {}, "cordova-plugin-file": {}, "cordova-plugin-device": {}, "cordova-plugin-customurlscheme": { "URL_SCHEME": "emission", "ANDROID_SCHEME": " ", "ANDROID_HOST": " ", "ANDROID_PATHPREFIX": "/" }, "cordova-plugin-email-composer": { "ANDROID_SUPPORT_V4_VERSION": "27.+" }, "cordova-plugin-x-socialsharing": { "PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION": "This app requires photo library access to share photos on social media.", "PHOTO_LIBRARY_USAGE_DESCRIPTION": "This app requires photo library access to share photos on social media." }, "cordova-plugin-inappbrowser": {}, "cordova-plugin-local-notification": {}, "cordova-plugin-ionic": { "APP_ID": "e0d8cdec", "CHANNEL_NAME": "Production", "UPDATE_METHOD": "none", "UPDATE_API": "https://api.ionicjs.com", "MAX_STORE": "2" }, "cordova-plugin-advanced-http": {}, "cordova-plugin-ionic-webview": { "ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+" }, "cordova-plugin-em-jwt-auth": { "AUTH_VERSION": "19.2.0" }, "cordova-plugin-em-server-communication": {}, "cordova-plugin-em-serversync": {}, "cordova-plugin-em-settings": {}, "cordova-plugin-em-transition-notify": {}, "cordova-plugin-em-unifiedlogger": {}, "cordova-plugin-em-usercache": {}, "cordova-plugin-androidx-adapter": {}, "phonegap-plugin-barcodescanner": {}, "cordova-plugin-em-datacollection": { "LOCATION_VERSION": "18.0.0", "ANDROIDX_CORE_VERSION": "1.7.0" } } } --- End of Cordova JSON Snippet --- ```

Checklist

shankari commented 3 years ago

I can confirm that removing those lines from the plugin and then readding it made the build successful.

$ npx cordova build android
BUILD SUCCESSFUL in 9s
shankari commented 3 years ago

tried to hack around this by changing platforms/android/app/build.gradle to

        compileSdkVersion 31

Causes the error

> Task :app:compileDebugJavaWithJavac FAILED
An exception has occurred in the compiler (1.8.0_252). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError: annotationType(): unrecognized Attribute name MODULE (class com.sun.tools.javac.util.UnsharedNameTable$NameImpl)
breautek commented 3 years ago

Setting android-targetSdkVersion preference will set both the target and compile sdk version.

Using API 31 tooling has known issues and requires some breaking changes. So API 31 is not something cordova currently supports.

shankari commented 3 years ago

I understand that setting the targetSDKVersion preference will set both target and compile SDKs. However, I don't want to bump up to target SDK 31 prematurely. Google doesn't require it, and it has significant breaking changes for my app.

Notably:

I just want to compile against API 31 so I can use the new version of the androidx library, but still target API 30

shankari commented 3 years ago

For the record, I also looked into re-implementing the Compat implementations instead of using the androidx library, but they seem non-trivial. In particular: https://developer.android.com/reference/androidx/core/content/IntentCompat#createManageUnusedAppRestrictionsIntent(android.content.Context,%20java.lang.String)

SDK 23 through 29, this method will generate an intent with action Intent.ACTION_AUTO_REVOKE_PERMISSIONS and the package as the app with the Verifier role that can resolve the intent.

I'm not sure what that app is in all of the older versions.

shankari commented 3 years ago

Upgrading to Java 11 fixes the error above. I can now compile and run.

$ echo $JAVA_HOME
/Applications/Android_Studio.app/Contents/jre/Contents/Home

$ $JAVA_HOME/bin/java --version
openjdk 11.0.10 2021-01-19
OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
OpenJDK 64-Bit Server VM (build 11.0.10+0-b96-7281165, mixed mode)

$ npx cordova build android
> Configure project :app
Adding classpath: com.google.gms:google-services:4.3.3
WARNING:: Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.
It will be removed in version 7.0 of the Android Gradle plugin.
For more information, see http://d.android.com/r/tools/update-dependency-configurations.html.
WARNING:: Using flatDir should be avoided because it doesn't support any meta-data formats.

> Task :CordovaLib:compileDebugJavaWithJavac
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

> Task :app:compileDebugJavaWithJavac
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

BUILD SUCCESSFUL in 22s
49 actionable tasks: 8 executed, 41 up-to-date
Built the following apk(s):
    .../native_code_upgrade/platforms/android/app/build/outputs/apk/debug/app-debug.apk
shankari commented 3 years ago

cordova android team, as you can see, I have fixed this for my individual plugin by introducing a custom gradle file.

But given that @breautek said:

The stance that we took is "We'll make the change, release it, and if it becomes a problem, then we'll bring back the independent settings".

and

Isn't these libraries independent of the compile SDK? Looking at the android docs at a variety of different androidx packages, I don't ever recall (nor can I find anything that states you need a specific compileSdk) to use them.

I hope that this concrete use case of an androidx package that requires a specific compileSdk helps you revisit your original decision.

I'd even be open to making the change myself and submitting a PR if this is consistent with the long-term vision of the maintainers.

I am not familiar with the innards of the cordova codebase, but I think I found the PR with a similar change (e.g. https://github.com/apache/cordova-android/pull/1212) so it doesn't sound too terrible (famous last words?!)

breautek commented 2 years ago

We are looking to re-introduce the independent setting. The details will be in the PR at https://github.com/apache/cordova-android/pull/1431 (currently WIP, but pretty stable).

It may work slightly different than the setting that was in cordova-android 9.x.

Namely we are looking to default the compile SDK to whatever what the target SDK is, unless explicitly configured otherwise.

In otherwords:

In all cases where cordova accepts a user-defined value, cordova will accept is as is, including if the configured values produces invalid settings, such as a target sdk > compile sdk.

Feedback is welcome on the PR https://github.com/apache/cordova-android/pull/1431.