Skip to content

fix: [SDK-4523] Unity custom event nested property encoding#871

Merged
fadi-george merged 1 commit into
mainfrom
fadi/sdk-4523
May 19, 2026
Merged

fix: [SDK-4523] Unity custom event nested property encoding#871
fadi-george merged 1 commit into
mainfrom
fadi/sdk-4523

Conversation

@fadi-george
Copy link
Copy Markdown
Collaborator

@fadi-george fadi-george commented May 18, 2026

Description

One Line Summary

Fix Unity custom event properties losing nested objects/typed arrays on the way to the dashboard, plus add the GitHub Actions E2E workflow that runs the Appium suite against the demo app.

Screenshot 2026-05-18 at 2 57 19 PM Screenshot 2026-05-18 at 2 54 59 PM Screenshot 2026-05-18 at 2 47 28 PM Screenshot 2026-05-18 at 2 41 05 PM

Details

Motivation

Linear: SDK-4523 Unity Custom Events.

OneSignal.User.TrackEvent(name, properties) on Unity was mangling complex property values on both Android and iOS. Given:

{
  "someNum": 123,
  "someFloat": 3.14159,
  "someObject": { "abc": "123", "nested": { "def": "456" }, "ghi": null },
  "someArray": [1, 2],
  "someMixedArray": [1, "2", { "abc": "123" }, null]
}

the dashboard received:

{
  "someArray": ["1", "2"],
  "someObject": [null, null, null],
  "someMixedArray": ["1", "2", null, ""]
}

Two root causes:

  1. MiniJSON serializer (com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs) checked IList before IDictionary. Any dict-like type that also implements IList (Newtonsoft's JObject is the common case, since JContainer : IList<JToken>) was serialized as a JSON array of its child JProperty items, producing [null, null, null] for a 3-key object.
  2. Android ToMap (com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs) switched on the concrete type Dictionary<string, object> only. JObject is not Dictionary<string, object>, so it fell into the IList case and was treated as a JSON array.

Demo on top of that used Newtonsoft.JsonConvert.DeserializeObject<Dictionary<string, object>>, which is exactly the path that surfaces JObject/JArray wrappers.

Scope

  • Fixes nested object + nested array + typed-primitive (int, double) property encoding for OneSignal.User.TrackEvent on iOS and Android.
  • Does not change the public Unity API. Direct callers using plain Dictionary<string, object> / List<object> continue to work as before.
  • Adds the GitHub Actions E2E workflow that builds the Unity demo for Android emulator + iOS device and runs the shared Appium suite. Required for [SDK-4406] / future regression coverage of this fix.
  • run-android.sh / run-ios.sh now auto-detect Unity (newest 6000.x under the Hub) and adb (ANDROID_HOME, ~/Library/Android/sdk, which adb, then Unity's bundled SDK) instead of hardcoding a specific editor version.

Changes by file

Area File Change
SDK com.onesignal.unity.core/Runtime/Utilities/MiniJSON.cs Check IDictionary before IList in SerializeValue
SDK com.onesignal.unity.android/Runtime/Utilities/AndroidJavaObjectExtensions.cs ToMap matches IDictionary before IList (replaces strict Dictionary<string, object>)
Demo examples/demo/Assets/Scripts/UI/Dialogs/TrackEventDialog.cs Parse JSON via SDK's MiniJSON (returns native Dictionary<string, object> / List<object>) instead of Newtonsoft, which returns JObject/JArray
Demo examples/demo/run-android.sh, run-ios.sh Auto-detect Unity + adb, with env-var overrides
CI .github/workflows/e2e.yml, .github/actions/create-demo-env/action.yml, examples/demo/Assets/Scripts/Editor/BuildScript.cs Add the Unity demo E2E workflow (Android emulator + iOS device) and demo .env action

Testing

Manual testing

  • Sent TEST_JSON (see appium/tests/specs/10_event.spec.ts) on Android emulator (Pixel 6, API 34) and iOS Simulator (iPhone 16 Pro, iOS 26.2). Verified on the OneSignal dashboard that someObject is a nested object, someArray contains numbers (not strings), and someMixedArray preserves its inner object/null entries.
  • Verified the existing tracked-event behavior (top-level scalars + nulls) still round-trips correctly.
  • Ran ./run-android.sh and ./run-ios.sh with no UNITY_PATH / ADB set and confirmed they discover the newest installed Unity 6000.x and ~/Library/Android/sdk/platform-tools/adb.

Made temp changes to custom events section e.g.

            // ---- TEMP: SDK-4523 native nested-properties sanity check ----
            // Bypasses the dialog/MiniJSON parser to confirm Dictionary<string,object>
            // and List<object> nested data round-trips correctly to the dashboard.
            section.Add(
                SectionBuilder.CreatePrimaryButton(
                    "TRACK NATIVE TEST",
                    "track_native_test_button",
                    TrackNativeTest
                )
            );
            // ---- END TEMP ----

            return section;
        }

        // ---- TEMP: SDK-4523 ----
        private void TrackNativeTest()
        {
            var props = new Dictionary<string, object>
            {
                ["someNum"] = 123,
                ["someFloat"] = 3.14159,
                ["someString"] = "abc",
                ["someBool"] = true,
                ["someObject"] = new Dictionary<string, object>
                {
                    ["abc"] = "123",
                    ["nested"] = new Dictionary<string, object> { ["def"] = "456" },
                    ["ghi"] = null,
                },
                ["someArray"] = new List<object> { 1, 2 },
                ["someMixedArray"] = new List<object>
                {
                    1,
                    "2",
                    new Dictionary<string, object> { ["abc"] = "123" },
                    null,
                },
                ["someNull"] = null,
            };

            _viewModel.TrackEvent("props_native", props);
        }
        // ---- END TEMP ----
    }

to test props_native vs just the json parsing.

Unit / E2E

  • The shared Appium spec at appium/tests/specs/10_event.spec.ts exercises track_event_button with this JSON. The E2E workflow added in this PR will run that spec against the demo on every PR going forward.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing (Unity custom event property encoding + the E2E workflow that covers it)
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes (E2E suite via the new workflow)
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device

Final pass

  • Code is as readable as possible
  • I have reviewed this PR myself

@fadi-george fadi-george merged commit 6c6aa2b into main May 19, 2026
4 checks passed
@fadi-george fadi-george deleted the fadi/sdk-4523 branch May 19, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants