diff --git a/OneSignalExample/Assets/OneSignal/CHANGELOG.md b/OneSignalExample/Assets/OneSignal/CHANGELOG.md index 456673e44..d61f1bd3c 100644 --- a/OneSignalExample/Assets/OneSignal/CHANGELOG.md +++ b/OneSignalExample/Assets/OneSignal/CHANGELOG.md @@ -5,9 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Added a delayed call when attempting to reshow the `OneSignalSetupWindow` after importing packages. +- Moved the example code to a separate assembly definition so that it may be utilized in place. +- The EDM4U setup step will rename the `Google.IOSResolver_v1.2.165.dll` on import in Unity 2021 and above. See EDM4U issue [#441](https://github.com/googlesamples/unity-jar-resolver/issues/441) for more information. +### Changed +- Updated formatting and documentation within the [OneSignalExampleBehaviour.cs](https://github.com/OneSignal/OneSignal-Unity-SDK/blob/main/OneSignalExample/Assets/OneSignal/Example/Scripts/OneSignalExampleBehaviour.cs) example code for clarity. +- Marked `EnabledVibrate` and `EnableSound` as `Obsolete` with as they do not function on Android 8+. Please check out https://documentation.onesignal.com/docs/android-notification-categories for more information. + ## [2.14.2] ### Fixed - Fixes rare iOS crash with some apps due to a threading issue. From [OneSignal-iOS-SDK PR #979](https://github.com/OneSignal/OneSignal-iOS-SDK/pull/979) + ## [2.14.1] ### Fixed - Corrected directory separators in post processor when building for iOS in a diff --git a/OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef b/OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef similarity index 92% rename from OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef rename to OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef index b58b38c6a..596366a79 100644 --- a/OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef +++ b/OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef @@ -1,5 +1,5 @@ { - "name": "OneSignal.UnityPackage", + "name": "OneSignal.UnityPackage.Editor", "references": [ "OneSignal.Core.Editor", "OneSignal.Core" diff --git a/OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef.meta b/OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef.meta similarity index 54% rename from OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef.meta rename to OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef.meta index 8a0d085de..388bbbcf3 100644 --- a/OneSignalExample/Assets/OneSignal/OneSignal.UnityPackage.asmdef.meta +++ b/OneSignalExample/Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 2eb579cd0b594304a0847fa97a894e84 +guid: f8571c548ad31d74abb46c04f5777db8 timeCreated: 1625590596 \ No newline at end of file diff --git a/OneSignalExample/Assets/OneSignal/Editor/Resources/OneSignalFileInventory.asset b/OneSignalExample/Assets/OneSignal/Editor/Resources/OneSignalFileInventory.asset index 2d69e8fe9..c291d6ecc 100644 --- a/OneSignalExample/Assets/OneSignal/Editor/Resources/OneSignalFileInventory.asset +++ b/OneSignalExample/Assets/OneSignal/Editor/Resources/OneSignalFileInventory.asset @@ -19,8 +19,6 @@ MonoBehaviour: - Assets/OneSignal/Example.meta - Assets/OneSignal/LICENSE.md - Assets/OneSignal/LICENSE.md.meta - - Assets/OneSignal/OneSignal.UnityPackage.asmdef - - Assets/OneSignal/OneSignal.UnityPackage.asmdef.meta - Assets/OneSignal/README.md - Assets/OneSignal/README.md.meta - Assets/OneSignal/VERSION @@ -41,6 +39,8 @@ MonoBehaviour: - Assets/OneSignal/Documentation~/setup_window.png - Assets/OneSignal/Editor/AssemblyInfo.cs - Assets/OneSignal/Editor/AssemblyInfo.cs.meta + - Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef + - Assets/OneSignal/Editor/OneSignal.UnityPackage.Editor.asmdef.meta - Assets/OneSignal/Editor/OneSignalBootstrapper.cs - Assets/OneSignal/Editor/OneSignalBootstrapper.cs.meta - Assets/OneSignal/Editor/OneSignalFileInventory.cs @@ -72,6 +72,8 @@ MonoBehaviour: - Assets/OneSignal/Editor/Utilities/GitHubUtility.cs.meta - Assets/OneSignal/Editor/Utilities/MiniJSON.cs - Assets/OneSignal/Editor/Utilities/MiniJSON.cs.meta + - Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef + - Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef.meta - Assets/OneSignal/Example/Scenes.meta - Assets/OneSignal/Example/Scripts.meta - Assets/OneSignal/Example/Scenes/OneSignalExampleScene.unity diff --git a/OneSignalExample/Assets/OneSignal/Editor/SetupSteps/ImportPackagesStep.cs b/OneSignalExample/Assets/OneSignal/Editor/SetupSteps/ImportPackagesStep.cs index 9cd218fee..a94152358 100644 --- a/OneSignalExample/Assets/OneSignal/Editor/SetupSteps/ImportPackagesStep.cs +++ b/OneSignalExample/Assets/OneSignal/Editor/SetupSteps/ImportPackagesStep.cs @@ -65,7 +65,7 @@ public static void _showCoreInstallerWindow() return; SessionState.EraseBool(_shouldShowWindowKey); - OneSignalSetupWindow.ShowWindow(); + EditorApplication.delayCall += OneSignalSetupWindow.ShowWindow; } #endif diff --git a/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef b/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef new file mode 100644 index 000000000..0b8097e42 --- /dev/null +++ b/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef @@ -0,0 +1,26 @@ +{ + "name": "OneSignal.UnityPackage.Example", + "rootNamespace": "", + "references": [ + "OneSignal.Core" + ], + "includePlatforms": [ + "Android", + "Editor", + "iOS" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.onesignal.unity.core", + "expression": "0.0.1-preview", + "define": "ONE_SIGNAL_INSTALLED" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef.meta b/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef.meta new file mode 100644 index 000000000..28a4d0344 --- /dev/null +++ b/OneSignalExample/Assets/OneSignal/Example/OneSignal.UnityPackage.Example.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a28dab59edddfb3448f1fd9318f85c32 +timeCreated: 1625590596 \ No newline at end of file diff --git a/OneSignalExample/Assets/OneSignal/Example/Scenes/OneSignalExampleScene.unity b/OneSignalExample/Assets/OneSignal/Example/Scenes/OneSignalExampleScene.unity index 0b19668da..dff005d04 100644 --- a/OneSignalExample/Assets/OneSignal/Example/Scenes/OneSignalExampleScene.unity +++ b/OneSignalExample/Assets/OneSignal/Example/Scenes/OneSignalExampleScene.unity @@ -244,6 +244,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9e0cf583b67c419894c77bc78acc66c4, type: 3} m_Name: m_EditorClassIdentifier: + email: Email Address + externalId: External User ID --- !u!4 &1816083102 Transform: m_ObjectHideFlags: 0 diff --git a/OneSignalExample/Assets/OneSignal/Example/Scripts/OneSignalExampleBehaviour.cs b/OneSignalExample/Assets/OneSignal/Example/Scripts/OneSignalExampleBehaviour.cs index 1c1355f68..0be6923b2 100644 --- a/OneSignalExample/Assets/OneSignal/Example/Scripts/OneSignalExampleBehaviour.cs +++ b/OneSignalExample/Assets/OneSignal/Example/Scripts/OneSignalExampleBehaviour.cs @@ -32,229 +32,320 @@ public class OneSignalExampleBehaviour : MonoBehaviour { - private static string extraMessage; - public string email = "Email Address"; - public string externalId = "External User ID"; - - private static bool requiresUserPrivacyConsent = false; - - void Start() { - extraMessage = null; + /// + /// set to an email address you would like to test notifications against + /// + public string email = "EMAIL_ADDRESS"; + + /// + /// set to an external user id you would like to test notifications against + /// + public string externalId = "EXTERNAL_USER_ID"; + + /// + /// set to your app id (https://documentation.onesignal.com/docs/accounts-and-keys) + /// + public string appId = "ONESIGNAL_APP_ID"; + + /// + /// whether you would prefer OneSignal Unity SDK prevent initialization until consent is granted via + /// in this test MonoBehaviour + /// + public bool requiresUserPrivacyConsent; + + /// + /// we recommend initializing OneSignal early in your application's lifecycle such as in the Start method of a + /// MonoBehaviour in your opening Scene + /// + private void Start() { + _logMessage = null; // Enable line below to debug issues with OneSignal. (logLevel, visualLogLevel) OneSignal.SetLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - // If you set to true, the user will have to provide consent - // using OneSignal.UserDidProvideConsent(true) before the - // SDK will initialize + /* + * If you set to true, the user will have to provide consent via OneSignal.UserDidProvideConsent(true) before + * the SDK will initialize + */ OneSignal.SetRequiresUserPrivacyConsent(requiresUserPrivacyConsent); - // The only required method you need to call to setup OneSignal to receive push notifications. - // Call before using any other methods on OneSignal (except setLogLevel or SetRequiredUserPrivacyConsent) - // Should only be called once when your app is loaded. - OneSignal.StartInit("99015f5e-87b1-462e-a75b-f99bf7c2822e") - .HandleNotificationReceived(HandleNotificationReceived) - .HandleNotificationOpened(HandleNotificationOpened) - .HandleInAppMessageClicked(HandlerInAppMessageClicked) - .EndInit(); - + /* + * The only required method you need to call to setup OneSignal to receive push notifications. + * Call before using any other methods on OneSignal (except setLogLevel or SetRequiredUserPrivacyConsent) + * Should only invoke once when your app is loaded. + */ + OneSignal.StartInit(appId) + .HandleNotificationReceived(HandleNotificationReceived) + .HandleNotificationOpened(HandleNotificationOpened) + .HandleInAppMessageClicked(OnInAppMessageClicked) + .EndInit(); + + // Control how OneSignal notifications will be shown when one is received while your app is in focus OneSignal.inFocusDisplayType = OneSignal.OSInFocusDisplayOption.Notification; - OneSignal.permissionObserver += OneSignal_permissionObserver; - OneSignal.subscriptionObserver += OneSignal_subscriptionObserver; - OneSignal.emailSubscriptionObserver += OneSignal_emailSubscriptionObserver; + // Each of these events can inform your application when the user's OneSignal states have change + OneSignal.permissionObserver += OnPermissionStateChange; + OneSignal.subscriptionObserver += OnSubscriptionStateChange; + OneSignal.emailSubscriptionObserver += OnEmailSubscriptionStateChange; - var pushState = OneSignal.GetPermissionSubscriptionState(); + // You can also get the current states directly + var fullUserState = OneSignal.GetPermissionSubscriptionState(); + var permissionState = fullUserState.permissionStatus; + var subscriptionState = fullUserState.subscriptionStatus; + var emailSubscriptionState = fullUserState.emailSubscriptionStatus; OneSignalInAppMessageTriggerExamples(); OneSignalOutcomeEventsExamples(); } - - // Examples of using OneSignal External User Id - private void OneSignalExternalUserIdCallback(Dictionary results) - { + /// + /// Examples of using OneSignal External User Id + /// + private void OnUpdatedExternalUserId(Dictionary results) { // The results will contain push and email success statuses - Console.WriteLine("External user id updated with results: " + Json.Serialize(results)); + print($"External user id updated with results: {Json.Serialize(results)}"); // Push can be expected in almost every situation with a success status, but // as a pre-caution its good to verify it exists - if (results.ContainsKey("push")) - { - Dictionary pushStatusDict = results["push"] as Dictionary; - if (pushStatusDict.ContainsKey("success")) - { - Console.WriteLine("External user id updated for push with results: " + pushStatusDict["success"] as string); - } + if (results.ContainsKey("push")) { + if (results["push"] is Dictionary pushStatus && pushStatus.ContainsKey("success")) + print($"External user id updated for push with results: {pushStatus["success"]}"); } // Verify the email is set or check that the results have an email success status - if (results.ContainsKey("email")) - { - Dictionary emailStatusDict = results["email"] as Dictionary; - if (emailStatusDict.ContainsKey("success")) - { - Console.WriteLine("External user id updated for email with results: " + emailStatusDict["success"] as string); - } + if (results.ContainsKey("email")) { + if (results["email"] is Dictionary emailStatus && emailStatus.ContainsKey("success")) + print($"External user id updated for email with results: {emailStatus["success"]}"); } } - private void OneSignalExternalUserIdCallbackFailure(Dictionary error) - { - // The results will contain push and email success statuses - Console.WriteLine("External user id failed with error: " + Json.Serialize(error)); + private void OnUpdatedExternalUserIdFailure(Dictionary error) { + // As above the results will contain push and email statuses + print($"External user id failed with error: {Json.Serialize(error)}"); } - // Examples of using OneSignal In-App Message triggers - private void OneSignalInAppMessageTriggerExamples() { + /// + /// Examples of using OneSignal In-App Message triggers + /// https://documentation.onesignal.com/docs/in-app-message-examples + /// + private static void OneSignalInAppMessageTriggerExamples() { // Add a single trigger OneSignal.AddTrigger("key", "value"); // Get the current value to a trigger by key - var triggerKey = "key"; + var triggerKey = "key"; var triggerValue = OneSignal.GetTriggerValueForKey(triggerKey); - String output = "Trigger key: " + triggerKey + " value: " + (String) triggerValue; - Console.WriteLine(output); + print($"Trigger key: {triggerKey} value: {triggerValue}"); // Add multiple triggers - OneSignal.AddTriggers(new Dictionary() { { "key1", "value1" }, { "key2", 2 } }); + OneSignal.AddTriggers(new Dictionary { + { "key1", "value1" }, + { "key2", 2 } + }); // Delete a trigger OneSignal.RemoveTriggerForKey("key"); // Delete a list of triggers - OneSignal.RemoveTriggersForKeys(new List() { "key1", "key2" }); + OneSignal.RemoveTriggersForKeys(new List { "key1", "key2" }); // Temporarily pause In-App messages; If true is passed in. // Great to ensure you never interrupt your user while they are in the middle of a match in your game. OneSignal.PauseInAppMessages(false); - } + } - private void OneSignalOutcomeEventsExamples() { + /// + /// Send data to OneSignal which will allow you to track the result of notifications + /// https://documentation.onesignal.com/docs/outcomes + /// + private static void OneSignalOutcomeEventsExamples() { + // Send a result which can occur multiple times OneSignal.SendOutcome("normal_1"); - OneSignal.SendOutcome("normal_2", (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); + OneSignal.SendOutcome("normal_2", OnSendOutcomeSuccess); + // Send a result which can only occur once OneSignal.SendUniqueOutcome("unique_1"); - OneSignal.SendUniqueOutcome("unique_2", (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); + OneSignal.SendUniqueOutcome("unique_2", OnSendOutcomeSuccess); + // Send a result which can occur multiple times with a float value OneSignal.SendOutcomeWithValue("value_1", 3.2f); - OneSignal.SendOutcomeWithValue("value_2", 3.2f, (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); - } - - private void printOutcomeEvent(OSOutcomeEvent outcomeEvent) { - Console.WriteLine(outcomeEvent.session + "\n" + - string.Join(", ", outcomeEvent.notificationIds) + "\n" + - outcomeEvent.name + "\n" + - outcomeEvent.timestamp + "\n" + - outcomeEvent.weight); + OneSignal.SendOutcomeWithValue("value_2", 3.2f, OnSendOutcomeSuccess); + } + + private static void OnSendOutcomeSuccess(OSOutcomeEvent outcomeEvent) { + print(outcomeEvent.session + "\n" + + string.Join(", ", outcomeEvent.notificationIds) + "\n" + + outcomeEvent.name + "\n" + + outcomeEvent.timestamp + "\n" + + outcomeEvent.weight); } - private void OneSignal_subscriptionObserver(OSSubscriptionStateChanges stateChanges) { - Debug.Log("SUBSCRIPTION stateChanges: " + stateChanges); - Debug.Log("SUBSCRIPTION stateChanges.to.userId: " + stateChanges.to.userId); - Debug.Log("SUBSCRIPTION stateChanges.to.subscribed: " + stateChanges.to.subscribed); - } + /* + * State change events provide both the new (to) and previous (from) states + */ + + private void OnSubscriptionStateChange(OSSubscriptionStateChanges stateChanges) { + print("SUBSCRIPTION stateChanges: " + stateChanges); + print("SUBSCRIPTION stateChanges.to.userId: " + stateChanges.to.userId); + print("SUBSCRIPTION stateChanges.to.subscribed: " + stateChanges.to.subscribed); + } - private void OneSignal_permissionObserver(OSPermissionStateChanges stateChanges) { - Debug.Log("PERMISSION stateChanges.from.status: " + stateChanges.from.status); - Debug.Log("PERMISSION stateChanges.to.status: " + stateChanges.to.status); - } + private void OnPermissionStateChange(OSPermissionStateChanges stateChanges) { + print($"PERMISSION stateChanges.from.status: {stateChanges.from.status}"); + print($"PERMISSION stateChanges.to.status: {stateChanges.to.status}"); + } - private void OneSignal_emailSubscriptionObserver(OSEmailSubscriptionStateChanges stateChanges) { - Debug.Log("EMAIL stateChanges.from.status: " + stateChanges.from.emailUserId + ", " + stateChanges.from.emailAddress); - Debug.Log("EMAIL stateChanges.to.status: " + stateChanges.to.emailUserId + ", " + stateChanges.to.emailAddress); + private void OnEmailSubscriptionStateChange(OSEmailSubscriptionStateChanges stateChanges) { + print($"EMAIL stateChanges.from.status: {stateChanges.from.emailUserId}, {stateChanges.from.emailAddress}"); + print($"EMAIL stateChanges.to.status: {stateChanges.to.emailUserId}, {stateChanges.to.emailAddress}"); } - // Called when your app is in focus and a notification is received. - // The name of the method can be anything as long as the signature matches. - // Method must be static or this object should be marked as DontDestroyOnLoad + /// + /// Called when your app is in focus and a notification is received. + /// The name of the method can be anything as long as the signature matches. + /// Method must be static or this object should be marked as DontDestroyOnLoad + /// private static void HandleNotificationReceived(OSNotification notification) { - OSNotificationPayload payload = notification.payload; - string message = payload.body; + var payload = notification.payload; + var message = payload.body; print("GameControllerExample:HandleNotificationReceived: " + message); print("displayType: " + notification.displayType); - extraMessage = "Notification received with text: " + message; + _logMessage = "Notification received with text: " + message; - Dictionary additionalData = payload.additionalData; - if (additionalData == null) - Debug.Log ("[HandleNotificationReceived] Additional Data == null"); + if (payload.additionalData == null) + print("[HandleNotificationReceived] Additional Data == null"); + else if (Json.Serialize(payload.additionalData) is { } dataString) + print($"[HandleNotificationReceived] message {message}, additionalData: {dataString}"); else - Debug.Log("[HandleNotificationReceived] message " + message + ", additionalData: " + Json.Serialize(additionalData) as string); + print("[HandleNotificationReceived] Additional Data could not be serialized"); } - // Called when a notification is opened. - // The name of the method can be anything as long as the signature matches. - // Method must be static or this object should be marked as DontDestroyOnLoad - public static void HandleNotificationOpened(OSNotificationOpenedResult result) { - OSNotificationPayload payload = result.notification.payload; - string message = payload.body; - string actionID = result.action.actionID; + /// + /// Called when a notification is opened. + /// The name of the method can be anything as long as the signature matches. + /// Method must be static or this object should be marked as DontDestroyOnLoad + /// + private static void HandleNotificationOpened(OSNotificationOpenedResult result) { + var payload = result.notification.payload; + var message = payload.body; + var actionID = result.action.actionID; print("GameControllerExample:HandleNotificationOpened: " + message); - extraMessage = "Notification opened with text: " + message; - - Dictionary additionalData = payload.additionalData; - if (additionalData == null) - Debug.Log ("[HandleNotificationOpened] Additional Data == null"); + _logMessage = "Notification opened with text: " + message; + + if (payload.additionalData == null) + print("[HandleNotificationOpened] Additional Data == null"); + else if (Json.Serialize(payload.additionalData) is { } dataString) + print($"[HandleNotificationOpened] message {message}, additionalData: {dataString}"); else - Debug.Log("[HandleNotificationOpened] message " + message + ", additionalData: " + Json.Serialize(additionalData) as string); + print("[HandleNotificationOpened] Additional Data could not be serialized"); if (actionID != null) { // actionSelected equals the id on the button the user pressed. // actionSelected will equal "__DEFAULT__" when the notification itself was tapped when buttons were present. - extraMessage = "Pressed ButtonId: " + actionID; + _logMessage = "Pressed ButtonId: " + actionID; } } - public static void HandlerInAppMessageClicked(OSInAppMessageAction action) { - String logInAppClickEvent = "In-App Message Clicked: " + + private static void OnInAppMessageClicked(OSInAppMessageAction action) { + var logInAppClickEvent = "In-App Message Clicked: " + "\nClick Name: " + action.clickName + "\nClick Url: " + action.clickUrl + "\nFirst Click: " + action.firstClick + "\nCloses Message: " + action.closesMessage; print(logInAppClickEvent); - extraMessage = logInAppClickEvent; + _logMessage = logInAppClickEvent; } - // Test Menu - // Includes SendTag/SendTags, getting the userID and pushToken, and scheduling an example notification - void OnGUI() { - GUIStyle customTextSize = new GUIStyle("button"); - customTextSize.fontSize = 30; + /// + /// See https://documentation.onesignal.com/reference/create-notification for a full list of options. + /// + /// + /// You can not use included_segments or any fields that require your OneSignal 'REST API Key' in your app for + /// security reasons. + /// If you need to use your OneSignal 'REST API Key' you will need your own server where you can make this call. + /// + private static void SendTestNotification(string userId) { + var notification = new Dictionary { + ["contents"] = new Dictionary { { "en", "Test Message" } }, + + // Send notification to this user + ["include_player_ids"] = new List { userId }, + + // Example of scheduling a notification in the future. + ["send_after"] = DateTime.Now.ToUniversalTime().AddSeconds(30).ToString("U") + }; + + _logMessage = "Posting test notification now. By default the example should arrive 30 seconds in the future." + + "If you would like to see it as a Push and not an In App Alert then please leave the application."; + OneSignal.PostNotification(notification, OnNotificationPostSuccess, OnNotificationPostFailure); + } - GUIStyle guiBoxStyle = new GUIStyle("box"); - guiBoxStyle.fontSize = 30; + private static void OnNotificationPostSuccess(Dictionary response) + => _logMessage = "Notification post success!\n" + Json.Serialize(response); - GUIStyle textFieldStyle = new GUIStyle("textField"); - textFieldStyle.fontSize = 30; + private static void OnNotificationPostFailure(Dictionary response) + => _logMessage = "Notification failed to post:\n" + Json.Serialize(response); + + /* + * UI Rendering + */ + private const float ItemOriginX = 50.0f; + private const float BoxOriginY = 120.0f; + private const float ItemStartY = 200.0f; + private const float ItemHeightOffset = 90.0f; + private const float ItemHeight = 60.0f; - float itemOriginX = 50.0f; - float itemWidth = Screen.width - 120.0f; - float boxWidth = Screen.width - 20.0f; - float boxOriginY = 120.0f; - float boxHeight = requiresUserPrivacyConsent ? 980.0f : 890.0f; - float itemStartY = 200.0f; - float itemHeightOffset = 90.0f; - float itemHeight = 60.0f; + private static string _logMessage; - GUI.Box(new Rect(10, boxOriginY, boxWidth, boxHeight), "Test Menu", guiBoxStyle); + private GUIStyle _customTextSize; + private GUIStyle _guiBoxStyle; - float count = 0.0f; + private static float ItemWidth => Screen.width - 120.0f; + private static float BoxWidth => Screen.width - 20.0f; + private float BoxHeight => requiresUserPrivacyConsent ? 980.0f : 890.0f; - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SendTags", customTextSize)) { + private Rect MainMenuRect => new Rect(10, BoxOriginY, BoxWidth, BoxHeight); + + private static Rect ItemRect(ref int position) => new Rect( + ItemOriginX, + ItemStartY + position++ * ItemHeightOffset, + ItemWidth, + ItemHeight + ); + + private bool MenuButton(ref int position, string label) + => GUI.Button(ItemRect(ref position), label, _customTextSize); + + // Test Menu + // Includes SendTag/SendTags, getting the userID and pushToken, and scheduling an example notification + private void OnGUI() { + _customTextSize ??= new GUIStyle(GUI.skin.button) { + fontSize = 30 + }; + + _guiBoxStyle ??= new GUIStyle(GUI.skin.box) { + fontSize = 30, + alignment = TextAnchor.UpperLeft, + wordWrap = true + }; + + GUI.Box(MainMenuRect, "Test Menu", _guiBoxStyle); + + int position = 0; + + if (MenuButton(ref position, "Send Example Tags")) { // You can tags users with key value pairs like this: OneSignal.SendTag("UnityTestKey", "TestValue"); + // Or use an IDictionary if you need to set more than one tag. - OneSignal.SendTags(new Dictionary() { { "UnityTestKey2", "value2" }, { "UnityTestKey3", "value3" } }); + OneSignal.SendTags(new Dictionary { + { "UnityTestKey2", "value2" }, + { "UnityTestKey3", "value3" } + }); // You can delete a single tag with it's key. // OneSignal.DeleteTag("UnityTestKey"); @@ -262,105 +353,77 @@ void OnGUI() { // OneSignal.DeleteTags(new List() {"UnityTestKey2", "UnityTestKey3" }); } - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "GetIds", customTextSize)) { + if (MenuButton(ref position, "Get Ids")) { OneSignal.IdsAvailable((userId, pushToken) => { - extraMessage = "UserID:\n" + userId + "\n\nPushToken:\n" + pushToken; + _logMessage = $"UserID:\n{userId}\n\nPushToken:\n{pushToken}"; }); } - count++; + if (MenuButton(ref position, "Test Notification")) { + _logMessage = "Waiting to get a OneSignal userId. Uncomment OneSignal.SetLogLevel in the Start method if " + + "it hangs here to debug the issue."; - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "TestNotification", customTextSize)) { - extraMessage = "Waiting to get a OneSignal userId. Uncomment OneSignal.SetLogLevel in the Start method if it hangs here to debug the issue."; + // Checking to make sure this device is registered or you will not receive the notification OneSignal.IdsAvailable((userId, pushToken) => { - if (pushToken != null) { - // See https://documentation.onesignal.com/reference/create-notification for a full list of options. - // You can not use included_segments or any fields that require your OneSignal 'REST API Key' in your app for security reasons. - // If you need to use your OneSignal 'REST API Key' you will need your own server where you can make this call. - - var notification = new Dictionary(); - notification["contents"] = new Dictionary() { {"en", "Test Message"} }; - // Send notification to this device. - notification["include_player_ids"] = new List() { userId }; - // Example of scheduling a notification in the future. - //notification["send_after"] = System.DateTime.Now.ToUniversalTime().AddSeconds(30).ToString("U"); - - extraMessage = "Posting test notification now."; - - OneSignal.PostNotification(notification, (responseSuccess) => { - extraMessage = "Notification posted successful! Delayed by about 30 seconds to give you time to press the home button to see a notification vs an in-app alert.\n" + Json.Serialize(responseSuccess); - }, (responseFailure) => { - extraMessage = "Notification failed to post:\n" + Json.Serialize(responseFailure); - }); - } else { - extraMessage = "ERROR: Device is not registered."; - } + if (pushToken != null) + SendTestNotification(userId); + else + _logMessage = "ERROR: Device is not registered."; }); } - count++; - - email = GUI.TextField(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), email, customTextSize); - - count++; + email = GUI.TextField(ItemRect(ref position), email, _customTextSize); - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SetEmail", customTextSize)) { - extraMessage = "Setting email to " + email; + if (MenuButton(ref position, "Set Email")) { + _logMessage = "Setting email to " + email; - OneSignal.SetEmail (email, () => { - Debug.Log("Successfully set email"); - }, (error) => { - Debug.Log("Encountered error setting email: " + Json.Serialize(error)); - }); + OneSignal.SetEmail(email, + () => print("Successfully set email"), + error => printError("Error setting email: " + Json.Serialize(error)) + ); } - count++; + if (MenuButton(ref position, "Logout Email")) { + _logMessage = "Logging Out of example@example.com"; - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "LogoutEmail", customTextSize)) { - extraMessage = "Logging Out of example@example.com"; - - OneSignal.LogoutEmail (() => { - Debug.Log("Successfully logged out of email"); - }, (error) => { - Debug.Log("Encountered error logging out of email: " + Json.Serialize(error)); - }); + OneSignal.LogoutEmail( + () => print("Successfully logged out of email"), + error => printError("Error logging out of email: " + Json.Serialize(error)) + ); } - count++; - - externalId = GUI.TextField(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), externalId, customTextSize); - - count++; - - if (GUI.Button(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SetExternalId", customTextSize)) { - OneSignal.SetExternalUserId(externalId, OneSignalExternalUserIdCallback); - // Auth external id method - // OneSignal.SetExternalUserId(externalId, "your_auth_hash_token", OneSignalExternalUserIdCallback, OneSignalExternalUserIdCallbackFailure); - } + externalId = GUI.TextField(ItemRect(ref position), externalId, _customTextSize); - count++; + if (MenuButton(ref position, "Set External Id")) + OneSignal.SetExternalUserId(externalId, OnUpdatedExternalUserId); - if (GUI.Button(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "RemoveExternalId", customTextSize)) { - OneSignal.RemoveExternalUserId(OneSignalExternalUserIdCallback); - } + if (MenuButton(ref position, "Remove External Id")) + OneSignal.RemoveExternalUserId(OnUpdatedExternalUserId); if (requiresUserPrivacyConsent) { - count++; + var consentText = OneSignal.UserProvidedConsent() + ? "Revoke Privacy Consent" + : "Provide Privacy Consent"; + + if (GUI.Button(ItemRect(ref position), consentText, _customTextSize)) { + _logMessage = "Providing user privacy consent"; - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), (OneSignal.UserProvidedConsent() ? "Revoke Privacy Consent" : "Provide Privacy Consent"), customTextSize)) { - extraMessage = "Providing user privacy consent"; - OneSignal.UserDidProvideConsent(!OneSignal.UserProvidedConsent()); } } - if (extraMessage != null) { - guiBoxStyle.alignment = TextAnchor.UpperLeft; - guiBoxStyle.wordWrap = true; - GUI.Box (new Rect (10, boxOriginY + boxHeight + 20, Screen.width - 20, Screen.height - (boxOriginY + boxHeight + 40)), extraMessage, guiBoxStyle); + if (_logMessage != null) { + var logRect = new Rect( + 10, + BoxOriginY + BoxHeight + 20, + Screen.width - 20, + Screen.height - (BoxOriginY + BoxHeight + 40) + ); + + GUI.Box(logRect, _logMessage, _guiBoxStyle); } } + + private static void printError(object message) => Debug.LogError(message); } #endif \ No newline at end of file diff --git a/OneSignalExample/Assets/OneSignalPackager/OneSignal.Packager.asmdef b/OneSignalExample/Assets/OneSignalPackager/OneSignal.Packager.asmdef index 250ab63c2..65004ba9b 100644 --- a/OneSignalExample/Assets/OneSignalPackager/OneSignal.Packager.asmdef +++ b/OneSignalExample/Assets/OneSignalPackager/OneSignal.Packager.asmdef @@ -1,7 +1,7 @@ { "name": "OneSignal.Packager", "references": [ - "OneSignal.UnityPackage" + "OneSignal.UnityPackage.Editor" ], "includePlatforms": [ "Editor" diff --git a/com.onesignal.unity.android/Editor/SetupSteps/InstallEdm4uStep.cs b/com.onesignal.unity.android/Editor/SetupSteps/InstallEdm4uStep.cs index 26940e99e..699c1f969 100644 --- a/com.onesignal.unity.android/Editor/SetupSteps/InstallEdm4uStep.cs +++ b/com.onesignal.unity.android/Editor/SetupSteps/InstallEdm4uStep.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using UnityEditor; using UnityEditor.Compilation; using UnityEngine; @@ -6,37 +7,34 @@ /// /// Checks for EDM4U assemblies and installs the package from its github releases /// -public sealed class InstallEdm4uStep : OneSignalSetupStep +public sealed class InstallEdm4uStep : OneSignalSetupStep { public override string Summary => $"Install EDM4U {_edm4UVersion}"; public override string Details => $"Downloads and imports version {_edm4UVersion} from Google's repo. This library resolves dependencies " + - $"among included libraries on Android."; +#if UNITY_2021_1_OR_NEWER + "among included libraries on Android.\n\nNOTE: In Unity 2021+ the " + + $"Google.IOSResolver_v{_edm4UVersion}.dll will be renamed to Google.IOSResolver.dll in order to resolve a bug."; +#else + "among included libraries on Android."; +#endif - public override bool IsRequired + public override bool IsRequired => true; protected override bool _getIsStepCompleted() - { - var precompiledAssemblies = CompilationPipeline.GetPrecompiledAssemblyNames(); - foreach (var assemblyName in precompiledAssemblies) - { - if (assemblyName.StartsWith("Google.VersionHandler")) - return true; - } - - return false; - } + => CompilationPipeline.GetPrecompiledAssemblyNames() + .Any(assemblyName => assemblyName.StartsWith("Google.VersionHandler")); - protected override void _runStep() + protected override void _runStep() { var request = EditorWebRequest.Get(_edm4UPackageDownloadUrl); request.AddEditorProgressDialog("Downloading Google External Dependency Manager"); - request.Send(unityRequest => + request.Send(unityRequest => { - if (unityRequest.error != null) + if (unityRequest.error != null) { EditorUtility.DisplayDialog("Package Download failed.", unityRequest.error, "Ok"); return; @@ -47,13 +45,35 @@ protected override void _runStep() var tmpPackageFile = projectPath + FileUtil.GetUniqueTempPathInProject() + ".unityPackage"; File.WriteAllBytes(tmpPackageFile, unityRequest.downloadHandler.data); - AssetDatabase.ImportPackage(tmpPackageFile, false); + +#if UNITY_2021_1_OR_NEWER + SessionState.SetBool(_shouldFix2021Bug, true); +#endif + _shouldCheckForCompletion = true; }); } + + [InitializeOnLoadMethod] + public static void _fixUnity2021Bug() + { + if (!SessionState.GetBool(_shouldFix2021Bug, false)) + return; + + SessionState.EraseBool(_shouldFix2021Bug); + + EditorApplication.delayCall += () => { + File.Move(_iosDLLSourcePath, _iosDLLDestPath); + File.Move(_iosDLLSourcePath + ".meta", _iosDLLDestPath + ".meta"); + }; + } private const string _edm4UVersion = "1.2.165"; + private const string _shouldFix2021Bug = "onesignal.installedm4u.shouldfix2021bug"; + private const string _iosDLLDestPath = "Assets/ExternalDependencyManager/Editor/Google.IOSResolver.dll"; + private static readonly string _iosDLLSourcePath = $"Assets/ExternalDependencyManager/Editor/Google.IOSResolver_v{_edm4UVersion}.dll"; - static readonly string _edm4UPackageDownloadUrl = $"https://github.com/googlesamples/unity-jar-resolver/blob/v{_edm4UVersion}/external-dependency-manager-{_edm4UVersion}.unitypackage?raw=true"; + static readonly string _edm4UPackageDownloadUrl + = $"https://github.com/googlesamples/unity-jar-resolver/blob/v{_edm4UVersion}/external-dependency-manager-{_edm4UVersion}.unitypackage?raw=true"; } \ No newline at end of file diff --git a/com.onesignal.unity.android/Runtime/Plugins/Android.meta b/com.onesignal.unity.android/Runtime/Plugins/Android.meta index a3bbde55f..0a6b2225c 100644 --- a/com.onesignal.unity.android/Runtime/Plugins/Android.meta +++ b/com.onesignal.unity.android/Runtime/Plugins/Android.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 6e4a361afc49e41ed93e195e8b4e792b +guid: 01819e7850e978e45887bb8f0f8d1452 folderAsset: yes -timeCreated: 1450315055 -licenseType: Free DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/com.onesignal.unity.core/Runtime/Core/OneSignal.cs b/com.onesignal.unity.core/Runtime/Core/OneSignal.cs index f502b51de..718b76bde 100644 --- a/com.onesignal.unity.core/Runtime/Core/OneSignal.cs +++ b/com.onesignal.unity.core/Runtime/Core/OneSignal.cs @@ -614,6 +614,7 @@ public static void IdsAvailable(IdsAvailableCallback inIdsAvailableDelegate) /// /// Android - When user receives notification, vibrate device less. /// + [Obsolete("Only works below Android 8, please check out https://documentation.onesignal.com/docs/android-notification-categories")] public static void EnableVibrate(bool enable) { oneSignalPlatform.EnableVibrate(enable); @@ -622,6 +623,7 @@ public static void EnableVibrate(bool enable) /// /// Android - When user receives notification, do not play a sound /// + [Obsolete("Only works below Android 8, please check out https://documentation.onesignal.com/docs/android-notification-categories")] public static void EnableSound(bool enable) { oneSignalPlatform.EnableSound(enable); diff --git a/com.onesignal.unity.core/Samples~/GameControllerExample.cs b/com.onesignal.unity.core/Samples~/GameControllerExample.cs deleted file mode 100644 index f9d768bc8..000000000 --- a/com.onesignal.unity.core/Samples~/GameControllerExample.cs +++ /dev/null @@ -1,365 +0,0 @@ -/** - * Modified MIT License - * - * Copyright 2021 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 UnityEngine; -using System.Collections.Generic; - -using System; - -public class GameControllerExample : MonoBehaviour { - - private static string extraMessage; - public string email = "Email Address"; - public string externalId = "External User ID"; - - private static bool requiresUserPrivacyConsent = false; - - void Start() { - extraMessage = null; - - // Enable line below to debug issues with OneSignal. (logLevel, visualLogLevel) - OneSignal.SetLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); - - // If you set to true, the user will have to provide consent - // using OneSignal.UserDidProvideConsent(true) before the - // SDK will initialize - OneSignal.SetRequiresUserPrivacyConsent(requiresUserPrivacyConsent); - - // The only required method you need to call to setup OneSignal to receive push notifications. - // Call before using any other methods on OneSignal (except setLogLevel or SetRequiredUserPrivacyConsent) - // Should only be called once when your app is loaded. - OneSignal.StartInit("99015f5e-87b1-462e-a75b-f99bf7c2822e") - .HandleNotificationReceived(HandleNotificationReceived) - .HandleNotificationOpened(HandleNotificationOpened) - .HandleInAppMessageClicked(HandlerInAppMessageClicked) - .EndInit(); - - OneSignal.inFocusDisplayType = OneSignal.OSInFocusDisplayOption.Notification; - - OneSignal.permissionObserver += OneSignal_permissionObserver; - OneSignal.subscriptionObserver += OneSignal_subscriptionObserver; - OneSignal.emailSubscriptionObserver += OneSignal_emailSubscriptionObserver; - - var pushState = OneSignal.GetPermissionSubscriptionState(); - - OneSignalInAppMessageTriggerExamples(); - OneSignalOutcomeEventsExamples(); - } - - - // Examples of using OneSignal External User Id - private void OneSignalExternalUserIdCallback(Dictionary results) - { - // The results will contain push and email success statuses - Console.WriteLine("External user id updated with results: " + Json.Serialize(results)); - - // Push can be expected in almost every situation with a success status, but - // as a pre-caution its good to verify it exists - if (results.ContainsKey("push")) - { - Dictionary pushStatusDict = results["push"] as Dictionary; - if (pushStatusDict.ContainsKey("success")) - { - Console.WriteLine("External user id updated for push with results: " + pushStatusDict["success"] as string); - } - } - - // Verify the email is set or check that the results have an email success status - if (results.ContainsKey("email")) - { - Dictionary emailStatusDict = results["email"] as Dictionary; - if (emailStatusDict.ContainsKey("success")) - { - Console.WriteLine("External user id updated for email with results: " + emailStatusDict["success"] as string); - } - } - } - - private void OneSignalExternalUserIdCallbackFailure(Dictionary error) - { - // The results will contain push and email success statuses - Console.WriteLine("External user id failed with error: " + Json.Serialize(error)); - } - - // Examples of using OneSignal In-App Message triggers - private void OneSignalInAppMessageTriggerExamples() { - // Add a single trigger - OneSignal.AddTrigger("key", "value"); - - // Get the current value to a trigger by key - var triggerKey = "key"; - var triggerValue = OneSignal.GetTriggerValueForKey(triggerKey); - String output = "Trigger key: " + triggerKey + " value: " + (String) triggerValue; - Console.WriteLine(output); - - // Add multiple triggers - OneSignal.AddTriggers(new Dictionary() { { "key1", "value1" }, { "key2", 2 } }); - - // Delete a trigger - OneSignal.RemoveTriggerForKey("key"); - - // Delete a list of triggers - OneSignal.RemoveTriggersForKeys(new List() { "key1", "key2" }); - - // Temporarily pause In-App messages; If true is passed in. - // Great to ensure you never interrupt your user while they are in the middle of a match in your game. - OneSignal.PauseInAppMessages(false); - } - - private void OneSignalOutcomeEventsExamples() { - OneSignal.SendOutcome("normal_1"); - OneSignal.SendOutcome("normal_2", (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); - - OneSignal.SendUniqueOutcome("unique_1"); - OneSignal.SendUniqueOutcome("unique_2", (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); - - OneSignal.SendOutcomeWithValue("value_1", 3.2f); - OneSignal.SendOutcomeWithValue("value_2", 3.2f, (OSOutcomeEvent outcomeEvent) => { - printOutcomeEvent(outcomeEvent); - }); - } - - private void printOutcomeEvent(OSOutcomeEvent outcomeEvent) { - Console.WriteLine(outcomeEvent.session + "\n" + - string.Join(", ", outcomeEvent.notificationIds) + "\n" + - outcomeEvent.name + "\n" + - outcomeEvent.timestamp + "\n" + - outcomeEvent.weight); - } - - private void OneSignal_subscriptionObserver(OSSubscriptionStateChanges stateChanges) { - Debug.Log("SUBSCRIPTION stateChanges: " + stateChanges); - Debug.Log("SUBSCRIPTION stateChanges.to.userId: " + stateChanges.to.userId); - Debug.Log("SUBSCRIPTION stateChanges.to.subscribed: " + stateChanges.to.subscribed); - } - - private void OneSignal_permissionObserver(OSPermissionStateChanges stateChanges) { - Debug.Log("PERMISSION stateChanges.from.status: " + stateChanges.from.status); - Debug.Log("PERMISSION stateChanges.to.status: " + stateChanges.to.status); - } - - private void OneSignal_emailSubscriptionObserver(OSEmailSubscriptionStateChanges stateChanges) { - Debug.Log("EMAIL stateChanges.from.status: " + stateChanges.from.emailUserId + ", " + stateChanges.from.emailAddress); - Debug.Log("EMAIL stateChanges.to.status: " + stateChanges.to.emailUserId + ", " + stateChanges.to.emailAddress); - } - - // Called when your app is in focus and a notification is received. - // The name of the method can be anything as long as the signature matches. - // Method must be static or this object should be marked as DontDestroyOnLoad - private static void HandleNotificationReceived(OSNotification notification) { - OSNotificationPayload payload = notification.payload; - string message = payload.body; - - print("GameControllerExample:HandleNotificationReceived: " + message); - print("displayType: " + notification.displayType); - extraMessage = "Notification received with text: " + message; - - Dictionary additionalData = payload.additionalData; - if (additionalData == null) - Debug.Log ("[HandleNotificationReceived] Additional Data == null"); - else - Debug.Log("[HandleNotificationReceived] message " + message + ", additionalData: " + Json.Serialize(additionalData) as string); - } - - // Called when a notification is opened. - // The name of the method can be anything as long as the signature matches. - // Method must be static or this object should be marked as DontDestroyOnLoad - public static void HandleNotificationOpened(OSNotificationOpenedResult result) { - OSNotificationPayload payload = result.notification.payload; - string message = payload.body; - string actionID = result.action.actionID; - - print("GameControllerExample:HandleNotificationOpened: " + message); - extraMessage = "Notification opened with text: " + message; - - Dictionary additionalData = payload.additionalData; - if (additionalData == null) - Debug.Log ("[HandleNotificationOpened] Additional Data == null"); - else - Debug.Log("[HandleNotificationOpened] message " + message + ", additionalData: " + Json.Serialize(additionalData) as string); - - if (actionID != null) { - // actionSelected equals the id on the button the user pressed. - // actionSelected will equal "__DEFAULT__" when the notification itself was tapped when buttons were present. - extraMessage = "Pressed ButtonId: " + actionID; - } - } - - public static void HandlerInAppMessageClicked(OSInAppMessageAction action) { - String logInAppClickEvent = "In-App Message Clicked: " + - "\nClick Name: " + action.clickName + - "\nClick Url: " + action.clickUrl + - "\nFirst Click: " + action.firstClick + - "\nCloses Message: " + action.closesMessage; - - print(logInAppClickEvent); - extraMessage = logInAppClickEvent; - } - - // Test Menu - // Includes SendTag/SendTags, getting the userID and pushToken, and scheduling an example notification - void OnGUI() { - GUIStyle customTextSize = new GUIStyle("button"); - customTextSize.fontSize = 30; - - GUIStyle guiBoxStyle = new GUIStyle("box"); - guiBoxStyle.fontSize = 30; - - GUIStyle textFieldStyle = new GUIStyle("textField"); - textFieldStyle.fontSize = 30; - - - float itemOriginX = 50.0f; - float itemWidth = Screen.width - 120.0f; - float boxWidth = Screen.width - 20.0f; - float boxOriginY = 120.0f; - float boxHeight = requiresUserPrivacyConsent ? 980.0f : 890.0f; - float itemStartY = 200.0f; - float itemHeightOffset = 90.0f; - float itemHeight = 60.0f; - - GUI.Box(new Rect(10, boxOriginY, boxWidth, boxHeight), "Test Menu", guiBoxStyle); - - float count = 0.0f; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SendTags", customTextSize)) { - // You can tags users with key value pairs like this: - OneSignal.SendTag("UnityTestKey", "TestValue"); - // Or use an IDictionary if you need to set more than one tag. - OneSignal.SendTags(new Dictionary() { { "UnityTestKey2", "value2" }, { "UnityTestKey3", "value3" } }); - - // You can delete a single tag with it's key. - // OneSignal.DeleteTag("UnityTestKey"); - // Or delete many with an IList. - // OneSignal.DeleteTags(new List() {"UnityTestKey2", "UnityTestKey3" }); - } - - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "GetIds", customTextSize)) { - OneSignal.IdsAvailable((userId, pushToken) => { - extraMessage = "UserID:\n" + userId + "\n\nPushToken:\n" + pushToken; - }); - } - - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "TestNotification", customTextSize)) { - extraMessage = "Waiting to get a OneSignal userId. Uncomment OneSignal.SetLogLevel in the Start method if it hangs here to debug the issue."; - OneSignal.IdsAvailable((userId, pushToken) => { - if (pushToken != null) { - // See https://documentation.onesignal.com/reference/create-notification for a full list of options. - // You can not use included_segments or any fields that require your OneSignal 'REST API Key' in your app for security reasons. - // If you need to use your OneSignal 'REST API Key' you will need your own server where you can make this call. - - var notification = new Dictionary(); - notification["contents"] = new Dictionary() { {"en", "Test Message"} }; - // Send notification to this device. - notification["include_player_ids"] = new List() { userId }; - // Example of scheduling a notification in the future. - //notification["send_after"] = System.DateTime.Now.ToUniversalTime().AddSeconds(30).ToString("U"); - - extraMessage = "Posting test notification now."; - - OneSignal.PostNotification(notification, (responseSuccess) => { - extraMessage = "Notification posted successful! Delayed by about 30 seconds to give you time to press the home button to see a notification vs an in-app alert.\n" + Json.Serialize(responseSuccess); - }, (responseFailure) => { - extraMessage = "Notification failed to post:\n" + Json.Serialize(responseFailure); - }); - } else { - extraMessage = "ERROR: Device is not registered."; - } - }); - } - - count++; - - email = GUI.TextField(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), email, customTextSize); - - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SetEmail", customTextSize)) { - extraMessage = "Setting email to " + email; - - OneSignal.SetEmail (email, () => { - Debug.Log("Successfully set email"); - }, (error) => { - Debug.Log("Encountered error setting email: " + Json.Serialize(error)); - }); - } - - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "LogoutEmail", customTextSize)) { - extraMessage = "Logging Out of example@example.com"; - - OneSignal.LogoutEmail (() => { - Debug.Log("Successfully logged out of email"); - }, (error) => { - Debug.Log("Encountered error logging out of email: " + Json.Serialize(error)); - }); - } - - count++; - - externalId = GUI.TextField(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), externalId, customTextSize); - - count++; - - if (GUI.Button(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "SetExternalId", customTextSize)) { - OneSignal.SetExternalUserId(externalId, OneSignalExternalUserIdCallback); - // Auth external id method - // OneSignal.SetExternalUserId(externalId, "your_auth_hash_token", OneSignalExternalUserIdCallback, OneSignalExternalUserIdCallbackFailure); - } - - count++; - - if (GUI.Button(new Rect(itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), "RemoveExternalId", customTextSize)) { - OneSignal.RemoveExternalUserId(OneSignalExternalUserIdCallback); - } - - if (requiresUserPrivacyConsent) { - count++; - - if (GUI.Button (new Rect (itemOriginX, itemStartY + (count * itemHeightOffset), itemWidth, itemHeight), (OneSignal.UserProvidedConsent() ? "Revoke Privacy Consent" : "Provide Privacy Consent"), customTextSize)) { - extraMessage = "Providing user privacy consent"; - - OneSignal.UserDidProvideConsent(!OneSignal.UserProvidedConsent()); - } - } - - if (extraMessage != null) { - guiBoxStyle.alignment = TextAnchor.UpperLeft; - guiBoxStyle.wordWrap = true; - GUI.Box (new Rect (10, boxOriginY + boxHeight + 20, Screen.width - 20, Screen.height - (boxOriginY + boxHeight + 40)), extraMessage, guiBoxStyle); - } - } -} diff --git a/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs b/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs new file mode 100644 index 000000000..49241225f --- /dev/null +++ b/com.onesignal.unity.core/Samples~/OneSignalExampleBehaviour.cs @@ -0,0 +1,425 @@ +#if ONE_SIGNAL_INSTALLED +/* + * Modified MIT License + * + * Copyright 2021 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 UnityEngine; +using System.Collections.Generic; +using System; + +public class OneSignalExampleBehaviour : MonoBehaviour { + + /// + /// set to an email address you would like to test notifications against + /// + public string email = "EMAIL_ADDRESS"; + + /// + /// set to an external user id you would like to test notifications against + /// + public string externalId = "EXTERNAL_USER_ID"; + + /// + /// set to your app id (https://documentation.onesignal.com/docs/accounts-and-keys) + /// + public string appId = "ONESIGNAL_APP_ID"; + + /// + /// whether you would prefer OneSignal Unity SDK prevent initialization until consent is granted via + /// in this test MonoBehaviour + /// + public bool requiresUserPrivacyConsent; + + /// + /// we recommend initializing OneSignal early in your application's lifecycle such as in the Start method of a + /// MonoBehaviour in your opening Scene + /// + private void Start() { + _logMessage = null; + + // Enable line below to debug issues with OneSignal. (logLevel, visualLogLevel) + OneSignal.SetLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE); + + /* + * If you set to true, the user will have to provide consent via OneSignal.UserDidProvideConsent(true) before + * the SDK will initialize + */ + OneSignal.SetRequiresUserPrivacyConsent(requiresUserPrivacyConsent); + + /* + * The only required method you need to call to setup OneSignal to receive push notifications. + * Call before using any other methods on OneSignal (except setLogLevel or SetRequiredUserPrivacyConsent) + * Should only invoke once when your app is loaded. + */ + OneSignal.StartInit(appId) + .HandleNotificationReceived(HandleNotificationReceived) + .HandleNotificationOpened(HandleNotificationOpened) + .HandleInAppMessageClicked(OnInAppMessageClicked) + .EndInit(); + + // Control how OneSignal notifications will be shown when one is received while your app is in focus + OneSignal.inFocusDisplayType = OneSignal.OSInFocusDisplayOption.Notification; + + // Each of these events can inform your application when the user's OneSignal states have change + OneSignal.permissionObserver += OnPermissionStateChange; + OneSignal.subscriptionObserver += OnSubscriptionStateChange; + OneSignal.emailSubscriptionObserver += OnEmailSubscriptionStateChange; + + // You can also get the current states directly + var fullUserState = OneSignal.GetPermissionSubscriptionState(); + var permissionState = fullUserState.permissionStatus; + var subscriptionState = fullUserState.subscriptionStatus; + var emailSubscriptionState = fullUserState.emailSubscriptionStatus; + + OneSignalInAppMessageTriggerExamples(); + OneSignalOutcomeEventsExamples(); + } + + /// + /// Examples of using OneSignal External User Id + /// + private void OnUpdatedExternalUserId(Dictionary results) { + // The results will contain push and email success statuses + print($"External user id updated with results: {Json.Serialize(results)}"); + + // Push can be expected in almost every situation with a success status, but + // as a pre-caution its good to verify it exists + if (results.ContainsKey("push")) { + if (results["push"] is Dictionary pushStatus && pushStatus.ContainsKey("success")) + print($"External user id updated for push with results: {pushStatus["success"]}"); + } + + // Verify the email is set or check that the results have an email success status + if (results.ContainsKey("email")) { + if (results["email"] is Dictionary emailStatus && emailStatus.ContainsKey("success")) + print($"External user id updated for email with results: {emailStatus["success"]}"); + } + } + + private void OnUpdatedExternalUserIdFailure(Dictionary error) { + // As above the results will contain push and email statuses + print($"External user id failed with error: {Json.Serialize(error)}"); + } + + /// + /// Examples of using OneSignal In-App Message triggers + /// https://documentation.onesignal.com/docs/in-app-message-examples + /// + private static void OneSignalInAppMessageTriggerExamples() { + // Add a single trigger + OneSignal.AddTrigger("key", "value"); + + // Get the current value to a trigger by key + var triggerKey = "key"; + var triggerValue = OneSignal.GetTriggerValueForKey(triggerKey); + print($"Trigger key: {triggerKey} value: {triggerValue}"); + + // Add multiple triggers + OneSignal.AddTriggers(new Dictionary { + { "key1", "value1" }, + { "key2", 2 } + }); + + // Delete a trigger + OneSignal.RemoveTriggerForKey("key"); + + // Delete a list of triggers + OneSignal.RemoveTriggersForKeys(new List { "key1", "key2" }); + + // Temporarily pause In-App messages; If true is passed in. + // Great to ensure you never interrupt your user while they are in the middle of a match in your game. + OneSignal.PauseInAppMessages(false); + } + + /// + /// Send data to OneSignal which will allow you to track the result of notifications + /// https://documentation.onesignal.com/docs/outcomes + /// + private static void OneSignalOutcomeEventsExamples() { + // Send a result which can occur multiple times + OneSignal.SendOutcome("normal_1"); + OneSignal.SendOutcome("normal_2", OnSendOutcomeSuccess); + + // Send a result which can only occur once + OneSignal.SendUniqueOutcome("unique_1"); + OneSignal.SendUniqueOutcome("unique_2", OnSendOutcomeSuccess); + + // Send a result which can occur multiple times with a float value + OneSignal.SendOutcomeWithValue("value_1", 3.2f); + OneSignal.SendOutcomeWithValue("value_2", 3.2f, OnSendOutcomeSuccess); + } + + private static void OnSendOutcomeSuccess(OSOutcomeEvent outcomeEvent) { + print(outcomeEvent.session + "\n" + + string.Join(", ", outcomeEvent.notificationIds) + "\n" + + outcomeEvent.name + "\n" + + outcomeEvent.timestamp + "\n" + + outcomeEvent.weight); + } + + /* + * State change events provide both the new (to) and previous (from) states + */ + + private void OnSubscriptionStateChange(OSSubscriptionStateChanges stateChanges) { + print("SUBSCRIPTION stateChanges: " + stateChanges); + print("SUBSCRIPTION stateChanges.to.userId: " + stateChanges.to.userId); + print("SUBSCRIPTION stateChanges.to.subscribed: " + stateChanges.to.subscribed); + } + + private void OnPermissionStateChange(OSPermissionStateChanges stateChanges) { + print($"PERMISSION stateChanges.from.status: {stateChanges.from.status}"); + print($"PERMISSION stateChanges.to.status: {stateChanges.to.status}"); + } + + private void OnEmailSubscriptionStateChange(OSEmailSubscriptionStateChanges stateChanges) { + print($"EMAIL stateChanges.from.status: {stateChanges.from.emailUserId}, {stateChanges.from.emailAddress}"); + print($"EMAIL stateChanges.to.status: {stateChanges.to.emailUserId}, {stateChanges.to.emailAddress}"); + } + + /// + /// Called when your app is in focus and a notification is received. + /// The name of the method can be anything as long as the signature matches. + /// Method must be static or this object should be marked as DontDestroyOnLoad + /// + private static void HandleNotificationReceived(OSNotification notification) { + var payload = notification.payload; + var message = payload.body; + + print("GameControllerExample:HandleNotificationReceived: " + message); + print("displayType: " + notification.displayType); + _logMessage = "Notification received with text: " + message; + + print(payload.additionalData != null && Json.Serialize(payload.additionalData) is { } dataString + ? $"[HandleNotificationReceived] message {message}, additionalData: {dataString}" + : "[HandleNotificationReceived] Additional Data == null" + ); + } + + /// + /// Called when a notification is opened. + /// The name of the method can be anything as long as the signature matches. + /// Method must be static or this object should be marked as DontDestroyOnLoad + /// + private static void HandleNotificationOpened(OSNotificationOpenedResult result) { + var payload = result.notification.payload; + var message = payload.body; + var actionID = result.action.actionID; + + print("GameControllerExample:HandleNotificationOpened: " + message); + _logMessage = "Notification opened with text: " + message; + + print(payload.additionalData != null && Json.Serialize(payload.additionalData) is { } dataString + ? $"[HandleNotificationOpened] message {message}, additionalData: {dataString}" + : "[HandleNotificationOpened] Additional Data == null" + ); + + if (actionID != null) { + // actionSelected equals the id on the button the user pressed. + // actionSelected will equal "__DEFAULT__" when the notification itself was tapped when buttons were present. + _logMessage = "Pressed ButtonId: " + actionID; + } + } + + private static void OnInAppMessageClicked(OSInAppMessageAction action) { + var logInAppClickEvent = "In-App Message Clicked: " + + "\nClick Name: " + action.clickName + + "\nClick Url: " + action.clickUrl + + "\nFirst Click: " + action.firstClick + + "\nCloses Message: " + action.closesMessage; + + print(logInAppClickEvent); + _logMessage = logInAppClickEvent; + } + + /// + /// See https://documentation.onesignal.com/reference/create-notification for a full list of options. + /// + /// + /// You can not use included_segments or any fields that require your OneSignal 'REST API Key' in your app for + /// security reasons. + /// If you need to use your OneSignal 'REST API Key' you will need your own server where you can make this call. + /// + private static void SendTestNotification(string userId) { + var notification = new Dictionary { + ["contents"] = new Dictionary { { "en", "Test Message" } }, + + // Send notification to this user + ["include_player_ids"] = new List { userId }, + + // Example of scheduling a notification in the future. + ["send_after"] = DateTime.Now.ToUniversalTime().AddSeconds(30).ToString("U") + }; + + _logMessage = "Posting test notification now. By default the example should arrive 30 seconds in the future." + + "If you would like to see it as a Push and not an In App Alert then please leave the application."; + OneSignal.PostNotification(notification, OnNotificationPostSuccess, OnNotificationPostFailure); + } + + private static void OnNotificationPostSuccess(Dictionary response) + => _logMessage = "Notification post success!\n" + Json.Serialize(response); + + private static void OnNotificationPostFailure(Dictionary response) + => _logMessage = "Notification failed to post:\n" + Json.Serialize(response); + + /* + * UI Rendering + */ + + private const float ItemOriginX = 50.0f; + private const float BoxOriginY = 120.0f; + private const float ItemStartY = 200.0f; + private const float ItemHeightOffset = 90.0f; + private const float ItemHeight = 60.0f; + + private static string _logMessage; + + private GUIStyle _customTextSize; + private GUIStyle _guiBoxStyle; + + private static float ItemWidth => Screen.width - 120.0f; + private static float BoxWidth => Screen.width - 20.0f; + private float BoxHeight => requiresUserPrivacyConsent ? 980.0f : 890.0f; + + private Rect MainMenuRect => new Rect(10, BoxOriginY, BoxWidth, BoxHeight); + + private static Rect ItemRect(ref int position) => new Rect( + ItemOriginX, + ItemStartY + position++ * ItemHeightOffset, + ItemWidth, + ItemHeight + ); + + private bool MenuButton(ref int position, string label) + => GUI.Button(ItemRect(ref position), label, _customTextSize); + + // Test Menu + // Includes SendTag/SendTags, getting the userID and pushToken, and scheduling an example notification + private void OnGUI() { + _customTextSize ??= new GUIStyle(GUI.skin.button) { + fontSize = 30 + }; + + _guiBoxStyle ??= new GUIStyle(GUI.skin.box) { + fontSize = 30, + alignment = TextAnchor.UpperLeft, + wordWrap = true + }; + + GUI.Box(MainMenuRect, "Test Menu", _guiBoxStyle); + + int position = 0; + + if (MenuButton(ref position, "Send Example Tags")) { + // You can tags users with key value pairs like this: + OneSignal.SendTag("UnityTestKey", "TestValue"); + + // Or use an IDictionary if you need to set more than one tag. + OneSignal.SendTags(new Dictionary { + { "UnityTestKey2", "value2" }, + { "UnityTestKey3", "value3" } + }); + + // You can delete a single tag with it's key. + // OneSignal.DeleteTag("UnityTestKey"); + // Or delete many with an IList. + // OneSignal.DeleteTags(new List() {"UnityTestKey2", "UnityTestKey3" }); + } + + if (MenuButton(ref position, "Get Ids")) { + OneSignal.IdsAvailable((userId, pushToken) => { + _logMessage = $"UserID:\n{userId}\n\nPushToken:\n{pushToken}"; + }); + } + + if (MenuButton(ref position, "Test Notification")) { + _logMessage = "Waiting to get a OneSignal userId. Uncomment OneSignal.SetLogLevel in the Start method if " + + "it hangs here to debug the issue."; + + // Checking to make sure this device is registered or you will not receive the notification + OneSignal.IdsAvailable((userId, pushToken) => { + if (pushToken != null) + SendTestNotification(userId); + else + _logMessage = "ERROR: Device is not registered."; + }); + } + + email = GUI.TextField(ItemRect(ref position), email, _customTextSize); + + if (MenuButton(ref position, "Set Email")) { + _logMessage = "Setting email to " + email; + + OneSignal.SetEmail(email, + () => print("Successfully set email"), + error => printError("Error setting email: " + Json.Serialize(error)) + ); + } + + if (MenuButton(ref position, "Logout Email")) { + _logMessage = "Logging Out of example@example.com"; + + OneSignal.LogoutEmail( + () => print("Successfully logged out of email"), + error => printError("Error logging out of email: " + Json.Serialize(error)) + ); + } + + externalId = GUI.TextField(ItemRect(ref position), externalId, _customTextSize); + + if (MenuButton(ref position, "Set External Id")) + OneSignal.SetExternalUserId(externalId, OnUpdatedExternalUserId); + + if (MenuButton(ref position, "Remove External Id")) + OneSignal.RemoveExternalUserId(OnUpdatedExternalUserId); + + if (requiresUserPrivacyConsent) { + var consentText = OneSignal.UserProvidedConsent() + ? "Revoke Privacy Consent" + : "Provide Privacy Consent"; + + if (GUI.Button(ItemRect(ref position), consentText, _customTextSize)) { + _logMessage = "Providing user privacy consent"; + + OneSignal.UserDidProvideConsent(!OneSignal.UserProvidedConsent()); + } + } + + if (_logMessage != null) { + var logRect = new Rect( + 10, + BoxOriginY + BoxHeight + 20, + Screen.width - 20, + Screen.height - (BoxOriginY + BoxHeight + 40) + ); + + GUI.Box(logRect, _logMessage, _guiBoxStyle); + } + } + + private static void printError(object message) => Debug.LogError(message); +} +#endif \ No newline at end of file diff --git a/com.onesignal.unity.core/Samples~/OneSignalExampleScene.unity b/com.onesignal.unity.core/Samples~/OneSignalExampleScene.unity index 6de92fb7e..dff005d04 100644 --- a/com.onesignal.unity.core/Samples~/OneSignalExampleScene.unity +++ b/com.onesignal.unity.core/Samples~/OneSignalExampleScene.unity @@ -241,7 +241,7 @@ MonoBehaviour: m_GameObject: {fileID: 1816083100} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 327cfd461164140378248387917903e7, type: 3} + m_Script: {fileID: 11500000, guid: 9e0cf583b67c419894c77bc78acc66c4, type: 3} m_Name: m_EditorClassIdentifier: email: Email Address