NativeScript icon indicating copy to clipboard operation
NativeScript copied to clipboard

Android 12 support

Open sebj54 opened this issue 4 years ago • 53 comments

Is your feature request related to a problem? Please describe.

Hi NativeScript maintainers :)

I'm currently trying to target and compile my NativeScript with Android 12 (SDK Platform 31).

Describe the solution you'd like

The ideal would be to have this out of the box, but I thinked it was possible by changing only a few configurations (I was wrong).

Describe alternatives you've considered

Here is what I did so far:

Install latest SDK and build tools

sdkmanager --install "platforms;android-31" "build-tools;31.0.0"

I also removed previous versions for platforms and build-tools.

Change target and compile SDK versions in app.gradle:

project.compileSdk = 31
project.targetSdk = 31

android {
  // no change in this object
}

Here is the error I get when trying to compile:

Could not determine the dependencies of task ':app:compileDebugJavaWithJavac'.
Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.

I found this related issue: #9639. @rigor789 suggested to uninstall build-tools and reinstall them with version 30. If I do that, I'm still not able to compile. The error is now:

Unable to apply changes on device: 0xxxxxxxxxx4. Error is: The parser encountered some structural problem in the manifest..

I think it's because build-tools 31 are mandatory to compile with platform 31.

I found this related StackOverflow issue: https://stackoverflow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted

This issue suggests to rename or add a symlink for two files missing in the latest version (dxand lib/dx.jar). I tested this solution but it does not work. There is also a less upvoted suggestion:

The point is not to downgrade target API level, but to build exactly for API level 31 to prepare and test an app for Android 12!

It looks like DX is removed from SDK in favor of D8.

It looks like that Android Gradle plugin 4.x is not aware of that.

At the moment I see only two solutions:

  • To stay with AGP 4.x, one should copy DX from 30.0.3 to 31.0.0
  • Upgrade AGP to 7.x

I think this is the correct way to support Android 12 but I don't know if this "Android Gradle Plugin" is part of NativeScript or not. My installed Gradle version is 7.2 so I would say yes.

Anything else?

I would be very happy to help as I have an Android 12 phone with me (it's a custom ROM though).

Also, what are the plans for the official support?

sebj54 avatar Nov 04 '21 16:11 sebj54

Apps built with lower level SDK (30 for example) should have no trouble running on Android 12 (sdk 31).

@triniwiz has updated the android-runtime to AGP 7, and released the aplpha version of the runtime, you may be able to test that: npm i --save-dev @nativescript/android@alpha.

rigor789 avatar Nov 04 '21 17:11 rigor789

Yes you're right, it runs fine if we build with SDK 29 (the default one if I'm right).

The fact is I wanted to implement new Bluetooth Android 12 permissions and submit a PR to ˋ@nativescript-community/ble`.

I will give a try tomorrow at the Android runtime alpha, thanks for the info!

sebj54 avatar Nov 04 '21 18:11 sebj54

Unfortunately, it still fails with latest @nativescript/android@alpha. Should I open an issue on https://github.com/NativeScript/android-runtime?

sebj54 avatar Nov 05 '21 09:11 sebj54

I'm also running into the problem as @sebj54 with a brand new nativescript project:

Unable to apply changes on device: <device id>. Error is: The parser encountered some structural problem in the manifest..

I tried adding @nativescript/android@alpha, and I can see the changes in ./platforms/android/build.gradle, using AGP 7.0.2. When I clean and run the project again, I get:

Execution failed for task ':app:processDebugMainManifest'.
Manifest merger failed : android:exported needs to be explicitly specified for <activity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

If I manually change my single activity in the manifest, adding android:exported="true", the build appears to finish and install on the device. It looks declaring android:exported is required for Android 12: https://developer.android.com/about/versions/12/behavior-changes-12#exported

jquerius avatar Nov 07 '21 16:11 jquerius

You're right, it compiles after running ns clean and adding android:exported="true".

Unfortunately I have another problem with a hook from @nativescript/firebase:

Script '/Users/_____/projets/sample-project/node_modules/@nativescript/firebase/platforms/android/include.gradle' line: 96
A problem occurred evaluating script.
Plugin with id 'com.google.gms.google-services' not found.

I think I'll wait a bit for the Android runtime to get out of alpha.

sebj54 avatar Nov 10 '21 11:11 sebj54

I'm new to app development and started from zero and have the same issue. Is it correct to add android:exported="true" to the manifest here App_Resources/Android/src/main/AndroidManifest.xml?

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="__PACKAGE__"
	android:versionCode="10000"
	android:versionName="1.0">

	<supports-screens
		android:smallScreens="true"
		android:normalScreens="true"
		android:largeScreens="true"
		android:xlargeScreens="true"/>

	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.INTERNET"/>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

	<application
		android:name="com.tns.NativeScriptApplication"
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:theme="@style/AppTheme"
		android:hardwareAccelerated="true"
		android:exported="true">

		<activity
			android:name="com.tns.NativeScriptActivity"
			android:label="@string/title_activity_kimera"
			android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode"
			android:theme="@style/LaunchScreenTheme"
			android:hardwareAccelerated="true"
      		android:launchMode="singleTask">

			<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />

			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<activity android:name="com.tns.ErrorReportActivity"/>
	</application>
</manifest>

ndabAP avatar Dec 17 '21 13:12 ndabAP

android:exported="true"

That's exactly where I updated the manifest file as well, however for me, the error message didn't go away even after that Unable to apply changes on device: emulator-5554. Error is: The parser encountered some structural problem in the manifest..

rreddy80 avatar Dec 21 '21 00:12 rreddy80

It needs to be added to the activity not application

triniwiz avatar Dec 21 '21 01:12 triniwiz

It needs to be added to the activity not application

yes that did the trick, nice

rreddy80 avatar Dec 21 '21 12:12 rreddy80

We are experiencing the same issue targeting Android 12 / SDK 31:

The parser encountered some structural problem in the manifest

Trying to install the apk gives the following error:

The APK failed to install. Error: INSTALL_PARSE_FAILED_MANIFEST MALFORMED: Failed parse during installPackageLl: /data/app/vmd1969193467.tmp/base.apk (at Binary XML file line #50): com.tns.NativeScriptActivity: Targeting S+ (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present

After setting android:exported="true" the parser error is gone but the firebase issue occurs:

The APK failed to install. Error. INSTALL_PARSE_FAILED_MANIFEST MALFORMED: Failed parse during installPackageLl: /data/app/vmd111210731.tmp/base.apk (at Binary XML file line #142): org.nativescript.plugins.firebase.MyFirebaseMessagingService: Targeting Si- (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present

Is there a perspective until when the error will be fixed? Currently Android 12 users are completely unable to use our app.

markusmauch avatar Jan 14 '22 10:01 markusmauch

@markusmauch you can use patch-package to add android:exported="true" to the firebase service and rebuild your app: https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/master/src/platforms/android/libraryproject/firebase/src/main/AndroidManifest.xml

rigor789 avatar Jan 14 '22 10:01 rigor789

@rigor789 Hi! Can you explain how to do this using patch-package?

nojcc avatar Jan 20 '22 02:01 nojcc

@sarezjay sure, though after a quick look - seems like the AndroidManifest is packaged into an aar file - so in that case patch-package won't work. But you can still work around this:

  1. make a folder in your project where you can store a patched aar - for example patches/firebase/

  2. copy the firebase-release.aar-disabled from node_modules/@nativescript/firebase/platforms/android into patches/firebase/

  3. open the file (it's basically a zip file, so you can either rename it to .zip and unpack it, or open it with a program that can read zip files - on windows WinRar would work, etc.)

  4. Change the AndroidManifest.xml and add the android:exported="true"

  5. Repack - it's just a zip file with a different extension...

  6. Add a postinstall script to your package.json that copies the file back into node_modules

    "scripts": {
      "postinstall": "cp patches/firebase/firebase-release.aar-disabled node_modules/@nativescript/firebase/platforms/android"
    }
    

    (might need to add a force flag to override the file in node_modules)


Though it would be simpler to open a PR with the fix, and get this published in a patch...

rigor789 avatar Jan 20 '22 10:01 rigor789

@rigor789 in node_modules/@nativescript/firebase/platforms/android there is firebase-release.aar, I think I need to copy that file not firebase-release.aar-disabled.arr file

correct ?

After doing this when I am making build it give error:

Execution failed for task ':app:javaPreCompileDebug'. error in opening zip file

Do any one has idea about it ?

Could you please share you updated firebase-release.aar file ?

jitendraP-ashutec avatar Jan 31 '22 07:01 jitendraP-ashutec

On a fresh install it's firebase-release.aar-disabled but it's renamed to .aar in a postinstall hook, though I don't think it really matters, as long as the final file is named .aar either by the custom postinstall hook, or by firebase's own rename hook.

Odd you are getting that error afterwards, how did you unpack/repack the aar? Should be packed the same way as the original - meaning the files should be at the root of the zip file and not inside a folder.

I've done a test here, I believe it should be correct, but unable to test it myself firebase-release-patched.aar.zip

(I added the .zip extension to be able to upload here, just rename the file to firebase-release.aar without extracting anything.)

rigor789 avatar Feb 01 '22 14:02 rigor789

Thanks @rigor789 for uploading this zip file. I have managed to fix this issue. Somehow It was not working that time, but when I tried after some time it worked as you explained.

jitendraP-ashutec avatar Feb 07 '22 03:02 jitendraP-ashutec

For me it worked with creating the apk with:

ns build android --compileSdk 30

In case someone comes over this error and does not need to compile with 31 yet

asharghi avatar Feb 14 '22 22:02 asharghi

For me it worked with creating the apk with:

ns build android --compileSdk 30

In case someone comes over this error and does not need to compile with 31 yet

Your tip fixed the issue for me. Many thanks!

WesleyGeneroso95 avatar Mar 10 '22 14:03 WesleyGeneroso95

You're right, it compiles after running ns clean and adding android:exported="true".

Unfortunately I have another problem with a hook from @nativescript/firebase:

Script '/Users/_____/projets/sample-project/node_modules/@nativescript/firebase/platforms/android/include.gradle' line: 96
A problem occurred evaluating script.
Plugin with id 'com.google.gms.google-services' not found.

I think I'll wait a bit for the Android runtime to get out of alpha.

For the issue of 'com.google.gms.google-services', I added a classpath line to this file /platforms/android/build.gradle, and it solved it. The classpath will be added under buildscript -> dependencies, like:

dependencies {
        ...
        classpath "com.google.gms:google-services:4.3.4"
    }

Hope if can help solve your issue. :)

cowfox avatar Mar 19 '22 20:03 cowfox

I'm hitting this same issue, even after trying all the above suggestions. This is a serious obstacle, as I need to publish my app but right now can't install on Android 12.

dlcole avatar Apr 12 '22 01:04 dlcole

@dlcole which error are you currently stuck on ?

triniwiz avatar Apr 12 '22 02:04 triniwiz

@triniwiz yes, I realized as I was going to bed I should have been more specific :-)

Here's my current AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  package="__PACKAGE__" 
  android:versionCode="25" 
  android:versionName="5.0.0">

	<supports-screens
		android:smallScreens="true"
		android:normalScreens="true"
		android:largeScreens="true"
		android:xlargeScreens="true"/>

  <uses-sdk 
    android:minSdkVersion="17" 
    android:targetSdkVersion="__APILEVEL__" />

  <uses-permission android:name="android.permission.READ_CONTACTS" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
  <uses-permission android:name="android.permission.CALL_PHONE" />
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
  <uses-permission android:name="android.permission.WRITE_CONTACTS" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

  <application 
    android:name="com.tns.NativeScriptApplication" 
    android:allowBackup="true" 
    android:icon="@drawable/icon" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme"

    android:usesCleartextTraffic="true">

    <!-- See https://github.com/dapriett/nativescript-google-maps-sdk/issues/339 -->
    <uses-library android:name="org.apache.http.legacy" android:required="false"/>
    <meta-data android:name="com.google.android.geo.API_KEY" android:value="@string/nativescript_google_maps_api_key" />

    <activity 
      android:name="com.tns.NativeScriptActivity" 
      android:label="@string/title_activity_kimera" 
      android:configChanges="keyboardHidden|orientation|screenSize" 
      android:theme="@style/LaunchScreenTheme" 
      android:screenOrientation="portrait" 
      android:exported="true" 
      android:launchMode="singleTask">

      <meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
      
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>

      <intent-filter>
        <data android:scheme="rrr" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
      </intent-filter>

      <intent-filter android:autoVerify="true">
        <data android:scheme="https" />
        <data android:host="rrr.govia.tech" />
        <data android:pathPattern="/.*" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
      </intent-filter>

    </activity>
    <activity android:name="com.tns.ErrorReportActivity" />

    <!-- See https://github.com/NativeScript/nativescript-geolocation/issues/256 -->
    <service
      android:name="org.nativescript.geolocation.ForegroundService"
      android:enabled="true"
      android:stopWithTask="true"
      android:exported="false" 
      android:foregroundServiceType="location" />
   
  </application>
</manifest>

Here's my current app.gradle file:

android {  
  compileSdkVersion 31 // had been 30
  defaultConfig {  
    generatedDensities = []
    applicationId = "tech.govia.rrr" 
    multiDexEnabled true
    minSdkVersion 19
  }  

  aaptOptions {  
    additionalParameters "--no-version-vectors"  
  }   
} 

project.ext {
  googlePlayServicesVersion = "+"
}

And if it matters, here's before-plugins.gradle:

project.ext.googlePlayServicesVersion = "16.+"

dependencies {
  // classpath "com.google.gms:google-services:4.3.4"
}

and build script.gradle:

// See https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues/1873
repositories {
    google()
    jcenter()
}
dependencies {
    classpath "com.google.gms:google-services:4.3.4"
}

So, I do have android:exported="true" in the activity section.

The content of these files has evolved over the years as I chase down various issues on SO and GitHub. Probably like a lot of other folks, I'll make changes until things work, sometimes without fully understanding the nature of those changes.

I'd truly welcome any insights here!

dlcole avatar Apr 12 '22 13:04 dlcole

Do you have any error message to share with us?

sebj54 avatar Apr 12 '22 14:04 sebj54

Yes, the resulting error message is,

The parser encountered some structural problem in the manifest

dlcole avatar Apr 12 '22 14:04 dlcole

I think your error is caused by a conflict between the <uses-sdk> tag in your manifest and compileSdkVersion defined in your gradle file.

sebj54 avatar Apr 12 '22 14:04 sebj54

@sebj54 I made these changes:

in app.gradle I added targetSdkVersion to defaultConfig

android {  
  compileSdkVersion 31 // had been 30
  defaultConfig {  
    generatedDensities = []
    applicationId = "tech.govia.rrr" 
    multiDexEnabled true
    minSdkVersion 19
    targetSdkVersion 31
  }  
...

This yields the same error message,

Installing on device emulator-5554...
Unable to apply changes on device: emulator-5554. Error is: The parser encountered some structural problem in the manifest..

so I tried hard-coding the targetSdkVersion in AndroidManifest.xml:

  <uses-sdk 
    android:minSdkVersion="17" 
    android:targetSdkVersion="31" />

But received the same error message.

dlcole avatar Apr 12 '22 16:04 dlcole

There is still a problem because you have minSdkVersion="17" in your manifest and minSdkVersion 19 in your gradle file. I think you should completely remove the <uses-sdk> tag in your manifest and let gradle handle this.

sebj54 avatar Apr 12 '22 16:04 sebj54

So I commented out the <uses-sdk> section of AndroidManifest.xml but still received the error,

Unable to apply changes on device: emulator-5554. Error is: The parser encountered some structural problem in the manifest..

I should note that this is with @nativescript/android 8.1.1. If I switch to 8.2.2 I don't even get as far and fail with the message,

Script '/Users/david/Documents/NativeScriptProjects/rrr/node_modules/nativescript-danem-google-maps-utils/platforms/android/include.gradle' line: 6
A problem occurred evaluating script.
Could not find method compile() for arguments [com.google.maps.android:android-maps-utils:2.0.3] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

Unable to apply changes on device: emulator-5554. Error is: Command ./gradlew failed with exit code 1.

dlcole avatar Apr 12 '22 16:04 dlcole

You need to replace compile in /Users/david/Documents/NativeScriptProjects/rrr/node_modules/nativescript-danem-google-maps-utils/platforms/android/include.gradle to implementation

triniwiz avatar Apr 12 '22 16:04 triniwiz

@triniwiz yep, I've seen that issue before. Upon doing that and rebuilding with @nativescript/android 8.2.2, I'm now back at the same error,

Unable to apply changes on device: emulator-5554. Error is: The parser encountered some structural problem in the manifest..

dlcole avatar Apr 12 '22 16:04 dlcole