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

Add OneSignalId and ExternalId getters as well as a user changed observer #98

Merged
merged 8 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ Once (or if) the user is no longer identifiable in your app (i.e. they logged ou

Logging out has the affect of reverting to a “device-scoped” user, which is the new owner of the device’s push subscription.

To observe changes to the onesignalId or externalId you can add a custom method to the event:

OneSignal.User.Changed += User_Changed;

private void User_Changed(object sender, OneSignalSDK.DotNet.Core.User.UserStateChangedEventArgs e) {
var user = e.State.Current;
...
}

## Subscriptions

Expand Down Expand Up @@ -157,7 +165,10 @@ The user name space is accessible via `OneSignal.User` and provides access to us
| **C#** | **Description** |
| ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IPushSubscription PushSubscription { get; }` | *The push subscription associated to the current user.* |
| `string Language { set; }` | *Set the 2-character language either as a detected language or explicitly set for this user.* |
| `string Language { set; }` | *Set the 2-character language either as a detected language or explicitly set for this user.*
| `string OneSignalId` | *The UUID generated by OneSignal to represent a user, null if this is currently unavailable.* |
| `string ExternalId` | *The External ID is OneSignal's default and recommended alias label. This should be the mainidentifier you use to identify users. It is set when calling the [OneSignal.login] method. Return null if this is currently unavailable.*
| `event EventHandler<UserStateChangedEventArgs> Changed` | *Adds a change event that will run whenever the onesignalId or externalId has been changed.*
| `void AddAlias(string label, string id)` | *Set an alias for the current user. If this alias already exists it will be overwritten.* |
| `void AddAliases(IDictionary<string, string> aliases)` | *Set aliases for the current user. If any alias already exists it will be overwritten.* |
| `void RemoveAlias(string label)` | *Remove an alias from the current user.* |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<attr path="/api/package[@name='com.onesignal.session']" name="managedName">Com.OneSignal.Android.Session</attr>
<attr path="/api/package[@name='com.onesignal.user']" name="managedName">Com.OneSignal.Android.User</attr>
<attr path="/api/package[@name='com.onesignal.user.subscriptions']" name="managedName">Com.OneSignal.Android.User.Subscriptions</attr>
<attr path="/api/package[@name='com.onesignal.user.state']" name="managedName">Com.OneSignal.Android.User.State</attr>

<remove-node path="/api/package[starts-with(@name, 'com.onesignal.common.events')]" />
<remove-node path="/api/package[starts-with(@name, 'com.onesignal.common.exceptions')]" />
Expand Down
52 changes: 52 additions & 0 deletions OneSignalSDK.DotNet.Android/AndroidUserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,33 @@ public string Language

public IPushSubscription PushSubscription { get; } = new AndroidPushSubscription();

private InternalUserChangedHandler? _userChangedHandler;

public void Initialize()
{
_userChangedHandler = new InternalUserChangedHandler(this);
OneSignalNative.User.AddObserver(_userChangedHandler);
((AndroidPushSubscription)PushSubscription).Initialize();
}

public string OneSignalId
{
get {
string id = OneSignalNative.User.OnesignalId;
return string.IsNullOrEmpty(id)? null : id;
}
}

public string ExternalId
{
get {
string id = OneSignalNative.User.ExternalId;
return string.IsNullOrEmpty(id)? null : id;
}
}

public event EventHandler<UserStateChangedEventArgs> Changed;

public void AddAlias(string label, string id) => OneSignalNative.User.AddAlias(label, id);
public void AddAliases(IDictionary<string, string> aliases) => OneSignalNative.User.AddAliases(aliases);
public void RemoveAlias(string label) => OneSignalNative.User.RemoveAlias(label);
Expand All @@ -36,6 +58,35 @@ public void Initialize()
public void RemoveTag(string key) => OneSignalNative.User.RemoveTag(key);
public void RemoveTags(params string[] keys) => OneSignalNative.User.RemoveTags(keys);
public IDictionary<string, string> GetTags() => OneSignalNative.User.Tags;

private sealed class InternalUserState : IUserState
{
public string OneSignalId { get; }

public string ExternalId { get; }

public InternalUserState(string onesignalId, string externalId)
{
OneSignalId = onesignalId;
ExternalId = externalId;
}
}

private class InternalUserChangedHandler : Java.Lang.Object, Com.OneSignal.Android.User.State.IUserStateObserver
{
private AndroidUserManager _manager;
public InternalUserChangedHandler(AndroidUserManager manager)
{
_manager = manager;
}

public void OnUserStateChange(Com.OneSignal.Android.User.State.UserChangedState state)
{
var current = new InternalUserState(state.Current.OnesignalId, state.Current.ExternalId);
var userChangedState = new UserChangedState(current);
_manager.Changed?.Invoke(_manager, new UserStateChangedEventArgs(userChangedState));
}
}
}

public class AndroidPushSubscription : IPushSubscription
Expand Down Expand Up @@ -99,5 +150,6 @@ public void OnPushSubscriptionChange(Com.OneSignal.Android.User.Subscriptions.Pu
_manager.Changed?.Invoke(_manager, new PushSubscriptionChangedEventArgs(changedState));
}
}

}
}
18 changes: 18 additions & 0 deletions OneSignalSDK.DotNet.Core/User/IUserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ public interface IUserManager
/// </summary>
IPushSubscription PushSubscription { get; }

/// <summary>
/// The UUID generated by OneSignal to represent a user, null if this is currently unavailable.
/// </summary>
string OneSignalId { get; }

/// <summary>
/// The External ID is OneSignal's default and recommended alias label. This should be the main
/// identifier you use to identify users. It is set when calling the [OneSignal.login] method.
///
/// This is null if the External ID has not been set.
/// </summary>
string ExternalId { get; }

/// <summary>
/// When onesignalId or externalId has changed
/// </summary>
event EventHandler<UserStateChangedEventArgs> Changed;

/// <summary>
/// Set an alias for the current user. If this alias already exists it will be overwritten.
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions OneSignalSDK.DotNet.Core/User/IUserState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace OneSignalSDK.DotNet.Core.User
{
public interface IUserState {
/// <summary>
/// The unique identifier for your OneSignal account. This will be an empty string until the
/// user has been successfully logged in on the backend and assigned an ID.
/// Use [Changed] to be notified when the [OneSignalId] has been successfully assigned.
/// </summary>
string OneSignalId { get; }

/// <summary>
/// The external identifier that you use to identify users. Use [Changed] to be notified
/// when the [ExternalId] has been successfully assigned. This will be an empty string if no
/// external identifier has been assigned to the associated [OneSignalId].
/// </summary>
string ExternalId { get; }
}
}
24 changes: 24 additions & 0 deletions OneSignalSDK.DotNet.Core/User/UserStateChangedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace OneSignalSDK.DotNet.Core.User
{
/// <summary>
/// Several states associated with the SDK can be changed in and outside of the application.
/// </summary>
public class UserStateChangedEventArgs : EventArgs
{
public UserChangedState State { get; }

public UserStateChangedEventArgs(UserChangedState state) {
State = state;
}
}

public sealed class UserChangedState {
public IUserState Current { get; }

public UserChangedState(IUserState state) {
Current = state;
}
}
}
74 changes: 74 additions & 0 deletions OneSignalSDK.DotNet.iOS.Binding/ApiDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,60 @@ interface OSPushSubscription
void RemoveObserver(OSPushSubscriptionObserver observer);
}

// @interface OSUserState : NSObject
[BaseType (typeof(NSObject), Name = "_TtC13OneSignalUser11OSUserState")]
[DisableDefaultCtor]
interface OSUserState
{
// @property (readonly, copy, nonatomic) NSString * _Nullable onesignalId;
[NullAllowed, Export ("onesignalId")]
string OnesignalId { get; }

// @property (readonly, copy, nonatomic) NSString * _Nullable externalId;
[NullAllowed, Export ("externalId")]
string ExternalId { get; }

// @property (readonly, copy, nonatomic) NSString * _Nonnull description;
[Export ("description")]
string Description { get; }

// -(NSDictionary * _Nonnull)jsonRepresentation __attribute__((warn_unused_result("")));
[Export ("jsonRepresentation")]
//[Verify (MethodToProperty)]
NSDictionary JsonRepresentation { get; }
}

// @interface OSUserChangedState : NSObject
[BaseType (typeof(NSObject), Name = "_TtC13OneSignalUser18OSUserChangedState")]
[DisableDefaultCtor]
interface OSUserChangedState
{
// @property (readonly, nonatomic, strong) OSUserState * _Nonnull current;
[Export ("current", ArgumentSemantic.Strong)]
OSUserState Current { get; }

// @property (readonly, copy, nonatomic) NSString * _Nonnull description;
[Export ("description")]
string Description { get; }

// -(NSDictionary * _Nonnull)jsonRepresentation __attribute__((warn_unused_result("")));
[Export ("jsonRepresentation")]
//[Verify (MethodToProperty)]
NSDictionary JsonRepresentation { get; }
}

// @protocol OSUserStateObserver
[Protocol (Name = "_TtP13OneSignalUser19OSUserStateObserver_")]
[Model]
[BaseType(typeof(NSObject))]
interface OSUserStateObserver
{
// @required -(void)onUserStateDidChangeWithState:(OSUserChangedState * _Nonnull)state;
//[Abstract]
[Export ("onUserStateDidChangeWithState:")]
void OnUserStateDidChangeWithState (OSUserChangedState state);
}

// @protocol OSUser
[Protocol(Name = "_TtP13OneSignalUser6OSUser_")]
[BaseType(typeof(NSObject))]
Expand All @@ -454,6 +508,26 @@ interface OSUser
[Export ("pushSubscription", ArgumentSemantic.Strong)]
OSPushSubscription PushSubscription { get; }

// @required @property (readonly, copy, nonatomic) NSString * _Nullable onesignalId;
//[Abstract]
[NullAllowed, Export ("onesignalId")]
string OnesignalId { get; }

// @required @property (readonly, copy, nonatomic) NSString * _Nullable externalId;
//[Abstract]
[NullAllowed, Export ("externalId")]
string ExternalId { get; }

// @required -(void)addObserver:(id<OSUserStateObserver> _Nonnull)observer;
//[Abstract]
[Export ("addObserver:")]
void AddObserver (OSUserStateObserver observer);

// @required -(void)removeObserver:(id<OSUserStateObserver> _Nonnull)observer;
[Abstract]
[Export ("removeObserver:")]
void RemoveObserver (OSUserStateObserver observer);

// @required -(void)addAliasWithLabel:(NSString * _Nonnull)label id:(NSString * _Nonnull)id;
//[Abstract]
[Export ("addAliasWithLabel:id:")]
Expand Down
44 changes: 44 additions & 0 deletions OneSignalSDK.DotNet.iOS/iOSUserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,26 @@ public string Language

public IPushSubscription PushSubscription { get; } = new iOSPushSubscription();

private InternalUserChangedHandler _userChangedHandler;

public void Initialize()
{
_userChangedHandler = new InternalUserChangedHandler(this);
OneSignalNative.User.AddObserver(_userChangedHandler);
((iOSPushSubscription)PushSubscription).Initialize();
}

public string OneSignalId
{
get => OneSignalNative.User.OnesignalId;
}

public string ExternalId
{
get => OneSignalNative.User.ExternalId;
}
public event EventHandler<UserStateChangedEventArgs>? Changed;

public void AddAlias(string label, string id) => OneSignalNative.User.AddAliasWithLabel(label, id);
public void AddAliases(IDictionary<string, string> aliases) => OneSignalNative.User.AddAliases(NativeConversion.DictToNSDict(aliases));
public void RemoveAlias(string label) => OneSignalNative.User.RemoveAlias(label);
Expand All @@ -39,6 +54,35 @@ public void Initialize()
public void RemoveTag(string key) => OneSignalNative.User.RemoveTag(key);
public void RemoveTags(params string[] keys) => OneSignalNative.User.RemoveTags(keys);
public IDictionary<string, string> GetTags() => FromNativeConversion.NSDictToPureStringDict(OneSignalNative.User.GetTags());

private sealed class InternalUserState : IUserState
{
public string OneSignalId { get; }

public string ExternalId { get; }

public InternalUserState(string onesignalId, string externalId)
{
OneSignalId = onesignalId;
ExternalId = externalId;
}
}

private class InternalUserChangedHandler : Com.OneSignal.iOS.OSUserStateObserver
{
private iOSUserManager _manager;
public InternalUserChangedHandler(iOSUserManager manager)
{
_manager = manager;
}

public override void OnUserStateDidChangeWithState(OSUserChangedState state)
{
var current = new InternalUserState(state.Current.OnesignalId, state.Current.ExternalId);
var userChangedState = new UserChangedState(current);
_manager.Changed?.Invoke(_manager, new UserStateChangedEventArgs(userChangedState));
}
}
}

public class iOSPushSubscription : IPushSubscription
Expand Down
8 changes: 8 additions & 0 deletions Samples/OneSignalApp/Models/MainPageModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Windows.Input;
using OneSignalSDK.DotNet;
using OneSignalSDK.DotNet.Core.Debug;
using OneSignalSDK.DotNet.Core.User;
using OneSignalSDK.DotNet.Core.User.Subscriptions;

namespace OneSignalApp.Models
Expand Down Expand Up @@ -190,6 +191,7 @@ public MainPageModel(Page page)

OneSignal.Initialize(_appId);

OneSignal.User.Changed += User_Changed;
OneSignal.User.PushSubscription.Changed += PushSubscription_Changed;
OneSignal.Notifications.PermissionChanged += Notifications_PermissionChanged;
OneSignal.Notifications.Clicked += Notifications_Clicked;
Expand All @@ -208,6 +210,12 @@ public MainPageModel(Page page)
PushSubscriptionId = OneSignal.User.PushSubscription.Id;
}

private void User_Changed(object sender, OneSignalSDK.DotNet.Core.User.UserStateChangedEventArgs e)
{
var user = e.State.Current;
Debug.WriteLine($"User has changed: OneSignalId=${user.OneSignalId}, ExternalId={user.ExternalId}");
}

private void InAppMessages_Clicked(object sender, OneSignalSDK.DotNet.Core.InAppMessages.InAppMessageClickedEventArgs e)
{
Debug.WriteLine($"IAM clicked: ${e.Result.ActionId}.");
Expand Down
Loading