From 5ea0ca23348b5fb21f68edf4a6d933a14013b305 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Mon, 18 May 2026 14:30:56 -0700 Subject: [PATCH] fix(android): prefer IDictionary over IList for JObject --- .../Utilities/AndroidJavaObjectExtensions.cs | 4 +- .../Runtime/Utilities/MiniJSON.cs | 10 +++-- .../Scripts/UI/Dialogs/TrackEventDialog.cs | 39 ++++++++++--------- examples/demo/run-android.sh | 36 ++++++++++++++++- examples/demo/run-ios.sh | 15 ++++++- 5 files changed, 78 insertions(+), 26 deletions(-) diff --git a/com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs b/com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs index 960631414..97c65b921 100644 --- a/com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs +++ b/com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs @@ -173,7 +173,9 @@ public static AndroidJavaObject ToMap(this Dictionary source) case bool boolValue: value = new AndroidJavaObject("java.lang.Boolean", boolValue); break; - case Dictionary dictValue: + // Check IDictionary before IList: some dict-like types + // (e.g. Newtonsoft's JObject) also implement IList. + case System.Collections.IDictionary dictValue: value = new AndroidJavaObject( "org.json.JSONObject", Json.Serialize(dictValue) diff --git a/com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs b/com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs index df91487a0..5db0d0c97 100644 --- a/com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs +++ b/com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs @@ -509,14 +509,16 @@ void SerializeValue(object value) { builder.Append((bool)value ? "true" : "false"); } - else if ((asList = value as IList) != null) - { - SerializeArray(asList); - } + // Check IDictionary before IList: some dict-like types (e.g. Newtonsoft's + // JObject) also implement IList, and would otherwise be serialized as arrays. else if ((asDict = value as IDictionary) != null) { SerializeObject(asDict); } + else if ((asList = value as IList) != null) + { + SerializeArray(asList); + } else if (value is char) { SerializeString(new string((char)value, 1)); diff --git a/examples/demo/Assets/Scripts/UI/Dialogs/TrackEventDialog.cs b/examples/demo/Assets/Scripts/UI/Dialogs/TrackEventDialog.cs index b8547424a..efa7ff42a 100644 --- a/examples/demo/Assets/Scripts/UI/Dialogs/TrackEventDialog.cs +++ b/examples/demo/Assets/Scripts/UI/Dialogs/TrackEventDialog.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using OneSignalSDK; using UnityEngine.UIElements; namespace OneSignalDemo.UI.Dialogs @@ -75,14 +75,7 @@ private void ValidateInput() var propsText = _propertiesField?.value; if (!string.IsNullOrEmpty(propsText)) { - try - { - JsonConvert.DeserializeObject>(propsText); - } - catch - { - _jsonValid = false; - } + _jsonValid = TryParseProperties(propsText, out _); } _jsonError.style.display = _jsonValid ? DisplayStyle.None : DisplayStyle.Flex; @@ -97,20 +90,30 @@ private void OnConfirm() Dictionary props = null; var propsText = _propertiesField?.value; - if (!string.IsNullOrEmpty(propsText)) + if (!string.IsNullOrEmpty(propsText) && !TryParseProperties(propsText, out props)) { - try - { - props = JsonConvert.DeserializeObject>(propsText); - } - catch - { - return; - } + return; } _onConfirm?.Invoke(name, props); Dismiss(); } + + // Use the SDK's MiniJSON parser so nested objects/arrays come back as plain + // Dictionary / List. Newtonsoft would hand back + // JObject/JArray, which the native bridges then mis-serialize. + private static bool TryParseProperties(string propsText, out Dictionary props) + { + props = null; + try + { + props = Json.Deserialize(propsText) as Dictionary; + } + catch + { + return false; + } + return props != null; + } } } diff --git a/examples/demo/run-android.sh b/examples/demo/run-android.sh index 5e90e6951..fe6bafdb4 100755 --- a/examples/demo/run-android.sh +++ b/examples/demo/run-android.sh @@ -6,8 +6,39 @@ set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -UNITY="${UNITY_PATH:-/Applications/Unity/Hub/Editor/6000.3.6f1/Unity.app/Contents/MacOS/Unity}" -ADB="/Applications/Unity/Hub/Editor/6000.3.6f1/PlaybackEngines/AndroidPlayer/SDK/platform-tools/adb" + +# Auto-detect newest Unity 6000.x install under the Hub, unless UNITY_PATH is set. +find_unity() { + if [ -n "${UNITY_PATH:-}" ]; then + echo "$UNITY_PATH" + return + fi + for d in $(ls -1 /Applications/Unity/Hub/Editor 2>/dev/null | sort -rV); do + BIN="/Applications/Unity/Hub/Editor/$d/Unity.app/Contents/MacOS/Unity" + [ -x "$BIN" ] && echo "$BIN" && return + done +} +UNITY="$(find_unity)" + +# Resolve adb in this order: $ADB, $ANDROID_HOME/platform-tools, ~/Library/Android/sdk, +# `which adb`, then Unity's bundled Android SDK. +find_adb() { + if [ -n "${ADB:-}" ] && [ -x "$ADB" ]; then echo "$ADB"; return; fi + for CANDIDATE in \ + "${ANDROID_HOME:-}/platform-tools/adb" \ + "${ANDROID_SDK_ROOT:-}/platform-tools/adb" \ + "$HOME/Library/Android/sdk/platform-tools/adb"; do + [ -x "$CANDIDATE" ] && echo "$CANDIDATE" && return + done + if command -v adb >/dev/null 2>&1; then command -v adb; return; fi + if [ -n "$UNITY" ]; then + UNITY_DIR=$(dirname "$(dirname "$(dirname "$(dirname "$UNITY")")")") + CANDIDATE="$UNITY_DIR/PlaybackEngines/AndroidPlayer/SDK/platform-tools/adb" + [ -x "$CANDIDATE" ] && echo "$CANDIDATE" && return + fi +} +ADB="$(find_adb)" + OUTPUT="$SCRIPT_DIR/Build/Android/onesignal-demo.apk" LOG="$SCRIPT_DIR/Build/build-android.log" INSTALL=true @@ -21,6 +52,7 @@ for arg in "$@"; do done pick_emulator() { + [ -z "$ADB" ] && echo "adb not found. Set ADB or ANDROID_HOME to your Android SDK." && exit 1 LIST=$("$ADB" devices | awk '/emulator-[0-9]+[[:space:]]+device/{print $1}') COUNT=$(printf '%s\n' "$LIST" | grep -c . || true) diff --git a/examples/demo/run-ios.sh b/examples/demo/run-ios.sh index 84864207c..cacf2800c 100755 --- a/examples/demo/run-ios.sh +++ b/examples/demo/run-ios.sh @@ -6,7 +6,20 @@ set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -UNITY="${UNITY_PATH:-/Applications/Unity/Hub/Editor/6000.3.6f1/Unity.app/Contents/MacOS/Unity}" + +# Auto-detect newest Unity 6000.x install under the Hub, unless UNITY_PATH is set. +find_unity() { + if [ -n "${UNITY_PATH:-}" ]; then + echo "$UNITY_PATH" + return + fi + for d in $(ls -1 /Applications/Unity/Hub/Editor 2>/dev/null | sort -rV); do + BIN="/Applications/Unity/Hub/Editor/$d/Unity.app/Contents/MacOS/Unity" + [ -x "$BIN" ] && echo "$BIN" && return + done +} +UNITY="$(find_unity)" + XCODE_DIR="$SCRIPT_DIR/Build/iOS" LOG="$SCRIPT_DIR/Build/build-ios.log" SCHEME="Unity-iPhone"