Flutter issues with release-mode only APK builds
Asked Answered
O

3

8

When running the app from an installed APK I have issues but when running directly from Android studio the app works well. Tested on Both physical devices and emulators, and also with build modes debug, profile and release (where release and profile modes of course only works on physical devices)

Summary: a) Shared Prefs, Path Provider and Permission Handler produces a MissingPluginException. b) The Android back button does not work.

These may be separate issues but I have a strong suspicion that they are related because both of them occur only when the app is started from an APK not installed directly from Android Studio.

To be very clear - if I "install" the app from within Android Studio, I can then continue using the app even without AS connected. However when I build an APK, install it manually, and try to run the app I get various symptoms caused by the above errors. If I then connect Logcat via Android Studio, the issues will persist until I install a new build using AS.

Some more details:

  1. During the APK build process for release mode, gradle complains about missing "libs.jar" files, for example:
Execution failed for task ':app:lintVitalQaRelease'.                    
> Could not resolve all artifacts for configuration ':app:devProfileRuntimeClasspath'.
   > Failed to transform libs.jar to match attributes {artifactType=processed-jar, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
      > Execution failed for JetifyTransform: /home/johan/AndroidStudioProjects/teacher_app/build/app/intermediates/flutter/devProfile/libs.jar.
         > Transform's input file does not exist: /home/johan/AndroidStudioProjects/teacher_app/build/app/intermediates/flutter/devProfile/libs.jar. (See https://issuetracker.google.com/issues/158753935)

Searching for solutions to the above brings up several documented cases, except that they generally don't have Flavors, so :app:lintVitalRelease in stead of :app:lintVitalQaRelease as I am getting. In addition the error will show the missing intermediates as .../flutter/Profile/libs.jar in the reported cases, again without the flavors.

In my case the extra Qa and dev respectively are two different flavors. Where in the other cases the workaround is "build your debug and profile mode apk to fix the issue", in my case it is "Build your debug and profile AND release APKs for all the other flavors, not just the one you're trying to build".

So I toggle between trying to build flavor "Qa" mode "release", and whichever one it complains about, over and over about until it is satisfied and produces the APK. It is annoying to have to build a bunch of unrelated flavors and modes, but at least is is a workaround that gets me an APK.

After this I am able to install and un from the APK, but with issues. logcat shows some MissingPlugin exceptions occuring:

MissingPluginException(No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider)

and....

MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)

Finally: While investigating this all I tried the permission handler example from https://pub.dev/packages/permission_handler/example. I just added it as a new "page" into my app. On navigatign to this page I get another exception:

MissingPluginException(No implementation found for method checkPermissionStatus on channel flutter.baseflow.com/permissions/methods)

A lot of functionality in the app related to these plugins are not working - Photos don't display, user needs to authenticate on each restart, and so on. These are clearly dependent on the above plugins.

I've tried to add WRITE_EXTERNAL_STORAGE to the AndroidManifest, even added it to the separate manifests for each of the flavors. (I normally add shared config to the main AndroidManifest.xml only)

I've implemented signing for release mode just in case Android doesn't like to give permissions to unsigned APKs.

EDIT: To eliminate the application-ID as being the cause of the issue I've changed all instances back to the original package name used when the project was created. This means only one flavor can be installed on my device at a time. It however does not make any difference.


I've obviously done flutter-clean and flutter-get many times, each time forcing me to go through the process of building all the missing intermediates one by one.

One other thing... The Android Back button doesn't work. It works fine if I run the app directly from Android Studio, but doesn't work (seems to be ignored) when running it from APK only.

I'm at my wits end with this.

EDIT #2: Progress!
I created a new project and copied the source (lib/*) over. I also copied pubspec.yaml and the assets. I have made no changes to the build.gradle file, and only made two changes to the main AndroidManifest.xml - the Application Name and added the Internet permission.

I also did set the app icon.

Copying the source over was ardorous - there being many many many imports but the end result is a working build.

SharedPrefs survives restarts Downloaded images are displayed Android back-button works Device Permissions for Storage shows as granted Opening the camera from within the app asks for permission the first time. The app can send the user to the Android App settings screen.

Everything seems to work. I probably made a mistake somewhere because the new app shows the correct app Icon on the home screen but shows the Flutter default icon in the Android settings page for the app.

The next steps would be to sign the APK and then to re-introduce flavors, even if just to be able to set the dart target, but hopefully also to set other properties.

Organelle answered 6/9, 2020 at 15:53 Comment(3)
I am starting to suspect that this relates to the AppicationID / package name. Each "flavor" has a different applicationID in app/build.gradle. These generally match the flavor specific package name in the corresponding AndroidManifest.xml The issue is that there is also a name in the Kotlin mainActivity that correlates to the original package name at the time the project was created, and another one in the main AndroidManifest.xml. There are conflicts and I think this is causing issues. I don't know how to solve these.Organelle
I changed all the flavor and build modes to use the original packageID. This would mean that I can have only one flavour installed at a time, but alas it does not work, I still have the same issue.Organelle
Check your pro guard. Its the one messing around.Suavity
M
6

I had this exact problem. I solved it with a couple different ways:

  1. Add proguard-rules.pro to android/app/proguard-rules.pro
#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.**  { *; }
-keep class io.flutter.util.**  { *; }
-keep class io.flutter.view.**  { *; }
-keep class io.flutter.**  { *; }
-keep class io.flutter.plugins.**  { *; }
-keep class androidx.lifecycle.** { *; } #https://github.com/flutter/flutter/issues/58479
#https://medium.com/@swav.kulinski/flutter-and-android-obfuscation-8768ac544421
  1. add proguard to buildTypes in app level build.gradle
buildTypes {
    release {
        profile {
            matchingFallbacks = ['debug', 'release']
        }
    minifyEnabled true
    useProguard true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.release
    }
}
lintOptions {
    disable 'InvalidPackage'
    checkReleaseBuilds false
}
  1. You can also try running master channel in terminal:
flutter channel master
  1. I also migrated android to AndroidX in Android Studio by navigating to SDK manager->SDK tools->checking and downloading Google Play services

  2. I also made sure that compile SDK and target SDK is 29; there are issues with permission_handler package with SDK 30 at the moment.

  3. I also edited the kotlin main activity file:

package yourpackage
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
    }
}
Monochromat answered 7/10, 2020 at 1:33 Comment(0)
E
1

For me this solved the issue

just add proguard-rules.pro to android/app/proguard-rules.pro

and add the following line:

-keep class androidx.lifecycle.DefaultLifecycleObserver
Elga answered 13/2, 2021 at 19:44 Comment(0)
S
0

As @Alex answered, Flutter obfuscates code and sometimes it create errors on Android or Java libraries.

I recommend you to read this post below and try to add the missing class to "proguard-rules": https://medium.com/@swav.kulinski/flutter-and-android-obfuscation-8768ac544421

Siu answered 10/11, 2021 at 17:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.