diff --git a/MIGRATION_GUIDE_v3_to_v5.md b/MIGRATION_GUIDE_v3_to_v5.md
index 7ae865c8c..14f190ba4 100644
--- a/MIGRATION_GUIDE_v3_to_v5.md
+++ b/MIGRATION_GUIDE_v3_to_v5.md
@@ -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`
`event EventHandler Changed`
`UserStateChangedEventArgs { UserChangedState State }` | *Adds a change event that will run whenever the onesignalId or externalId has been changed.* |
+* |
| `PushSubsription.Changed`
`event EventHandler Changed`
`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 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.* |
diff --git a/OneSignalExample/Assets/OneSignal/CHANGELOG.md b/OneSignalExample/Assets/OneSignal/CHANGELOG.md
index e85fb57cc..a702f1dc2 100644
--- a/OneSignalExample/Assets/OneSignal/CHANGELOG.md
+++ b/OneSignalExample/Assets/OneSignal/CHANGELOG.md
@@ -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
diff --git a/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleBehaviour.cs b/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleBehaviour.cs
index 8ad01c338..847dfb25d 100644
--- a/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleBehaviour.cs
+++ b/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleBehaviour.cs
@@ -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 {onesignalId}");
+ }
+
+ public void GetExternalId() {
+ string externalId = OneSignal.User.ExternalId;
+ _log($"Get ExternalId {externalId}");
+ }
+
/*
* Push
*/
diff --git a/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleScene.unity b/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleScene.unity
index 8eed5e5ff..1edc6e35b 100644
--- a/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleScene.unity
+++ b/OneSignalExample/Assets/OneSignal/Example/OneSignalExampleScene.unity
@@ -809,6 +809,85 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 111296087}
m_CullTransparentMesh: 1
+--- !u!1 &118443139
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 118443140}
+ - component: {fileID: 118443142}
+ - component: {fileID: 118443141}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &118443140
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 118443139}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0.9, y: 0.9, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1278232628}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &118443141
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 118443139}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 1
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Get OneSignalId
+--- !u!222 &118443142
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 118443139}
+ m_CullTransparentMesh: 1
--- !u!1 &129243063
GameObject:
m_ObjectHideFlags: 0
@@ -3868,6 +3947,85 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 484811935}
m_CullTransparentMesh: 1
+--- !u!1 &495154762
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 495154763}
+ - component: {fileID: 495154765}
+ - component: {fileID: 495154764}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &495154763
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 495154762}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0.9, y: 0.9, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 910262211}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &495154764
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 495154762}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 14
+ m_FontStyle: 0
+ m_BestFit: 1
+ m_MinSize: 10
+ m_MaxSize: 40
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Get ExternalId
+--- !u!222 &495154765
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 495154762}
+ m_CullTransparentMesh: 1
--- !u!1 &499047144
GameObject:
m_ObjectHideFlags: 0
@@ -6747,6 +6905,139 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 909918831}
m_CullTransparentMesh: 1
+--- !u!1 &910262210
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 910262211}
+ - component: {fileID: 910262214}
+ - component: {fileID: 910262213}
+ - component: {fileID: 910262212}
+ m_Layer: 5
+ m_Name: button_getExternalId
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &910262211
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910262210}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 495154763}
+ m_Father: {fileID: 1250383578}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &910262212
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910262210}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 910262213}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 307684281}
+ m_TargetAssemblyTypeName: OneSignalExampleBehaviour, OneSignal.UnityPackage.Example
+ m_MethodName: GetExternalId
+ m_Mode: 1
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument:
+ m_BoolArgument: 0
+ m_CallState: 1
+--- !u!114 &910262213
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910262210}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &910262214
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 910262210}
+ m_CullTransparentMesh: 1
--- !u!1 &916273501
GameObject:
m_ObjectHideFlags: 0
@@ -10067,6 +10358,70 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1248003718}
m_CullTransparentMesh: 1
+--- !u!1 &1250383577
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1250383578}
+ - component: {fileID: 1250383579}
+ m_Layer: 5
+ m_Name: inputcontrols_container
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1250383578
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1250383577}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1278232628}
+ - {fileID: 910262211}
+ m_Father: {fileID: 1996857125}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1250383579
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1250383577}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Padding:
+ m_Left: 0
+ m_Right: 0
+ m_Top: 0
+ m_Bottom: 0
+ m_ChildAlignment: 0
+ m_Spacing: 10
+ m_ChildForceExpandWidth: 1
+ m_ChildForceExpandHeight: 1
+ m_ChildControlWidth: 1
+ m_ChildControlHeight: 1
+ m_ChildScaleWidth: 0
+ m_ChildScaleHeight: 0
+ m_ReverseArrangement: 0
--- !u!1 &1250632528
GameObject:
m_ObjectHideFlags: 0
@@ -10304,6 +10659,139 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1263276221}
m_CullTransparentMesh: 1
+--- !u!1 &1278232627
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1278232628}
+ - component: {fileID: 1278232631}
+ - component: {fileID: 1278232630}
+ - component: {fileID: 1278232629}
+ m_Layer: 5
+ m_Name: button_getOneSignalId
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1278232628
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1278232627}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 118443140}
+ m_Father: {fileID: 1250383578}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1278232629
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1278232627}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 1
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 1278232630}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls:
+ - m_Target: {fileID: 307684281}
+ m_TargetAssemblyTypeName: OneSignalExampleBehaviour, OneSignal.UnityPackage.Example
+ m_MethodName: GetOneSignalId
+ m_Mode: 1
+ m_Arguments:
+ m_ObjectArgument: {fileID: 0}
+ m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+ m_IntArgument: 0
+ m_FloatArgument: 0
+ m_StringArgument:
+ m_BoolArgument: 0
+ m_CallState: 1
+--- !u!114 &1278232630
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1278232627}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1278232631
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1278232627}
+ m_CullTransparentMesh: 1
--- !u!1 &1296016975
GameObject:
m_ObjectHideFlags: 0
@@ -13786,7 +14274,7 @@ MonoBehaviour:
m_HandleRect: {fileID: 916273502}
m_Direction: 2
m_Value: 1
- m_Size: 0.5315627
+ m_Size: 0.50223213
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
@@ -14155,6 +14643,7 @@ RectTransform:
- {fileID: 1144247376}
- {fileID: 1296016976}
- {fileID: 629334645}
+ - {fileID: 1996857125}
- {fileID: 262919209}
m_Father: {fileID: 2924184}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -16250,6 +16739,109 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1996857124
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1996857125}
+ - component: {fileID: 1996857128}
+ - component: {fileID: 1996857127}
+ - component: {fileID: 1996857126}
+ m_Layer: 5
+ m_Name: getIds_container
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1996857125
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1996857124}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1250383578}
+ m_Father: {fileID: 1654894820}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1996857126
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1996857124}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.9607844, g: 0.47450984, b: 0.47450984, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
+ m_Type: 1
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!222 &1996857127
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1996857124}
+ m_CullTransparentMesh: 1
+--- !u!114 &1996857128
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1996857124}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Padding:
+ m_Left: 10
+ m_Right: 10
+ m_Top: 10
+ m_Bottom: 10
+ m_ChildAlignment: 0
+ m_Spacing: 10
+ m_ChildForceExpandWidth: 1
+ m_ChildForceExpandHeight: 1
+ m_ChildControlWidth: 1
+ m_ChildControlHeight: 1
+ m_ChildScaleWidth: 0
+ m_ChildScaleHeight: 0
+ m_ReverseArrangement: 0
--- !u!1 &2009596016
GameObject:
m_ObjectHideFlags: 0
diff --git a/OneSignalExample/Assets/Plugins/Android/mainTemplate.gradle b/OneSignalExample/Assets/Plugins/Android/mainTemplate.gradle
index 09525b310..7255df042 100644
--- a/OneSignalExample/Assets/Plugins/Android/mainTemplate.gradle
+++ b/OneSignalExample/Assets/Plugins/Android/mainTemplate.gradle
@@ -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**}
diff --git a/OneSignalExample/ProjectSettings/AndroidResolverDependencies.xml b/OneSignalExample/ProjectSettings/AndroidResolverDependencies.xml
index 9eb42f5a1..f52f7b1b4 100644
--- a/OneSignalExample/ProjectSettings/AndroidResolverDependencies.xml
+++ b/OneSignalExample/ProjectSettings/AndroidResolverDependencies.xml
@@ -1,6 +1,6 @@
- com.onesignal:OneSignal:5.1.2
+ com.onesignal:OneSignal:5.1.4
diff --git a/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml b/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml
index 0bc1db54d..3ced2f24e 100644
--- a/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml
+++ b/com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml
@@ -3,6 +3,6 @@
https://repo.maven.apache.org/maven2
-
+
\ No newline at end of file
diff --git a/com.onesignal.unity.android/Runtime/AndroidUserManager.cs b/com.onesignal.unity.android/Runtime/AndroidUserManager.cs
index 430a547ab..e72b6f7dd 100644
--- a/com.onesignal.unity.android/Runtime/AndroidUserManager.cs
+++ b/com.onesignal.unity.android/Runtime/AndroidUserManager.cs
@@ -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 Changed;
public AndroidUserManager(AndroidJavaClass sdkClass) {
_user = sdkClass.CallStatic("getUser");
_pushSubscription = new AndroidPushSubscription(_user);
}
+ public string OneSignalId {
+ get => _user.Call("getOnesignalId");
+ }
+
+ public string ExternalId {
+ get => _user.Call("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;
+ }
+
+ /// UserChangedState
+ public void onUserStateChange(AndroidJavaObject state) {
+ var currentJO = state.Call("getCurrent");
+ var current = currentJO.ToSerializable();
+
+ UserChangedState userChangedState = new UserChangedState(current);
+ UserStateChangedEventArgs args = new UserStateChangedEventArgs(userChangedState);
+
+ EventHandler handler = _parent.Changed;
+ if (handler != null)
+ {
+ UnityMainThreadDispatch.Post(state => handler(_parent, args));
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/com.onesignal.unity.core/Editor/Platform/UserManager.cs b/com.onesignal.unity.core/Editor/Platform/UserManager.cs
index dfbe22775..e9393006d 100644
--- a/com.onesignal.unity.core/Editor/Platform/UserManager.cs
+++ b/com.onesignal.unity.core/Editor/Platform/UserManager.cs
@@ -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 Changed;
+
private PushSubscription _subscription = new PushSubscription();
public IPushSubscription PushSubscription {
diff --git a/com.onesignal.unity.core/Runtime/User/IUserManager.cs b/com.onesignal.unity.core/Runtime/User/IUserManager.cs
index 84c9418f3..f64dd606e 100644
--- a/com.onesignal.unity.core/Runtime/User/IUserManager.cs
+++ b/com.onesignal.unity.core/Runtime/User/IUserManager.cs
@@ -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 {
+ ///
+ /// Several states associated with the SDK can be changed in and outside of the application.
+ ///
+ public class UserStateChangedEventArgs : EventArgs
+ {
+ public UserChangedState State { get; }
+
+ public UserStateChangedEventArgs(UserChangedState state) {
+ State = state;
+ }
+ }
+
///
/// 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)
///
public interface IUserManager {
+ ///
+ /// The UUID generated by OneSignal to represent a user, empty if this is currently unavailable.
+ ///
+ string OneSignalId { get; }
+
+ ///
+ /// 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.
+ ///
+ string ExternalId { get; }
+
+ ///
+ /// When onesignalId or externalId has changed
+ ///
+ event EventHandler Changed;
+
///
/// 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
diff --git a/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs b/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs
new file mode 100644
index 000000000..eab372c57
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs.meta b/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs.meta
new file mode 100644
index 000000000..c58f687ca
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Internal/UserState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0dc78f38e7b0948d99aedd469f4a2a29
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.onesignal.unity.core/Runtime/User/Models/IPushSubscription.cs b/com.onesignal.unity.core/Runtime/User/Models/IPushSubscription.cs
index 378a948f6..fabdc919f 100644
--- a/com.onesignal.unity.core/Runtime/User/Models/IPushSubscription.cs
+++ b/com.onesignal.unity.core/Runtime/User/Models/IPushSubscription.cs
@@ -25,10 +25,10 @@
* THE SOFTWARE.
*/
+using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
-using System;
namespace OneSignalSDK.User.Models {
///
diff --git a/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs b/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs
new file mode 100644
index 000000000..6bfcab177
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs
@@ -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 {
+ ///
+ /// 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.
+ ///
+ string OneSignalId { get; }
+
+ ///
+ /// 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].
+ ///
+ string ExternalId { get; }
+ }
+}
\ No newline at end of file
diff --git a/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs.meta b/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs.meta
new file mode 100644
index 000000000..93e556cbf
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Models/IUserState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 369a546d971624331b3abbb151bf363a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs b/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs
new file mode 100644
index 000000000..419fe0336
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs.meta b/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs.meta
new file mode 100644
index 000000000..5b4c07c05
--- /dev/null
+++ b/com.onesignal.unity.core/Runtime/User/Models/UserChangedState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63e0183774569451eb3aeccb49a7ea1f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs b/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs
index 1efb742a5..f2a0c64c5 100644
--- a/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs
+++ b/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs
@@ -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
*/
diff --git a/com.onesignal.unity.ios/Runtime/Plugins/iOS/OneSignalUnityBridgeUser.mm b/com.onesignal.unity.ios/Runtime/Plugins/iOS/OneSignalUnityBridgeUser.mm
index 0d4db99e9..5f005fd1f 100644
--- a/com.onesignal.unity.ios/Runtime/Plugins/iOS/OneSignalUnityBridgeUser.mm
+++ b/com.onesignal.unity.ios/Runtime/Plugins/iOS/OneSignalUnityBridgeUser.mm
@@ -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
+
++ (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];
+ }
}
diff --git a/com.onesignal.unity.ios/Runtime/iOSUserManager.cs b/com.onesignal.unity.ios/Runtime/iOSUserManager.cs
index 7b9822337..57ff77d43 100644
--- a/com.onesignal.unity.ios/Runtime/iOSUserManager.cs
+++ b/com.onesignal.unity.ios/Runtime/iOSUserManager.cs
@@ -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 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(current);
+
+ UserChangedState userChangedState = new UserChangedState(curr);
+ UserStateChangedEventArgs args = new UserStateChangedEventArgs(userChangedState);
+
+ EventHandler handler = _instance.Changed;
+ if (handler != null)
+ {
+ UnityMainThreadDispatch.Post(state => handler(_instance, args));
+ }
}
}
}
\ No newline at end of file