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

[Bug]: OneSignal .net-android error in Initialize call. Java.Lang.NoSuchMethodError #89

Open
1 task done
IainS1986 opened this issue Jan 18, 2024 · 20 comments
Open
1 task done

Comments

@IainS1986
Copy link

What happened?

Updgrading a Xamarin Native to .net-android and .net-ios project.

Added OneSignalSDK.DotnNet/5.0.2

OneSignal.Initialize("MY KEY");

This line then errors with...

Java.Lang.NoSuchMethodError
                                                                                                    no static method "Lcom/onesignal/OneSignal;.initWithContext(Landroid/content/Context;Ljava/lang/String;)V"
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(JniObjectReference type, String name, String signature)
                                                                                                       at Java.Interop.JniType.GetStaticMethod(String name, String signature)
                                                                                                       at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String method, String signature)
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String encodedMember)
                                                                                                       at Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(String encodedMember, JniArgumentValue* parameters)
                                                                                                       at Com.OneSignal.Android.OneSignal.InitWithContext(Context context, String appId)
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at OneSignalSDK.DotNet.Android.AndroidOneSignal.Initialize(String appId)
                                                                                                       at OneSignalSDK.DotNet.OneSignal.Initialize(String appId)
                                                                                                       at xxx.Droid.Views.AppStartup.AppStartupContainerActivity.OnCreate(Bundle bundle)

Steps to reproduce?

1. Create new .net-android project
2. Add the OneSignalSDK.DotNet/5.0.2 nuget
3. Add the Initialize line to your first/main Activity
4. Run

What did you expect to happen?

It initialises.

Relevant log output

Java.Lang.NoSuchMethodError
                                                                                                    no static method "Lcom/onesignal/OneSignal;.initWithContext(Landroid/content/Context;Ljava/lang/String;)V"
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at Java.Interop.JniEnvironment.StaticMethods.GetStaticMethodID(JniObjectReference type, String name, String signature)
                                                                                                       at Java.Interop.JniType.GetStaticMethod(String name, String signature)
                                                                                                       at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String method, String signature)
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at Java.Interop.JniPeerMembers.JniStaticMethods.GetMethodInfo(String encodedMember)
                                                                                                       at Java.Interop.JniPeerMembers.JniStaticMethods.InvokeVoidMethod(String encodedMember, JniArgumentValue* parameters)
                                                                                                       at Com.OneSignal.Android.OneSignal.InitWithContext(Context context, String appId)
2024-01-18 09:56:40.876 17411-17411 DOTNET                  com.xxx.xxx               I     at OneSignalSDK.DotNet.Android.AndroidOneSignal.Initialize(String appId)
                                                                                                       at OneSignalSDK.DotNet.OneSignal.Initialize(String appId)
                                                                                                       at xxx.Droid.Views.AppStartup.AppStartupContainerActivity.OnCreate(Bundle bundle)

Code of Conduct

  • I agree to follow this project's Code of Conduct
@IainS1986
Copy link
Author

Ok, this is an R8 shrinker issue.

I've tried adding some custom proguard rules but I'm struggling to get it to work.

-keep public class com.onesignal.** {;}
-keep interface com.onesignal.** {
;}

Works to get past the basic method missing errors but then I get the following Java.Lang.Exception...

Service interface com.onesignal.core.internal.operations.IOperationRepo could not be instantiated

I thought the keep interface line above would resolve this but it didn't. Any ideas what rules are needed?

@IainS1986
Copy link
Author

IainS1986 commented Jan 23, 2024

Does anyone have working, R8 shrinker rules for OneSignal on Android?

I've tried using older proguard rules from here https://github.com/OneSignal/OneSignal-Android-SDK/blob/main/OneSignalSDK/onesignal/consumer-proguard-rules.pro#L51 but this isn't working with R8 shrinking.

Turning off R8 works fine, I'm sure our older Xamarin native project using OneSignal was R8 shrinking so this seems a specific problem in the new .net-android SDK support.

Can't seem to get the R8 not to break whatever it is that implements IOperationRepo

[mono-rt] java.lang.Exception: Service interface com.onesignal.core.internal.operations.IOperationRepo could not be instantiated
[mono-rt] 	at com.onesignal.common.services.ServiceProvider.getService(ServiceProvider.kt:70)
[mono-rt] 	at com.onesignal.internal.OneSignalImp.initWithContext(OneSignalImp.kt:40)
[mono-rt] 	at com.onesignal.OneSignal.initWithContext(OneSignal.kt:126)

@IainS1986
Copy link
Author

Is there anyone from OneSignal able to advise on how to use this SDK with R8 shrinking on Android?

@IainS1986
Copy link
Author

IainS1986 commented Mar 8, 2024

This is the Full Proguard rules i've tried for OneSignal (based off the old Xamarin one and the Android project) but not had any success yet...

# OneSignal
# https://github.com/OneSignal/OneSignal-Android-SDK/blob/main/OneSignalSDK/onesignal/consumer-proguard-rules.pro#L51
-dontwarn com.amazon.**
-dontwarn com.google.android.gms.location.LocationListener
-dontwarn com.onesignal.**
-dontwarn com.onesignal.notification.**

-keep class com.google.firebase.provider.** { *; }
-keep class com.onesignal.** { *; }
-keep interface com.onesignal.** { *; }
-keep class com.onesignal.ActivityLifecycleListenerCompat** {*;}

# These 2 methods are called with reflection.
-keep class com.google.android.gms.common.api.GoogleApiClient {
    void connect();
    void disconnect();
}

# Need to keep as these 2 methods are called with reflection from com.onesignal.PushRegistratorFCM
-keep class com.google.firebase.iid.FirebaseInstanceId {
    static com.google.firebase.iid.FirebaseInstanceId getInstance(com.google.firebase.FirebaseApp);
    java.lang.String getToken(java.lang.String, java.lang.String);
}

-keep class ** implements com.onesignal.notifications.IPermissionObserver{
    void onNotificationPermissionChange(java.lang.Boolean);
}

-keep class ** implements com.onesignal.user.subscriptions.IPushSubscriptionObserver {
    void onPushSubscriptionChange(com.onesignal.user.subscriptions.PushSubscriptionChangedState);
}

-keep class ** implements com.onesignal.notifications.INotificationServiceExtension{
    void onNotificationReceived(com.onesignal.notifications.INotificationReceivedEvent);
}

# Observer backcall methods are called with reflection
-keep class com.onesignal.OSSubscriptionState {
    void changed(com.onesignal.OSPermissionState);
}

-keep class com.onesignal.OSPermissionChangedInternalObserver {
    void changed(com.onesignal.OSPermissionState);
}

-keep class com.onesignal.OSSubscriptionChangedInternalObserver {
    void changed(com.onesignal.OSSubscriptionState);
}

-keep class com.onesignal.OSEmailSubscriptionChangedInternalObserver {
    void changed(com.onesignal.OSEmailSubscriptionState);
}

-keep class com.onesignal.OSSMSSubscriptionChangedInternalObserver {
    void changed(com.onesignal.OSSMSSubscriptionState);
}

-keep class ** implements com.onesignal.OSPermissionObserver {
    void onOSPermissionChanged(com.onesignal.OSPermissionStateChanges);
}

-keep class ** implements com.onesignal.OSSubscriptionObserver {
    void onOSSubscriptionChanged(com.onesignal.OSSubscriptionStateChanges);
}

-keep class ** implements com.onesignal.OSEmailSubscriptionObserver {
    void onOSEmailSubscriptionChanged(com.onesignal.OSEmailSubscriptionStateChanges);
}

-keep class ** implements com.onesignal.OSSMSSubscriptionObserver {
    void onOSEmailSubscriptionChanged(com.onesignal.OSSMSSubscriptionStateChanges);
}

-keep class com.onesignal.shortcutbadger.impl.AdwHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.ApexHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.AsusHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.DefaultBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.EverythingMeHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.HuaweiHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.LGHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.NewHtcHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.NovaHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.OPPOHomeBader { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.SamsungHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.SonyHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.VivoHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.XiaomiHomeBadger { <init>(...); }
-keep class com.onesignal.shortcutbadger.impl.ZukHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.AdwHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.ApexHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.AsusHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.DefaultBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.EverythingMeHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.HuaweiHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.LGHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.NewHtcHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.NovaHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.OPPOHomeBader { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.SamsungHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.SonyHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.VivoHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.XiaomiHomeBadger { <init>(...); }
-keep class com.onesignal.notifications.internal.badges.impl.shortcutbadger.impl.ZukHomeBadger { <init>(...); }

-dontwarn com.amazon.**
-dontwarn com.huawei.**

# Proguard ends up removing this class even if it is used in AndroidManifest.xml so force keeping it.
-keep public class com.onesignal.ADMMessageHandler {*;}
-keep public class com.onesignal.ADMMessageHandlerJob {*;}

# OSRemoteNotificationReceivedHandler is an interface designed to be extend then referenced in the
#    app's AndroidManifest.xml as a meta-data tag.
# This doesn't count as a hard reference so this entry is required.
-keep class ** implements com.onesignal.OneSignal$OSRemoteNotificationReceivedHandler {
   void remoteNotificationReceived(android.content.Context, com.onesignal.OSNotificationReceivedEvent);
}

-keep class com.onesignal.JobIntentService$* {*;}
-keep class com.onesignal.OneSignalUnityProxy {*;}

-keepclassmembers class com.onesignal.notifications.** { *; }

@IainS1986
Copy link
Author

IainS1986 commented Mar 12, 2024

Example Repo of the issue (using MAUI)

https://github.com/IainS1986/OneSignal-R8-Test

This is a basic MAUI template (from Rider).

  • One Signal 5.1.1 added
  • One Signal intialisation same as your documentation
  • Release Configuration -> R8 Enabled
  • Proguard.cfg file added with all the proguard rules from all the Android modules found.

When I run a release configuration build to my phone I get the same exception…

FATAL EXCEPTION: main
Process: com.companyname.mauiapp1, PID: 1221
java.lang.RuntimeException: Unable to create application crc64e632a077a20c694c.MainApplication: java.lang.Exception: Service interface com.onesignal.core.internal.operations.IOperationRepo could not be instantiated

@rmayrink
Copy link

Same problema here...

@ghost
Copy link

ghost commented Apr 8, 2024

I had to add this instruction to my Proguard file to fix it:
-keepattributes Signature

@IainS1986
Copy link
Author

When I try adding that I'm getting a whole bunch of R8 errors "A type or variable is not in scope."

Can you share your whole proguard file?

@ghost
Copy link

ghost commented Apr 8, 2024

OneSignal - Proguard ends up removing this class even if it is used in AndroidManifest.xml so force keeping it.

-dontwarn com.onesignal.**

OneSignal - These 2 methods are called with reflection.

-keep class com.google.android.gms.common.api.GoogleApiClient {
void connect();
void disconnect();
}

-keep class com.onesignal.** {*;}
-keepattributes Signature

Keep methods annotated with @JavascriptInterface for webview bridge (InApp feature)

-keepclassmembers class * {
@android.webkit.JavascriptInterface *;
}

End OneSignal

@ghost
Copy link

ghost commented Apr 8, 2024

It seems only this was enough for my project. At least for initializing the onesignal.

@IainS1986
Copy link
Author

Cheers, mayhbe theres something else in my proguard colliding with this, i'll try removing bits and adding bits and see how I go, cheers for pointing this line out though 👍

@ghost
Copy link

ghost commented Apr 8, 2024

My project is Xamarin and it's using the version 5.0.2.

@IainS1986
Copy link
Author

Might be the difference too, this is specifically about .net-android 8+ (which you'll have to port over too soon). Hard to tell thought 🤷

@ghost
Copy link

ghost commented Apr 8, 2024

I don't think it doesn't change much because it's using the onesignal android 5.0.3. It should be the same.

@IainS1986
Copy link
Author

Proguard effects your entire app. Not just onesignal. So it might fix it, but adding that line breaks some other sections in my proguard that (may) be needed for .net-android, I can't say for sure so will need some time to go through things bit by bit. I think it broke an AndroidX section in my proguard but will see.

@ghost
Copy link

ghost commented Apr 8, 2024

# OneSignal
# https://github.com/OneSignal/OneSignal-Android-SDK/blob/main/OneSignalSDK/onesignal/consumer-proguard-rules.pro#L51
-dontwarn com.onesignal.**
-keep class com.microsoft.maui.** {*;}
-keep class androidx.startup.** {*;}
-dontwarn com.amazon.** 
-dontwarn com.google.firebase.**
-keep class com.google.firebase.**

# OneSignal - Proguard ends up removing this class even if it is used in AndroidManifest.xml so force keeping it.

-keep class com.onesignal.** {*;}
-keepattributes Signature

# Keep methods annotated with @JavascriptInterface for webview bridge (InApp feature)
-keepclassmembers class * {
@android.webkit.JavascriptInterface *;
}
# End OneSignal

 

@ghost
Copy link

ghost commented Apr 8, 2024

I tried to change your maui test app using this configuration.

@IainS1986
Copy link
Author

When I'm refering the my proguard file thats breaking I'm not referring to that test project, that was for the OneSignal team to investigate.

The proguard file I have in another app is much larger. But I'll dig more into it but won't be happening for a week or two

@IainS1986
Copy link
Author

I narrowed it down to the following lines that break with the keepattributes Signature line,

-dontwarn androidx.**
-keep class androidx.** { *; }
-keep interface androidx.** { *; }

So I need to figure out the exact bits of AndroidX to keep as opposed to an (ugly) blanket keep on the whole thing

@IainS1986
Copy link
Author

Ok. After a lot of head banging I think I've resolved the issue.

So as @arctouch-rafaelpontes above pointed out, you do need to have this in your proguard,

-keepattributes Signature

But, you might (like me) have the following your proguard

-keep class androidx.** { *; }

These two lines do not work together. Ideally, you shouldn't be just having keep on the whole androidx, but its a faff not doing that if you need it. However you'll need to work out all references you are using in androidx and only include those. This is not fun.

Thankfully, someone did a lot of leg work already around this issue they were having with a different library here
xamarin/xamarin-android#7008

So from this, I managed to make the following proguard that works, you might have some things still fail that you need to add, but this should work.

# OneSignal
-keep class com.onesignal.** { *; }
-keep class com.onesignal.core.** { *; }
-keep class com.onesignal.session.** { *; }
-keep class com.onesignal.user.** { *; }
-keep class com.onesignal.internal.** { *; }
-keep class com.onesignal.debug.** { *; }
-keep class com.onesignal.common.** { *; }
-keep class ** implements com.onesignal.common.modules.IModule { *; }

# https://github.com/xamarin/xamarin-android/issues/7008#issuecomment-1789672213
-keepattributes AnnotationDefault,
                EnclosingMethod,
                InnerClasses,
                RuntimeVisibleAnnotations, # <-- Kotlin metadata is a runtime-visible annotation
                RuntimeVisibleParameterAnnotations,
                RuntimeVisibleTypeAnnotations,
                Signature

# Glide and MAUI Essentials                
-keep class com.microsoft.maui.** { *; }
-keep class com.bumptech.glide.** { *; }

# Google Android Material
-keep class com.google.android.material.** { *; }

# AndroidX
-keep class androidx.activity.result.** { *; }
-keep class androidx.appcompat.** { *; }
-keep class androidx.autofill.** { *; }
-keep class androidx.biometric.** { *; }
-keep class androidx.core.app.** { *; }
-keep class androidx.core.content.pm.PackageInfoCompat { *; }
-keep class androidx.core.net.** { *; }
-keep class androidx.core.splashscreen.SplashScreen { *; }
-keep class androidx.core.text.** { *; }
-keep class androidx.core.transition.** { *; }
-keep class androidx.core.view.** { *; }
-keep class androidx.core.widget.** { *; }
-keep class androidx.constraintlayout.** { *; }
-keep class androidx.startup.** { *; }
-keep class androidx.security.crypto.** { *; }
-keep class androidx.window.** { *; }
-keep class com.android.internal.policy.** { *; }
-keep class androidx.fragment.** { *; }
-keep class androidx.work.impl.background.** { *; }
-keep class androidx.viewpager2.** { *; }
-keep class androidx.recyclerview.** { *; }
-keep class com.android.internal.policy.** { *; }
-keep class androidx.percentlayout.** { *; }
-keep class androidx.browser.** { *; }
-keep class android.app.** { *; }
-keep class android.view.** { *; }
-keep class android.util.** { *; }
-keep class android.net.** { *; }
-keep class androidx.navigation.** { *; }

# Java
-keep class java.util.** { *; }

If all you want is the specific OneSignal rules

# OneSignal
-keepattributes Signature
-keep class com.onesignal.** { *; }
-keep class com.onesignal.core.** { *; }
-keep class com.onesignal.session.** { *; }
-keep class com.onesignal.user.** { *; }
-keep class com.onesignal.internal.** { *; }
-keep class com.onesignal.debug.** { *; }
-keep class com.onesignal.common.** { *; }
-keep class ** implements com.onesignal.common.modules.IModule { *; }

tbh, this might be enough

# OneSignal
-keepattributes Signature
-keep class com.onesignal.** { *; }

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

2 participants