Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local notifications not working at all with shrinkResources set to true #1762

Closed
siherrmann opened this issue Oct 18, 2022 · 14 comments
Closed

Comments

@siherrmann
Copy link

Describe the bug
Local notifications are not working with shrinkResources true. Disabling works, but that's not best practice.

To Reproduce
I don't know whether my gradle version is too new so I'll include it:
android/build.gradle

buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.13'
    }
}
(...)

android/app/build.gradle

android {
    compileSdkVersion 33

    defaultConfig {
        // for local notifications
        multiDexEnabled true
        // config
        applicationId "..."
        minSdkVersion 21
        targetSdkVersion 33
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    compileOptions {
        // Flag to enable support for the new language APIs
        coreLibraryDesugaringEnabled true
        // Sets Java compatibility to Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])            
            storePassword keystoreProperties['storePassword']
        }
    }

    buildTypes {
        debug {
            signingConfig signingConfigs.debug
            ndk {
                debugSymbolLevel 'FULL'
            }
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        release {
            signingConfig signingConfigs.release
            ndk {
                debugSymbolLevel 'FULL'
            }
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
(...)

android/app/main/AppManifest.xml

(...)
<activity
            android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:exported="true"
(...)
<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
(...)

So all permissions should be set correctly.

Now, I think the most important thing is the 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.**  { *; }

## Flutter community
-keep class dev.fluttercommunity.** { *; }

## Flutter local notifications
-keep class com.dexterous.** { *; }
-keep public class android.support.** { *; }
-keepattributes InnerClasses  
-keep class **.R
-keep class **.R$* {
    <fields>;
}

## Shared preferences
-keep class com.loopj.android.** { *; }
-keep interface com.loopj.android.** { *; }

## Additional plugin rules
(...)

-keep class io.grpc.** {*;}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

## Gson rules for flutter local notification
-keepattributes Signature
-keepattributes *Annotation*

-dontwarn sun.misc.**

-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

I put everything in there what I found what could help, there should not be anything left what is needed for the local notifications, is there? Is something missing?

Expected behavior
Yeah, expected behaviour would be a working plugin. ;)

Sample code to reproduce the problem
Without code shrinking everything works, so my code should be fine, shouldn't it?

@MaikuB
Copy link
Owner

MaikuB commented Oct 23, 2022

Did you follow the steps referenced in the second paragraph of https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications#release-build-configuration? You don't mention it in your post so I assume that it hasn't been done as the paragraph also mentions that notifications could fail to appear

@siherrmann
Copy link
Author

Sry, yes, I did forget to mention that file but I already had it in my project.

In android/app/src/main/res/raw/keep.xml is this content:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict"
    tools:keep="@drawable/*,@raw/*" />

@siherrmann
Copy link
Author

class NotificationService {
  final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  Future initialize() async {
    timezone.initializeTimeZones();

    AndroidInitializationSettings androidInitializationSettings =
        const AndroidInitializationSettings('@mipmap/ic_launcher');

    DarwinInitializationSettings iosInitializationSettings =
        const DarwinInitializationSettings();

    final InitializationSettings initializationSettings =
        InitializationSettings(
            android: androidInitializationSettings,
            iOS: iosInitializationSettings);

    _flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.requestPermission();

    try {
      await _flutterLocalNotificationsPlugin.initialize(initializationSettings);
    } catch (e) {
      rethrow;
    }
  }
(...)

I did initialise it with .initialise(...), and as I mentioned the code works in Debug mode, so I don't think that it's something directly Dart related.

@krupikivan
Copy link

krupikivan commented Oct 28, 2022

Try this before requestPermission

await _flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channelId);

@siherrmann
Copy link
Author

Doesn't help, so it still works perfectly fine with shrinkResources false but doesn't work with shrinkResources true.

@MaikuB
Copy link
Owner

MaikuB commented Nov 2, 2022

I'm not that familiar with Android development ecosystem but could it be to with how the keep.xml you have specifies strict mode and that it should keep resources in the drawable folder but the one you're looking to use is the ic_launcher icon within the mipmap folder? Perhaps this needs tweaking but I realise how odd that sounds as you would normally would think that icon is kept. Not sure if higher versions of Grade plugin explicitly require that you specify to keep the mipmap resources under strict mode. Though in my experience, normally specifying a proper notification would typically require a drawable as that would be what results from using, say, the Image Asset Studio (see https://developer.android.com/studio/write/image-asset-studio). Might be worth trying to use a drawable instead. I can't reproduce the issue using the example app either after I make it use the launcher icon and when I copy the content of the keep.xml over to it. I don't believe it would be an issue with the plugin either given the plugin's responsibility is to specify the icon (which it does) and resource shrinking issues would fall outside of it and depends on having the appropriate configuration

@siherrmann
Copy link
Author

Thank you for you help. I already also tried the safe mode in the keep.xml, didn't change the situation. Did you also try my proguard file? I hope everything is correct in this file.

@MaikuB
Copy link
Owner

MaikuB commented Nov 9, 2022

Yes I did and is what I meant when I had copied the content of it over. You either need someone who can look at your app in more depth or provide a link to a repo with a minimal app that can reproduce the issue. Doubtful there's anything the plugin to address given the nature of the problem as I touched on earlier

@siherrmann
Copy link
Author

Oh, ok, sry, I didn't understand you correctly then. I will try to implement a minimal example that has the same issue when I have time, I hope I get it done this week.

@DanielArndt
Copy link
Contributor

FWIW I'm having a very similar issue. The only thing that seems to work is setting shrinkResources false.

I understand this is very likely a configuration issue, but it seems exceptionally difficult to track down what isn't configured correctly. I followed the instructions in the README, but I haven't done Android dev in a long time and I'm sure I missed or overlooked something. I'll be combing through it as best I can over the coming days.

@siherrmann Did you have any luck tracking down your issue?

@DanielArndt
Copy link
Contributor

the keep.xml you have specifies strict mode and that it should keep resources in the drawable folder but the one you're looking to use is the ic_launcher icon within the mipmap folder

This was the ticket for me.

I changed

android/app/src/main/res/raw/keep.xml to keep @mipmap/* like so:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@drawable/*,@mipmap/*,@raw/*" />

and now the notifications show up. I know very little about Android resources, so I need to do some reading to figure out what this all means, but at least I know where to look now.

@DanielArndt
Copy link
Contributor

For discoverability, here is what I saw in the logs before I added @mipmap/* to the keep.xml:

11-20 19:25:00.263 19739 19810 W AiAiEcho: SmartspaceNotificationPredictor no parser can handle this notification or notification is invalid
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.icon.IconManager.setIcon(IconManager.kt:76)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.icon.IconManager.createIcons(IconManager.kt:101)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl.inflateViews(NotificationRowBinderImpl.java:38)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.NotifInflaterImpl.inflateViews(NotifInflaterImpl.java:9)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator.inflateEntry(PreparationCoordinator.java:27)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator.inflateRequiredNotifViews(PreparationCoordinator.java:192)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator$$ExternalSyntheticLambda1.onBeforeFinalizeFilter(R8$$SyntheticClass:110)
11-20 19:25:00.297  2496  2496 E Icon    : 	at com.android.systemui.statusbar.notification.collection.NotifPipelineChoreographerImpl$frameCallback$1.doFrame(NotifPipelineChoreographer.kt:37)

@siherrmann
Copy link
Author

the keep.xml you have specifies strict mode and that it should keep resources in the drawable folder but the one you're looking to use is the ic_launcher icon within the mipmap folder

This was the ticket for me.

I changed

android/app/src/main/res/raw/keep.xml to keep @mipmap/* like so:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@drawable/*,@mipmap/*,@raw/*" />

and now the notifications show up. I know very little about Android resources, so I need to do some reading to figure out what this all means, but at least I know where to look now.

Thank you very much, the mipmap was also the problem for me. Now everything works perfectly with code shrinking enabled. Probably it would be good to put the keep.xml with all three values into the documentation?

@MaikuB
Copy link
Owner

MaikuB commented Nov 22, 2022

Closing since this was a configuration issue. There was already a link to the one used for the example app, a link to the Android docs and each app will configure things differently that I don't think that specific one warrants being in the readme. An example of this is some may want to specify the exact resources to keep rather than wildcards. This plugin also doesn't advise to use the launcher icon as the notification icon as was done here either. Note sing image asset studio (see https://developer.android.com/studio/write/image-asset-studio#notification) would've resulted in drawables and that from my understanding is better and more aligned with the official way as there would be assets for different device pixel densities. It would've also meant that the keep.xml file you had originally would've worked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants