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

WIP notification service extension service in dotnet #111

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tmijieux
Copy link

@tmijieux tmijieux commented Jun 18, 2024

Description

One Line Summary

add possibilities to use the notification service extension from the dotnet world.

Details

this is based on the work i already done in the "old" xamarin framework
OneSignal/OneSignal-Xamarin-SDK#381

the final usage would be very similar to the one i described in this message:
OneSignal/OneSignal-Xamarin-SDK#381 (comment)
YourApp/Platforms/Android/MyOneSignalServiceExtension.cs :

using AndroidX.Core.App;
using Com.OneSignal.Android;
using Com.OneSignal.Android.Notifications;
using Com.OneSignal.Notifications.Android;
using Org.Json;

namespace YourApp.Platforms.Android
{
    public class MyExtender : NotificationExtenderBase
    {
        private INotification Notification { get; set; }
        public MyExtender(INotification notif)
        {
            Notification = notif;
        }

        public override NotificationCompat.Builder Extend(NotificationCompat.Builder builder)
        {
            //do some logic with Notification to customize the notif,
            return builder
                //.SetContentTitle("coucou1")
                //.SetContentText("hello2")
                /*.AddAction(new NotificationCompat.Action(null, "coucou", null))*/
                ;
        }
    }

    /* this attribute declare a name in java world for the native onesignal lib 
    to be able to call our c# code. Change it with a name fitting for your app!
    Also, in your AndroidManifest.xml add the following tag 
    with name matching the one you choose under the application tag:
        <meta-data android:name="com.onesignal.NotificationServiceExtension" 
                            android:value="com.your.app.MyOneSignalServiceExtension" />
     */
    [NotificationExtension(Name = "com.your.app.MyOneSignalServiceExtension")]
    public class MyOneSignalServiceExtension : NotificationServiceExtenderBase
    {
        public bool SomeLogicOn(IDisplayableMutableNotification notif, JSONObject additionalData)
        {
            /* implement your logic here if appropriate for your app */
            return false;
        }

        public override void OnNotificationReceived(INotificationReceivedEvent ev)
        {
            var notif = ev.Notification;
            notif.SetExtender(new MyExtender(notif));

            /* example of logic usage to choose to hide the notif or not: */
            bool hideNotif = SomeLogicOn(notif, notif.AdditionalData);

            if (hideNotif)
            {
                ev.PreventDefault();
            }
            else
            {
                notif.Display();
            }
        }
    }
}

I did not yet test this usage because i still have dependencies issues, but it used to work in a similar way on the xamarin version.

the main point of this pull-request are:

  • i add a dependency on AndroidX.Core in the onesignal core binding library because some types used in the onesignal core binding comes from AndroidX and without this reference the binding are not generated for these API (the main type required here is NotificationCompat.IExtender that allow us to customize our notification the the extender through the IDisplayableNotification.setExtender method , without adding this dependency the method setExtender is not generated in the interface )

This dependency is the main reason this MR is still WIP. After adding this dependency, there are lots of conflicts in the final app, stuff about some classes being defined multiple times , some others classes are missing at runtime etc ... If someone is willing to bring help on this point this would be very welcome. In the end, I had to add a lot of dependency just for it to build and i think this is probably too much there must be a dependency/version combination that is optimal and should work in most case but i did not find it yet.

  • I add an attribute NotificationExtensionAttribute that inherits from Java.Interop.IJniNameProviderAttribute that allow us to give a name in the java world (callable wrapper for our c# service extension class) that will allow the java code to find and call our c# code from java world using the metadata defined in manifest. (see this)

  • i add two classes that act as boilerplates helpers base classes that the programmer (library-user) can use as helper if they wants to implement the notificationserviceextender and the notification extender

Motivation

fixes #92 this feature is already available in the android sdk but not working yet in dotnet sdk

Scope

notification service extension

Manual testing

RECOMMEND - OPTIONAL - Explain what scenarios were tested and the environment.
Example: Tested opening a notification while the app was foregrounded, app build with Android Studio 2020.3 with a fresh install of the OneSignal example app on a Pixel 6 with Android 12.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
    • If it is hard to explain how any codes changes are related to each other then it most likely needs to be more than one PR
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
    • Simplify with less code, followed by splitting up code into well named functions and variables, followed by adding comments to the code.
  • I have reviewed this PR myself, ensuring it meets each checklist item
    • WIP (Work In Progress) is ok, but explain what is still in progress and what you would like feedback on. Start the PR title with "WIP" to indicate this.

Copy link
Author

@tmijieux tmijieux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this review is an explanation of my code

@@ -55,6 +55,7 @@
<LibraryProjectZip Include="Jars\core-release.aar" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.12.0.4" />
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need this for the setExtender method on IDisplayableNotification

Comment on lines +5 to +8
public abstract class NotificationExtenderBase : Java.Lang.Object, NotificationCompat.IExtender
{
public abstract NotificationCompat.Builder Extend(NotificationCompat.Builder builder);
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a plumbing class the, main purpose of this class is to inherit Java.Lang.Object to create a peer object and allow programmer to not have to think about peer objects.

Comment on lines +5 to +8
public abstract class NotificationServiceExtenderBase: Java.Lang.Object, Com.OneSignal.Android.Notifications.INotificationServiceExtension
{
public abstract void OnNotificationReceived(Com.OneSignal.Android.Notifications.INotificationReceivedEvent ev);
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same idea than the other class.
Inherits from java.lang.object to create peer object, this is meant to be used as base class by the library-user.

Comment on lines +58 to +59
<ProjectReference Include="..\OneSignalSDK.DotNet.Android.Core.Binding\OneSignalSDK.DotNet.Android.Core.Binding.csproj" />
</ItemGroup>
Copy link
Author

@tmijieux tmijieux Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dependency on the core binding project from the notifications binding to get types from the core library that are used in the notifications library. wWthout this, some api were missing, but I cant remember which one exactly at the time i write this comment.
I will re-review this later and check if this is absolutely required or not...

<attr path="/api/package[@name='com.onesignal.notifications']" name="managedName">Com.OneSignal.Android.Notifications</attr>
<attr path="/api/package[@name='com.onesignal.notifications']" name="managedName">Com.OneSignal.Android.Notifications</attr>

<attr path="/api/package[@name='com.onesignal.notifications.internal']/class[@name='Notification']/method[@name='getGroupedNotifications' and count(parameter)=0]" name="return">java.util.List&lt;com.onesignal.notifications.INotification&gt;</attr>
Copy link
Author

@tmijieux tmijieux Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of the new androidx api that were brought in, this api (getGroupedNotifications() ) was not generated before, is now generated.

In the java world , the class implements the interface by returning a list of concrete class (i.e List<com.onesignal.notifications.internal.Notification> while the interface expects a return type of List<com.onesignal.notifications.INotification> ( the internal Notification implements the INotification)

and this kind of polymorphism on the generic parameter of List is not accepted in c# , (i guess this is allowed in java ? ).

this was triggering a compilation error, so i tell the binding generation to replace return type by List in the class( i did not tested it yet ? i dont know if it works yet)

Comment on lines +69 to +72
<PackageReference Include="Xamarin.AndroidX.Collection" Version="1.4.0.1" />
<PackageReference Include="Xamarin.AndroidX.Collection.Ktx" Version="1.4.0.1" />
<PackageReference Include="Xamarin.AndroidX.Activity" Version="1.7.2" />
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2" />
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all this diffs are because of many conflicts i had on this binding library dependencies.
This part is not working yet and is subject to change a lot.

Comment on lines +8 to +16
[Serializable]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class NotificationExtensionAttribute : Attribute, Java.Interop.IJniNameProviderAttribute
{
public string Name { get; set; }
public NotificationExtensionAttribute()
{
}
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the dotnet android team have made these compiling steps where they generate a class in java world from the name specified in any attribute that inherits from IJniNameProviderAttribute,

read the following files for details:

https://github.com/dotnet/java-interop/blob/ccafbe6a102a85efe84ceb210b3b8b93e49edbcb/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs#L314-L320

Comment on lines +4 to 5
<TargetFrameworks>netstandard2.0;net7.0;net7.0-android;net7.0-ios</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the nuget spec file seemed to expect netstandard dlls in this project. i did this because i wanted to test with a locally built nuget.

what to do in details here is up to the maintainer i guess.

Comment on lines +4 to 5
<version>5.1.3.1-alpha.1</version>
<id>OneSignalSDK.DotNet</id>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just bumped here to test with a locally built nuget.
this is not necessarily meant to stay

@aalsamoht
Copy link

Hello @tmijieux I was wondering on the status of the PR.

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

Successfully merging this pull request may close these issues.

[Bug]: Implementing Android INotificationServiceExtension
2 participants