Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #690 from OneSignal/AddOneSignalIdAndExternalId
Browse files Browse the repository at this point in the history
Add getters and watchers for oneSignalId and externalId
jinliu9508 committed Feb 23, 2024
2 parents 3094fd4 + 568f935 commit cab901a
Showing 20 changed files with 973 additions and 5 deletions.
13 changes: 13 additions & 0 deletions MIGRATION_GUIDE_v3_to_v5.md
Original file line number Diff line number Diff line change
@@ -99,6 +99,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 += _userStateChanged;

private void _userStateChanged(object sender, UserStateChangedEventArgs e) {
...
}


## Subscriptions

@@ -165,7 +173,12 @@ The user name space is accessible via `OneSignal.User` and provides access to us
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IPushSubscription PushSubscription` | *The push subscription associated to the current user.* |
| `string Language` | *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, empty 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.* |
| `Changed` <br><br> `event EventHandler<UserStateChangedEventArgs> Changed` <br><br> `UserStateChangedEventArgs { UserChangedState State }` | *Adds a change event that will run whenever the onesignalId or externalId has been changed.* |
* |
| `PushSubsription.Changed` <br><br> `event EventHandler<PushSubscriptionChangedEventArgs> Changed` <br><br> `PushSubscriptionChangedEventArgs { PushSubscriptionChangedState State }` | *Adds a change event that will run whenever the push subscription 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(Dictionary<string, string> aliases)` | S*et 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.* |
4 changes: 4 additions & 0 deletions OneSignalExample/Assets/OneSignal/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- iOS crash when calling OneSignal.User.PushSubscription.Id and OneSignal.User.PushSubscription.Token when they are null.
### Changed
- Add public getters for OneSignalId and ExternalId in the User namespace
- Add public event handler OneSignal.User.Changed that fires when the OneSignalId or ExternalId changes
- Updated included Android SDK to [5.1.4](https://github.com/OneSignal/OneSignal-Android-SDK/releases/tag/5.1.4)

## [5.0.6]
### Fixed
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
using OneSignalSDK;
using OneSignalSDK.Notifications;
using OneSignalSDK.InAppMessages;
using OneSignalSDK.User;
using OneSignalSDK.User.Models;
using OneSignalSDK.Debug.Models;
using OneSignalSDK.Debug.Utilities;
@@ -159,6 +160,7 @@ private void Start() {

// Setup the below to listen for and respond to state changes
OneSignal.User.PushSubscription.Changed += _pushSubscriptionChanged;
OneSignal.User.Changed += _userStateChanged;
}

/*
@@ -211,6 +213,11 @@ private void _pushSubscriptionChanged(object sender, PushSubscriptionChangedEven
_log($"Push subscription changed to current: {JsonUtility.ToJson(e.State.Current)}");
}

private void _userStateChanged(object sender, UserStateChangedEventArgs e) {
_log($"OneSignalId changed : {e.State.Current.OneSignalId}");
_log($"ExternalId changed : {e.State.Current.ExternalId}");
}

/*
* SDK setup
*/
@@ -298,6 +305,16 @@ public void RemoveAlias() {
OneSignal.User.RemoveAlias(aliasKey);
}

public void GetOneSignalId() {
string onesignalId = OneSignal.User.OneSignalId;
_log($"Get OneSignalId <b>{onesignalId}</b>");
}

public void GetExternalId() {
string externalId = OneSignal.User.ExternalId;
_log($"Get ExternalId <b>{externalId}</b>");
}

/*
* Push
*/
594 changes: 593 additions & 1 deletion OneSignalExample/Assets/OneSignal/Example/OneSignalExampleScene.unity

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ apply plugin: 'com.android.library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Android Resolver Dependencies Start
implementation 'com.onesignal:OneSignal:5.1.2' // Packages/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml:6
implementation 'com.onesignal:OneSignal:5.1.4' // Packages/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml:6
// Android Resolver Dependencies End
**DEPS**}

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<dependencies>
<packages>
<package>com.onesignal:OneSignal:5.1.2</package>
<package>com.onesignal:OneSignal:5.1.4</package>
</packages>
<files />
<settings>
Original file line number Diff line number Diff line change
@@ -3,6 +3,6 @@
<repositories>
<repository>https://repo.maven.apache.org/maven2</repository>
</repositories>
<androidPackage spec="com.onesignal:OneSignal:5.1.2" />
<androidPackage spec="com.onesignal:OneSignal:5.1.4" />
</androidPackages>
</dependencies>
35 changes: 35 additions & 0 deletions com.onesignal.unity.android/Runtime/AndroidUserManager.cs
Original file line number Diff line number Diff line change
@@ -27,8 +27,10 @@


using UnityEngine;
using System;
using System.Collections.Generic;
using OneSignalSDK.User;
using OneSignalSDK.User.Internal;
using OneSignalSDK.User.Models;
using OneSignalSDK.Android.User.Models;
using OneSignalSDK.Android.Utilities;
@@ -37,12 +39,21 @@ namespace OneSignalSDK.Android.User {
internal sealed class AndroidUserManager : IUserManager {
private readonly AndroidJavaObject _user;
private AndroidPushSubscription _pushSubscription;
public event EventHandler<UserStateChangedEventArgs> Changed;

public AndroidUserManager(AndroidJavaClass sdkClass) {
_user = sdkClass.CallStatic<AndroidJavaObject>("getUser");
_pushSubscription = new AndroidPushSubscription(_user);
}

public string OneSignalId {
get => _user.Call<string>("getOnesignalId");
}

public string ExternalId {
get => _user.Call<string>("getExternalId");
}

public IPushSubscription PushSubscription {
get => _pushSubscription;
}
@@ -93,7 +104,31 @@ public void RemoveSms(string sms)
=> _user.Call("removeSms", sms);

public void Initialize() {
_user.Call("addObserver", new InternalUserChangedHandler(this));
_pushSubscription.Initialize();
}

private sealed class InternalUserChangedHandler : OneSignalAndroidJavaProxy {
private AndroidUserManager _parent;

public InternalUserChangedHandler(AndroidUserManager userManager) : base("user.state.IUserStateObserver") {
_parent = userManager;
}

/// <param name="state">UserChangedState</param>
public void onUserStateChange(AndroidJavaObject state) {
var currentJO = state.Call<AndroidJavaObject>("getCurrent");
var current = currentJO.ToSerializable<UserState>();

UserChangedState userChangedState = new UserChangedState(current);
UserStateChangedEventArgs args = new UserStateChangedEventArgs(userChangedState);

EventHandler<UserStateChangedEventArgs> handler = _parent.Changed;
if (handler != null)
{
UnityMainThreadDispatch.Post(state => handler(_parent, args));
}
}
}
}
}
11 changes: 11 additions & 0 deletions com.onesignal.unity.core/Editor/Platform/UserManager.cs
Original file line number Diff line number Diff line change
@@ -25,11 +25,22 @@
* THE SOFTWARE.
*/

using System;
using System.Collections.Generic;
using OneSignalSDK.User.Models;

namespace OneSignalSDK.User {
internal sealed class UserManager : IUserManager {
public string OneSignalId {
get => "";
}

public string ExternalId {
get => "";
}

public event EventHandler<UserStateChangedEventArgs> Changed;

private PushSubscription _subscription = new PushSubscription();

public IPushSubscription PushSubscription {
33 changes: 33 additions & 0 deletions com.onesignal.unity.core/Runtime/User/IUserManager.cs
Original file line number Diff line number Diff line change
@@ -25,10 +25,25 @@
* THE SOFTWARE.
*/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using OneSignalSDK.User.Models;

namespace OneSignalSDK.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;
}
}

/// <summary>
/// The OneSignal user manager is responsible for managing the current user state. When
/// an app starts up for the first time, it is defaulted to having a guest user that is only
@@ -46,6 +61,24 @@ namespace OneSignalSDK.User {
/// 2. When the identity of the user is lost (i.e. a logout)
/// </summary>
public interface IUserManager {
/// <summary>
/// The UUID generated by OneSignal to represent a user, empty 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 empty 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>
/// The 2-character language either as a detected language or explicitly set for this user. See
/// https://documentation.onesignal.com/docs/language-localization#what-languages-are-supported
46 changes: 46 additions & 0 deletions com.onesignal.unity.core/Runtime/User/Internal/UserState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Modified MIT License
*
* Copyright 2023 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using OneSignalSDK.User;

namespace OneSignalSDK.User.Internal {
[Serializable] public sealed class UserState {
public string OneSignalId => onesignalId;
public string ExternalId => externalId;

#region Native Field Handling
public string onesignalId;
public string externalId;
#endregion

public UserState(string onesignalId, string externalId) {
this.onesignalId = onesignalId;
this.externalId = externalId;
}
}
}
11 changes: 11 additions & 0 deletions com.onesignal.unity.core/Runtime/User/Internal/UserState.cs.meta
Original file line number Diff line number Diff line change
@@ -25,10 +25,10 @@
* THE SOFTWARE.
*/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using System;

namespace OneSignalSDK.User.Models {
/// <summary>
46 changes: 46 additions & 0 deletions com.onesignal.unity.core/Runtime/User/Models/IUserState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Modified MIT License
*
* Copyright 2023 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;

namespace OneSignalSDK.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; }
}
}
11 changes: 11 additions & 0 deletions com.onesignal.unity.core/Runtime/User/Models/IUserState.cs.meta
39 changes: 39 additions & 0 deletions com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Modified MIT License
*
* Copyright 2023 OneSignal
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* 2. All copies of substantial portions of the Software may only be used in connection
* with services provided by OneSignal.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using OneSignalSDK.User.Internal;

namespace OneSignalSDK.User {
public sealed class UserChangedState {
public UserState Current { get; }

public UserChangedState(UserState state) {
Current = state;
}
}
}
Original file line number Diff line number Diff line change
@@ -159,6 +159,7 @@ private void Start() {

// Setup the below to listen for and respond to state changes
OneSignal.User.PushSubscription.Changed += _pushSubscriptionChanged;
OneSignal.User.Changed += _userStateChanged;
}

/*
@@ -211,6 +212,11 @@ private void _pushSubscriptionChanged(object sender, PushSubscriptionChangedEven
_log($"Push subscription changed to current: {JsonUtility.ToJson(e.State.Current)}");
}

private void _userStateChanged(object sender, UserStateChangedEventArgs e) {
_log($"OneSignalId changed : {JsonUtility.ToJson(e.State.Current.OneSignalId)}");
_log($"ExternalId changed : {JsonUtility.ToJson(e.State.Current.ExternalId)}");
}

/*
* SDK setup
*/
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
#import "OneSignalBridgeUtil.h"

typedef void (*StateListenerDelegate)(const char* current, const char* previous);
typedef void (*UserStateListenerDelegate)(const char* current);

/*
* Helpers
@@ -78,6 +79,45 @@ - (void)onPushSubscriptionDidChangeWithState:(OSPushSubscriptionChangedState*)st

@end

/*
* User state observer singleton for global callbacks
*/

@interface OneSignalUserStateObserver : NSObject <OSUserStateObserver>

+ (instancetype) sharedUserObserver;
@property UserStateListenerDelegate userStateDelegate;

@end

@implementation OneSignalUserStateObserver

+ (instancetype) sharedUserObserver {
static dispatch_once_t pred = 0;
static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}

- (instancetype) init {
if (self = [super init]) {
[OneSignal.User addObserver:self];
}

return self;
}

- (void)onUserStateDidChangeWithState:(OSUserChangedState*)state {
if (_userStateDelegate != nil) {
auto curr = oneSignalJsonStringFromDictionary([[state current] jsonRepresentation]);
_userStateDelegate(curr);
}
}

@end

/*
* Bridge methods
* We use strdup because Unity attempts to free the memory after we return the value
@@ -160,6 +200,20 @@ void _oneSignalUserRemoveTags(const char* tagsJson) {
[OneSignal.User removeTags:tags];
}

const char* _oneSignalUserGetOneSignalId(){
if (OneSignal.User.OneSignalId == NULL) {
return NULL;
}
return strdup([OneSignal.User.OneSignalId UTF8String]);
}

const char* _oneSignalUserGetExternalId(){
if (OneSignal.User.ExternalId == NULL) {
return NULL;
}
return strdup([OneSignal.User.ExternalId UTF8String]);
}

const char* _oneSignalPushSubscriptionGetId() {
if (OneSignal.User.pushSubscription.id == NULL) {
return NULL;
@@ -189,4 +243,8 @@ void _oneSignalPushSubscriptionOptOut() {
void _oneSignalPushSubscriptionAddStateChangedCallback(StateListenerDelegate callback) {
[[OneSignalUserObserver sharedUserObserver] setPushSubscriptionDelegate:callback];
}

void _oneSignalUserAddStateChangedCallback(UserStateListenerDelegate callback) {
[[OneSignalUserStateObserver sharedUserObserver] setUserStateDelegate:callback];
}
}
35 changes: 35 additions & 0 deletions com.onesignal.unity.ios/Runtime/iOSUserManager.cs
Original file line number Diff line number Diff line change
@@ -27,14 +27,18 @@


using UnityEngine;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using OneSignalSDK.User;
using OneSignalSDK.User.Internal;
using OneSignalSDK.User.Models;
using OneSignalSDK.iOS.User.Models;

namespace OneSignalSDK.iOS.User {
internal sealed class iOSUserManager : IUserManager {
[DllImport("__Internal")] private static extern string _oneSignalUserGetOneSignalId();
[DllImport("__Internal")] private static extern string _oneSignalUserGetExternalId();
[DllImport("__Internal")] private static extern void _oneSignalUserSetLanguage(string languageCode);
[DllImport("__Internal")] private static extern void _oneSignalUserAddAlias(string aliasLabel, string aliasId);
[DllImport("__Internal")] private static extern void _oneSignalUserAddAliases(string aliasesJson);
@@ -49,13 +53,29 @@ internal sealed class iOSUserManager : IUserManager {
[DllImport("__Internal")] private static extern void _oneSignalUserAddTags(string tagsJson);
[DllImport("__Internal")] private static extern void _oneSignalUserRemoveTag(string key);
[DllImport("__Internal")] private static extern void _oneSignalUserRemoveTags(string tagsJson);
[DllImport("__Internal")] private static extern void _oneSignalUserAddStateChangedCallback(UserStateListenerDelegate callback);

public delegate void UserStateListenerDelegate(string current);

public event EventHandler<UserStateChangedEventArgs> Changed;

private iOSPushSubscription _pushSubscription;

private static iOSUserManager _instance;

public iOSUserManager() {
_instance = this;
_pushSubscription = new iOSPushSubscription();
}

public string OneSignalId {
get => _oneSignalUserGetOneSignalId();
}

public string ExternalId {
get => _oneSignalUserGetExternalId();
}

public IPushSubscription PushSubscription {
get => _pushSubscription;
}
@@ -109,6 +129,21 @@ public void RemoveSms(string sms)

public void Initialize() {
_pushSubscription.Initialize();
_oneSignalUserAddStateChangedCallback(_onUserStateChanged);
}

[AOT.MonoPInvokeCallback(typeof(UserStateListenerDelegate))]
private static void _onUserStateChanged(string current) {
var curr = JsonUtility.FromJson<UserState>(current);

UserChangedState userChangedState = new UserChangedState(curr);
UserStateChangedEventArgs args = new UserStateChangedEventArgs(userChangedState);

EventHandler<UserStateChangedEventArgs> handler = _instance.Changed;
if (handler != null)
{
UnityMainThreadDispatch.Post(state => handler(_instance, args));
}
}
}
}

0 comments on commit cab901a

Please sign in to comment.