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

NotificationExtenderService no Extender prop at OverrideSettings #231

Open
lltwist opened this issue Apr 1, 2021 · 7 comments
Open

NotificationExtenderService no Extender prop at OverrideSettings #231

lltwist opened this issue Apr 1, 2021 · 7 comments

Comments

@lltwist
Copy link

lltwist commented Apr 1, 2021

Description:

I try to implement Android Notification Extender Service to change payload as it is described at https://documentation.onesignal.com/docs/service-extensions#notification-extender-service and also using this snippet #123 (comment)

    [Service(Permission = "android.permission.BIND_JOB_SERVICE", Exported = false)]
    [IntentFilter(actions: new[] {"com.onesignal.NotificationExtender"})]
    public sealed class OneSignalNotificationExtenderService : NotificationExtenderService
    {
        static readonly OverrideSettings _displaySettings = new OverrideSettings() {Extender = new Extender()};

        protected override bool OnNotificationProcessing(OSNotificationReceivedResult p0)
        {
            var notification = Com.OneSignal.NotificationOpenedHandler.OSNotificationToNative(new OSNotification() {Payload = p0.Payload});

            DisplayNotification(_displaySettings);

            // task.Wait();
            return true;
        }
        
        protected override void OnHandleIntent(Intent intent)
        {
        }

        private sealed class ExtenderEx : Java.Lang.Object, NotificationCompat.IExtender
        {
            public NotificationCompat.Builder Extend(NotificationCompat.Builder builder)
            {
                return builder
                    .SetContentTitle("modified")
                    .SetContentText("modified")
                    // .SetDefaults(~(int) NotificationDefaults.Sound);
            }
        }
    }

.. and having such problems:

  • in ver 3.10.4 there is no property Extender on class OverrideSettings (some binding attr problem, because in .aar such a field exists);
  • in ver 3.10.3 and older property Extender exists, but throws Java.Lang.NoSuchFieldError exception

Environment

  1. Targeting Android 10.0 API 29
  2. AndroidX.Migration packages are installed

3.10.3 and older crash stacktrace

Java.Lang.NoSuchFieldError: no type "Landroid/support/v4/app/NotificationCompat$Extender;" found and so no field "extender" could be found in class "Lcom/onesignal/NotificationExtenderService$OverrideSettings;" or its superclasses ---> Java.Lang.ClassNotFoundException: Didn't find class "android.support.v4.app.NotificationCompat$Extender" on path: DexPathList[[zip file "/data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/base.apk"],nativeLibraryDirectories=[/data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/lib/arm, /data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
--- End of inner exception stack trace ---
at Java.Interop.JniEnvironment+InstanceFields.GetFieldID (Java.Interop.JniObjectReference type, System.String name, System.String signature) [0x0005b] in <8b3b636835d84984ba4604c1f57b1983>:0
at Java.Interop.JniType.GetInstanceField (System.String name, System.String signature) [0x0000c] in <8b3b636835d84984ba4604c1f57b1983>:0
at Java.Interop.JniPeerMembers+JniInstanceFields.GetFieldInfo (System.String encodedMember) [0x00036] in <8b3b636835d84984ba4604c1f57b1983>:0
at Java.Interop.JniPeerMembers+JniInstanceFields.SetValue (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniObjectReference value) [0x00006] in <8b3b636835d84984ba4604c1f57b1983>:0
at Com.OneSignal.Android.NotificationExtenderService+OverrideSettings.set_Extender (AndroidX.Core.App.NotificationCompat+IExtender value) [0x00007] in /Users/josh/Documents/repos/OneSignal-Xamarin-SDK/OneSignal.Android.Binding/obj/Release/generated/src/Com.OneSignal.Android.NotificationExtenderService.cs:54
at CampusMobile.Droid.Services.OneSignalNotificationExtenderService.OnNotificationProcessing (Com.OneSignal.Android.OSNotificationReceivedResult p0) [0x0001f] in /Users/m/dev/repo/campus-mobile-xf/CampusMobile/CampusMobile/CampusMobile.Android/Services/OneSignalNotificationExtenderService.cs:27
at Com.OneSignal.Android.NotificationExtenderService.n_OnNotificationProcessing_Lcom_onesignal_OSNotificationReceivedResult_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_p0) [0x00011] in /Users/josh/Documents/repos/OneSignal-Xamarin-SDK/OneSignal.Android.Binding/obj/Release/generated/src/Com.OneSignal.Android.NotificationExtenderService.cs:295
at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.104(intptr,intptr,intptr)
--- End of managed Java.Lang.NoSuchFieldError stack trace ---
java.lang.NoSuchFieldError: no type "Landroid/support/v4/app/NotificationCompat$Extender;" found and so no field "extender" could be found in class "Lcom/onesignal/NotificationExtenderService$OverrideSettings;" or its superclasses
at crc64fee1e6eafa1c956b.OneSignalNotificationExtenderService.n_onNotificationProcessing(Native Method)
at crc64fee1e6eafa1c956b.OneSignalNotificationExtenderService.onNotificationProcessing(OneSignalNotificationExtenderService.java:30)
at com.onesignal.NotificationExtenderService.processJsonObject(NotificationExtenderService.java:170)
at com.onesignal.NotificationExtenderService.processIntent(NotificationExtenderService.java:155)
at com.onesignal.NotificationExtenderService.onHandleWork(NotificationExtenderService.java:123)
at com.onesignal.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:439)
at com.onesignal.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:430)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.app.NotificationCompat$Extender" on path: DexPathList[[zip file "/data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/base.apk"],nativeLibraryDirectories=[/data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/lib/arm, /data/app/com.tawasal.campus.mobile-O1CPsJ29_qaKpD3YgqcOmw==/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)

@akaitrade
Copy link

Did you find a solution for this problem because i am having exactly the same problem and i can't find anything about this extender service ?

Also the new 4.0 SDK Beta does not have any explanations at all regarding this topic

@tanaynigam
Copy link
Contributor

@lltwist Thanks for reporting the issue. We'll be looking into it shortly to see if this is possible with the current OneSignal 4.x.x SDK. If it is we will create a guide for this, if it requires some SDK changes this will take us a bit more to get a working solution.

@Acilec
Copy link

Acilec commented Nov 24, 2022

Any news on this?

Im using OneSignalSDK.Xamarin 4.1.3 and would like to receive remote push messages in the background.

@tmijieux
Copy link

tmijieux commented Dec 1, 2023

It looks like NotificationExtender is not available in the code with the new version OneSignalSDK.Xamarin; OneSignalSDK.Xamarin.Core;

while it was in the old deprecated lib Com.OneSignal

This is a rather big issue with my app also because i had a feature where i sent a notification just to wake up the app without displaying any notification band and without playing any sound in the Android UI. Without a customizable service the default behavior of the OneSignal default service is to display the notification.

Is there an alternative? does the native lib paradigm changed so that it cannot be translated anymore in Xamarin ?
If not would you be accepting pull request for this ?

@brismithers

It looks like there are a lot of issues that occurs when handling notification after a cold start that could be resolved with the customizable service.

@brismithers
Copy link
Contributor

I believe since v4 of the SDK (and v5 of the .NET SDK, which supports both Xamarin and .NET 6+) rely on the service extension documented here for v4 and here for v5. Unfortunately we do not have a .NET-specific solution, but you should be able to create a native Notification Service Extension and implement your logic in java/kotlin.

The primary reason we do not have a .NET-specific solution is the native Android SDK instantiates the class defined in your AndroidManifest.xml using reflection (if interested). We have not yet been able to come up with an elegant way for the Android native/.NET SDK to instantiate and call your Notification Service Extension within the Xamarin runtime (xamarin creates dynamic package names are dynamic, here's some docs describing how you can define an Activity with a predictable name that can be referenced in the AndroidManifest.xml).

We would absolutely be receptive to ideas from the Xamarin/.NET community on how best to tackle this to make it easier to get control on cold start, as we realize this is a common scenario and "going native" is not ideal.

@tmijieux
Copy link

tmijieux commented Dec 1, 2023

EDIT: TL:DR I heavily edited this because my first comment was messy, and will try to come up with a PR before commenting further.

This was the way it used to work

    <service android:name="com.my.app.NotificationExtender" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="false">
      <intent-filter>
	<action android:name="com.onesignal.NotificationExtender" />
      </intent-filter>
    </service>
using System;
using Android.App;
using Android.Content;
using Com.OneSignal.Android;
using Serilog;

namespace MyApp.Droid
{
    [Service(Name = "com.my.app.NotificationExtender")]
    public class NotificationExtender : NotificationExtenderService
    {
        protected override void OnHandleIntent(Intent intent) { }

        protected override bool OnNotificationProcessing(OSNotificationReceivedResult receivedResult)
        {
            if (receivedResult == null
                || receivedResult.Payload == null
                || receivedResult.Payload.AdditionalData == null)
            {
                return false;
            }
            var payload = receivedResult.Payload;
            bool ret = false;
            try
            {
                var discard = payload.AdditionalData.Get("silent");
                if (discard != null)
                {
                    ret = true;
                }
                payload.AdditionalData.Put("datetimeReceived", (string)DateTime.UtcNow.ToString("o"));
            }
            catch (Exception /*e*/)
            {
            }
            return ret;
        }
    }
}

we can specify a predictable name for the service with the name property of the Service attribute:
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/services/creating-a-service/

this class used to be mapped using the android binding project
https://github.com/OneSignal/OneSignal-Android-SDK/blob/feb29f16af5b7ab9c731399d78b95030f66d77ea/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationExtenderService.java#L116C31-L116C55

(we can see it in the jar that is in the aar)
https://github.com/OneSignal/OneSignal-Xamarin-SDK/tree/3.10.6/OneSignal.Android.Binding/Jars

the only thing i believe we need is an abstract base class that implements the "new" INotificationServiceExtension in java world so that we can reference it from android binding project and generate ACW

and basically i believe that with this setup, even if you instanciate with introspection from javaworld the predictable name will exist as a "ACW" class in javaworld , instanciating this class should automatically instanciate the peer object in dotnet world and call dotnet methods when called from java.

@tmijieux
Copy link

tmijieux commented Dec 2, 2023

Hi,@brismithers i submitted this PR #381 regarding what we discussed. Could you check if this would do the trick for you ?

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

6 participants