fleepp
fleepp

Reputation: 2671

Playstore error: App Bundle contains native code, and you've not uploaded debug symbols

When I want to release a new flutter app bundle to the Playstore. I get this error: "This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug." I can't find any way to fix this. I'm new with flutter and releasing app's and getting a bit desperate... Any help would be fantastic.

When I add "android.defaultConfig.ndk.debugSymbolLevel = 'FULL'" (on line 1) to the app/build.gradle as suggested in https://developer.android.com/studio/preview/features#native-crash-symbolization. I get This error in the Android studio terminal. I use this command "flutter build appbundle".

Error in Terminal: FAILURE: Build failed with an exception.

Could not get unknown property 'android' for project ':app' of type org.gradle.api.Project.

BUILD FAILED in 3s Running Gradle task 'bundleRelease'... Running Gradle task 'bundleRelease'... Done 4,3s Gradle task bundleRelease failed with exit code 1

Upvotes: 266

Views: 180641

Answers (20)

Numidia Ware
Numidia Ware

Reputation: 21

This is an update code from PravyNandas Tested in Android Studio Ladybug Feature Drop | 2024.2.2 Patch 2 with AGP version 8.8.2

Add it to build.gradle.kts(Module:app)

    tasks.register<Zip>("zipNativeDebugSymbols") {
        from("build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib")
        exclude("armeabi*")
        exclude("mips")
        archiveFileName.set("native-debug-symbols.zip")
        destinationDirectory.set(file("release"))
    }
    
    afterEvaluate {
        tasks.named("bundleRelease") {
            finalizedBy("zipNativeDebugSymbols")
        }
    }

This code defines a task zipNativeDebugSymbols to create a zip file of release debug symbols, excluding armeabi and mips architectures, and places it in the release directory.

It then configures the bundleRelease task to always run zipNativeDebugSymbols afterward, ensuring debug symbols are zipped after building the release bundle.

Upvotes: 0

Mohammed Ali
Mohammed Ali

Reputation: 2926

For Mac Users:

Go to build\app\intermediates\merged_native_libs\release\out\lib inside your Flutter project, and compress the folders (arm64-v8a, armeabi-v7a, x86_64) into Archive.zip.

Then cd [into the folder that contains Archive.zip]. Then run the command

zip -d Archive.zip "__MACOSX*"

to get rid of the Mac __MACOSX files. Now upload it into the google play console. If not getting rid of the __MACOSX files, then google play console will give error on uploading -

"The native debug symbols contain an invalid directory __MACOSX"

Upvotes: 0

PravyNandas
PravyNandas

Reputation: 677

Update Jan, 2025.

As of today, Gabriel Logan's solution still works, but a small tweak is needed since play store is not accepting 'mips' and 'armeabi' folders. Notice the "exclude statements".

project/app/build.gradle:

tasks.register('zipNativeDebugSymbols', Zip) {
    from 'build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib'
    exclude 'armeabi*'
    exclude 'mips'
    archiveFileName = 'native-debug-symbols.zip'
    destinationDirectory = file('build/outputs/bundle/release')
}

tasks.configureEach { task ->
    if (task.name == 'bundleRelease') {
        task.finalizedBy zipNativeDebugSymbols
    }
}

Upvotes: 2

Camron
Camron

Reputation: 763

Update for Oct, 2024

Following Gabriel's neat answer, I wanted to automate this process as well. However, that solution wasn't working for me. After two days of trial & error, I realized that that solution had in my case been silently failing (i.e. no errors logged) because the suggested from and destinationDirectory paths were different in my (Flutter) project. So if you are facing similar problems, the following is an expanded solution that adds some checks & logs, allowing you to easier isolate and address any issues specific to your setup now or in the future.

My project setup

Note: mine is a Flutter project but the below solution should be similar in other projects.

A) Update your android/app/build.gradle file

Note: to learn about "tasks" in Gradle, check out the official docs. Also, in the below solution, as suggested by one of the comments in one of the other answers, I am checking for (and removing) some hidden files that are generated by macOS, in case you are on a Mac. That step seems redundant though when the zip is generated programmatically like I do in my solution, but I left it in as a precaution.

Add import java.nio.file.Paths to the top of the android/app/build.gradle file. Then add everything else after the flutter {...} block here:

import java.nio.file.Paths

plugins {
    ...
}

android {
    ...
}

flutter {
    source = "../.."
}

// STEP 1: Create and register the `zipNativeDebugSymbols` task to zip debug symbol files for manual upload to the Google Play store.
def zipNativeDebugSymbols = tasks.register('zipNativeDebugSymbols', Zip) {

    // Optional: this sets some info about the task (to verify, run `./gradlew app:tasks` in the /android folder to see this task listed)
    group = 'Build'
    description = 'Zips debug symbol files for upload to Google Play store.'

    // Set the input source directory (this is where the debug symbol files should be after the `bundleRelease` process has finished)
    def libDir = file('../../build/app/intermediates/merged_native_libs/release/out/lib')
    from libDir

    // Include all subfiles and directories
    include '**/*'

    // Set the name for the output zip file
    archiveFileName = 'native-debug-symbols.zip'

    // Set the destination directory for the output zip file
    def destDir = file('../../build/app/outputs/bundle/release')
    destinationDirectory = destDir

    doFirst {
        // Ensure the paths are correct for the required directories and that they indeed were created / exist (the preceding task `bundleRelease` creates these directories)
        checkDirectoryExists(libDir, 'Library directory')
        checkDirectoryExists(destDir, 'Destination directory')
    }

    doLast {
        println '✅  zipNativeDebugSymbols: created native-debug-symbols.zip file'
        // Optional: if running on macOS, clean up unwanted files like '__MACOSX' and '.DS_Store' in the now created zip file
        // The '__MACOSX' and '.DS_Store' files seem to be added only when manually creating ZIPs on macOS, not programmatically like here. Nevertheless, no harm in leaving this in as a precaution.
        if (System.properties['os.name'].toLowerCase().contains('mac')) {
            println '   running on Mac...'

            // Combine destination path and zip file name
            def zipPath = Paths.get(destinationDirectory.get().asFile.path, archiveFileName.get()).toString()

            // Ensure the zip file exists
            if (new File(zipPath).exists()) {
                println "   removing any '__MACOSX' and '.DS_Store' files from the zip..."
                checkAndRemoveUnwantedFiles(zipPath, '__MACOSX*')
                checkAndRemoveUnwantedFiles(zipPath, '*.DS_Store')
            } else {
                println '❌  zip file does not exist: $zipPath'
            }
        }
        println '✅  zipNativeDebugSymbols: finished creating & cleaning native-debug-symbols.zip'
    }

    // Optional: force the task to run even if considered up-to-date
    outputs.upToDateWhen { false }

    println '✅  zipNativeDebugSymbols: task registered and configured'
}

// STEP 2: Configure the `zipNativeDebugSymbols` task to run after `bundleRelease`
tasks.whenTaskAdded { task ->
    if (task.name == 'bundleRelease') {
        // `finalizedBy` ensures `zipNativeDebugSymbols` runs after `bundleRelease` is complete
        task.finalizedBy zipNativeDebugSymbols
    }
}

//// ----------- HELPER METHODS -------------- ////

// Helper method to check if a directory exists
def checkDirectoryExists(File dir, String description) {
    if (dir.exists()) {
        println '✅  zipNativeDebugSymbols: found ${description} ${dir}'
    } else {
        println '❌  ${description} does not exist: ${dir}'
    }
}

// Helper method to check for unwanted files and remove them
def checkAndRemoveUnwantedFiles(String zipPath, String pattern) {
    def output = new ByteArrayOutputStream()

    exec {
        commandLine 'sh', '-c', "zipinfo $zipPath | grep '$pattern'"
        standardOutput = output
        errorOutput = new ByteArrayOutputStream()
        ignoreExitValue = true
    }

    if (output.toString().trim()) {
        println "✅  zipNativeDebugSymbols: found '$pattern' in the zip. Removing it..."
        exec {
            commandLine 'sh', '-c', "zip -d $zipPath '$pattern' || true"
        }
    }
}

B) Generate files and upload to Google Play store

1. Generate the files for upload:

  • From the root of your project, run flutter clean && flutter build appbundle.
  • Locate the folder that contains the generated files to upload, which is the folder you have defined in def destDir = .... In my case, it is in [project_name]/build/app/outputs/bundle/release. You should have two files in there: app-release.aab and native-debug-symbols.zip.

2. Upload to Google Play store:

  • Upload your app bundle (app-release.aab) to Google Play store.
  • Next, upload your debug symbols zip file (native-debug-symbols.zip) as well. If you don't know how, follow the instructions here in the section Step 2: Upload a deobfuscation or symbolication file.

Voila! That is it. Hope this saves you days of scratching your head like I did.


Helpful debugging info

In case you want to play around a little to understand Gradle and the above tasks better, here are some useful CLI commands. Note that they have to be run from your android/ directory. Also, for a Flutter project the base command here is ./gradlew but I'm guessing it is e.g. just gradlew for other projects.

  • ./gradlew --help displays all available commands
  • ./gradlew --version displays what Gradle version you are using, i.e. what you have set in your android/gradle/wrapper/gradle-wrapper.properties > distributionUrl=....
  • ./gradlew tasks lists all available Gradle tasks for the project (android/build.gradle), showing which tasks can be executed.
  • ./gradlew app:tasks lists all available Gradle tasks specifically for the app module (android/app/build.gradle).
  • ./gradlew clean cleans the build directory by removing all generated files, forcing a fresh build the next time tasks are run. Note: flutter clean achieves this as well.
  • ./gradlew bundleRelease builds the Android App Bundle (aab) in release mode, which is the app bundle that you upload to Google Play.
  • ./gradlew help --task bundleRelease Displays detailed information about the bundleRelease task, including its description, inputs, outputs, and other task properties.
  • ./gradlew zipNativeDebugSymbols --rerun-tasks --quiet runs the given task, e.g. the zipNativeDebugSymbols here, forcing it to rerun all tasks without showing any output unless there are errors.
  • ./gradlew zipNativeDebugSymbols --rerun-tasks --info runs the given task, e.g. the zipNativeDebugSymbols here, forcing it to rerun all tasks and displaying detailed information about the build process.
  • ./gradlew --scan creates a build scan with detailed performance and diagnostic data.

Upvotes: 6

Gabriel Logan
Gabriel Logan

Reputation: 21

As skyllet already answered, this procedure works, if you want to automate the process so you don't have to do it manually every time

You can add this code below in android/app/build.gradle

task zipNativeDebugSymbols(type: Zip) {
    from 'build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib'
    archiveFileName = 'native-debug-symbols.zip'
    destinationDirectory = file('build/outputs/bundle/release')
}

tasks.whenTaskAdded { task ->
    if (task.name == 'bundleRelease') {
        task.finalizedBy zipNativeDebugSymbols
    }
}

Under dependencies at the end of your build.gradle

This will do what the guy showed, but automatically, and will send the zip along with the aab

Upvotes: 1

Ian
Ian

Reputation: 11

I created a windows batch file to build and zip the native libraries.

This DOES NOT work

Compress-Archive -Path .\build\app\intermediates\merged_native_libs\release\out\lib\* -DestinationPath .\native_symbols.zip

Using a 3rd party app works

C:\<your path>\7-Zip\7z.exe a native_symbols.zip .\build\app\intermediates\merged_native_libs\release\out\lib\*

The only difference I can see is that "Compress-Archive" discards the "a" archive file attribute.

Upvotes: 1

skyllet
skyllet

Reputation: 3041

Reproduce the next steps and this warning will disappear.

  1. Go to [YOUR_PROJECT]\build\app\intermediates\merged_native_libs\release\out\lib

For some the path might be [YOUR_PROJECT]\app\build\.... and not [YOUR_PROJECT]\build\app\.... like mentioned above.

Note that 3 folders exist inside

  • arm64-v8a
  • armeabi-v7a
  • x86_64
  1. Select these 3 folders and create a .zip file. The name doesn't matter.

[PLEASE NOTE THAT I HAVEN'T COMPRESSED THE ./lib FOLDER]

  1. Upload this new *.zip file as a Symbol File.

.

The newest update, for us (8-Nov 2023) the folder exists in [YOUR_PROJECT]\build\app\intermediates\merged_native_libs\release\out\lib

Upvotes: 280

Jamshed Khan
Jamshed Khan

Reputation: 1

screenshot

My issue was this:

This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug.

Fix successfully just upload native debug symbols from the image reference directory shown.

Upvotes: -1

Adam Bridges
Adam Bridges

Reputation: 518

Instead of creating and uploading zip files, you can include the following to your app\build.gradle file:

buildTypes {
    debug { 
        // This is just here for local testing and is optional.
        firebaseCrashlytics { 
            nativeSymbolUploadEnabled true
            unstrippedNativeLibsDir file("build/app/intermediates/merged_native_libs/debug/out/lib")
        }
        ndk {
            debugSymbolLevel 'SYMBOL_TABLE'
        }
    }
    release {
        // ..
        firebaseCrashlytics { // Insert this
            nativeSymbolUploadEnabled true 
            unstrippedNativeLibsDir file("build/app/intermediates/merged_native_libs/release/out/lib")
        }
        ndk {
            // replace with 'FULL' if you need more info,
            // but note that it will increase the file size of your appbundle dramatically.
            debugSymbolLevel 'SYMBOL_TABLE'
        }
    }
}

Here is some documentation for reference: https://firebase.google.com/docs/crashlytics/ndk-reports#upload-symbols-external-dependencies

And if you're unclear about how to set up automatic uploading of native symbols, try adding this:

buildTypes { ... } // Your build types from the above snippet.

tasks.whenTaskAdded { task ->
    if (task.name.startsWith('assemble') && task.name != "assembleReleaseAndroidTest"
            && task.name != "assembleDebugAndroidTest") {
        String taskName = "uploadCrashlyticsSymbolFile" + task.name.substring('assemble'.length())
        task.finalizedBy taskName
        doFirst {
            println "Running Gradle task '$taskName'..."
        }
    }
}

More info for building gradle tasks here: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

Also, ensure that you have NDK and CMAKE installed in your IDE's SDK Manager.

Hope that helps!

Upvotes: 8

Md omer arafat
Md omer arafat

Reputation: 466

Simple approach, go to \build\app\intermediates\merged_native_libs\release\out\lib , you will find 3/4 folders , zip those , upload this ZIP from release option ( upload Symbol File ). Warning will be gone after bundle review.

Upvotes: 7

Oyvind Habberstad
Oyvind Habberstad

Reputation: 1052

I just upgraded ndk from 21.4.7075529 to 22.1.7171670, and now I get the debug symbols.

I'm using com.android.tools.build:gradle:7.1.1 and React Natvive 0.69 BTW.

Upvotes: 3

almamon Rasool Abd Ali
almamon Rasool Abd Ali

Reputation: 685

you can make these zip file by go to build\app\intermediates\merged_native_libs\release\out\lib inside your Flutter project

and compress the folders into symbols.zip, now upload it into the google play console

Upvotes: 30

Shakle
Shakle

Reputation: 1408

Before you can upload debug symbols files, you must be using Android Gradle plugin version 4.1 or higher.

Looks like it will come only with Android Studio 4.1, because I can only get Gradle 4.0.0 automatically now.

So I suggest you to return classic Play console and it will let you through :)

UPDATE: So just use an updated Gradle and add NDK debug symbols to the build now

Upvotes: 50

Shakle
Shakle

Reputation: 1408

If talking about Flutter, looks like the Flutter team needs to change some source files for the NDK, because it does not see where from to generate debug symbols.

Here is an issue thread: https://github.com/flutter/flutter/issues/60240

Setup steps are so:

  • Pre-condition: Intall Android studio 4.1+ and Gradle 4.1+
  1. Install NDK (Side by Side) in SDK manager enter image description here

  2. Write path to NDK in local.properties enter image description here

  3. Add in app/build.gradle (last line) android.buildTypes.release.ndk.debugSymbolLevel = 'FULL' enter image description here

Upvotes: 76

Taras Svidnytskyy
Taras Svidnytskyy

Reputation: 143

I had a similar problem. What really helped me:

  1. Make sure your Android Gradle plugin version is 4.1 or later.
  2. Install NDK (Side by Side) in SDK manager.
  3. Install CMake in SDK manager.
  4. Add
    ndkVersion <ndkVersion>
    ndk {
      debugSymbolLevel 'FULL'
    }

to app/build.gradle

My final build.gradle:

...
android {
  compileSdkVersion 30
  defaultConfig {
    applicationId "com.example.app"
    minSdkVersion 21
    targetSdkVersion 30
    versionCode 28
    versionName "1.0.59"
    ndkVersion "23.1.7779620"
    ndk {
      debugSymbolLevel 'FULL'
    }
  }
  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  configurations {
    compile.exclude group: 'com.google.zxing'
  }
}
...

I hope this will help you and save you time

Upvotes: 10

Han Parlak
Han Parlak

Reputation: 777

For fixing it in the Visual Studio Code: you should first download the NDK from the android's website.

  • Extract the zip file to a folder named ndk and place it under your - already installed - Android SDK folder. Like this: Android/sdk/ndk

  • Then open app/build.gradle.

  • Under the Android section. Add ndkPath property as follows: ndkPath = <ndk-dir>

app/build.gradle ndkPath property

  • At the end of app/build.gradle add android.buildTypes.release.ndk.debugSymbolLevel = 'full'

  • The next appbundle, built by flutter build appbundle command should not give any errors on the play store about native debug symbols.

a more thorough explanation is here

Upvotes: 2

connorads
connorads

Reputation: 530

I was able to get Flutter to build native debug symbols using Android Gradle Plugin (AGP) 4.1.0, installing corresponding NDK version and adding the appropriate config to android/app/build.gradle on macOS (but it should also work on Windows/Linux).

  1. Optional: Run flutter build appbundle and take note of the .aab file size
  2. Check what version of AGP you're using in android/build.gradle by looking in dependencies e.g. com.android.tools.build:gradle:4.1.0 is 4.1.0
  3. Check which version of NDK you need. Assuming your AGP is 4.1.0 the NDK version you want to install is 21.1.6352462 (for other AGP versions check mappings here)
  4. Install specific NDK version using Android Studio. Alternatively you can use sdkmanager and the CLI: $ANDROID_HOME/tools/bin/sdkmanager --install "ndk;21.1.6352462"
  5. In android/app/build.gradle, under android.defaultConfig add ndk { debugSymbolLevel 'FULL' } aka set android.defaultConfig.ndk.debugSymbolLevel = 'FULL' as per this
  6. Run flutter build appbundle. The .aab should now contain native debug symbols and be larger than the previous build in step 0

Troubleshooting: If you get any errors around CMake I didn't explicitly install it but you might need to, especially if you're using Windows, and you can do so using Android Studio.

Upvotes: 0

Kneelon
Kneelon

Reputation: 277

If you want to solve this warning error: This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug. Make sure also to install CMake

This will happen if your gradle version is higher than 4.0 Place this code into your build.gradle file

android {
compileSdkVersion 28
defaultConfig {
    applicationId 'com.example.myproject'
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0.0"
    ndk {
        debugSymbolLevel 'FULL'
    }
}

Upvotes: 8

LiveRock
LiveRock

Reputation: 1033

I have the exact same issue.

Possible solutions:

  1. Use the Google classic Play console
  2. Gradle 4.1 is now released with Android Studio 4.1

Upvotes: 1

Pratik Butani
Pratik Butani

Reputation: 62419

The Answer was given by Shakle will be not useful as per the following message on Play Console.

The old version of Play Console will be discontinued from November 2, 2020 You’re already using the new Play Console, so you don’t need to do anything. A few features are going away if you want to check them one last time.

It's just a warning, nothing else. Just go ahead.

If you don't want any warning, Go to this link and follow the steps:

https://support.google.com/googleplay/android-developer/answer/9848633?hl=en

You can use the new version of the play store as it is.

Upvotes: 27

Related Questions