Skip to content

chore: Release 6.1.5#174

Open
onesignal-deploy wants to merge 2 commits intomainfrom
rel/6.1.5
Open

chore: Release 6.1.5#174
onesignal-deploy wants to merge 2 commits intomainfrom
rel/6.1.5

Conversation

@onesignal-deploy
Copy link
Copy Markdown
Collaborator

@onesignal-deploy onesignal-deploy commented Apr 28, 2026

Channels: Current

🛠️ Native Dependency Updates

  • Update Android SDK from 5.7.7 to 5.8.0
    • feat: hash PII (email/SMS) in SharedPreferences at rest (#2620)
    • feat: SDK-4176: gate background threading behind remote feature flag (#2595)
    • feat: SDK-4210: Standardize BACKGROUND_THREADING feature flag key naming (#2598)
    • feat: SDK-4363: Turbine remote SDK feature flags and foreground refresh (#2612)
    • bug: catch exception if opening a notification fails (#2508)
    • Fix: a rare NPE from PermissionViewModel (#2504)
    • fix: add retry for notification opened confirmation (#2606)
    • fix: end initialization early if device storage is locked (#2520)
  • Update iOS SDK from 5.5.0 to 5.5.1

@onesignal-deploy onesignal-deploy requested a review from a team as a code owner April 28, 2026 23:13
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<version>6.1.4</version>
<version>6.1.5</version>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Android SDK 5.8.0 introduces a new runtime dependency on kotlinx-serialization-json:1.6.3 (declared in the upstream core-5.8.0.pom) used by the new FeatureFlagsJsonParser/FeatureFlagsRefreshService/RemoteFeatureFlagsResult classes shipped in this PR's core-release.aar, but neither the nuspec (lines 22-39) nor OneSignalSDK.DotNet.Android.csproj declares an equivalent Xamarin.KotlinX.Serialization.Json package. Since Xamarin AAR transitive deps are not auto-resolved (the existing Dagger comment in the csproj documents exactly this caveat), consumers of 6.1.5 will hit java.lang.NoClassDefFoundError: kotlinx.serialization.json.Json when the new remote feature-flag fetch path runs during SDK init. Fix: add Xamarin.KotlinX.Serialization.Json (matching upstream version 1.6.3) to the net10.0-android21.0 group in the nuspec and as a PackageReference in OneSignalSDK.DotNet.Android.csproj.

Extended reasoning...

What the bug is

OneSignal Android SDK 5.8.0 introduces a new feature-flag refresh subsystem (upstream PRs SDK-4176 / SDK-4210 / SDK-4363) that uses Kotlin serialization to parse remote JSON responses. The new FeatureFlagsJsonParser class in the bundled core-release.aar declares a private static final kotlinx.serialization.json.Json format field and uses the Json { … } DSL (JsonBuilder.setIgnoreUnknownKeys, setLenient, etc.), plus JsonObject/JsonElement/JsonPrimitive/JsonArray types. None of these classes are bundled inside the AAR's classes.jar — only com/onesignal/* is present.

The corresponding upstream Maven POM (com.onesignal:core:5.8.0) declares org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3 as a runtime dependency, which is how the OneSignal Android SDK consumers normally pick it up. But Xamarin/.NET binding projects do not auto-resolve Maven transitive dependencies for <LibraryProjectZip>-style AAR consumption — the existing comment on the Xamarin.Google.Dagger line in OneSignalSDK.DotNet.Android.csproj documents this exact limitation (xamarin/XamarinComponents#1069). Each native runtime dependency must be mirrored as an explicit Xamarin.* NuGet package.

Why the existing dependencies don't cover it

The net10.0-android21.0 dependency group in OneSignalSDK.DotNet.nuspec (lines 22-39) declares only Xamarin.Kotlin.StdLib.Jdk8, Xamarin.KotlinX.Coroutines.Core/Android, the AndroidX.* set, Firebase.Messaging, Google.Dagger, and GooglePlayServices.Base. None of these transitively pulls in kotlinx-serialization-json — it is a separate artifact (Xamarin.KotlinX.Serialization.Json on NuGet). A repo-wide grep for Serialization returns only an iOS file. The same omission holds for OneSignalSDK.DotNet.Android.csproj and OneSignalSDK.DotNet.Android.Core.Binding.csproj.

The previous 5.7.7 AAR did not reference any kotlinx/serialization/json/* types, so the dependency was correctly absent before — this is genuinely a 5.8.0 regression introduced by this PR. The pattern of mirroring native dep changes alongside AAR bumps is established (PR #171 / 6.1.4 bumped Xamarin.Kotlin.StdLib.Jdk8 from 1.8.0.1 to 1.9.23.3 alongside its AAR bump).

Why CI doesn't catch it

The release workflow in .github/workflows/create-release-pr.yml runs only dotnet build. The .NET compiler validates against the AAR's class metadata — it doesn't load the missing kotlinx.serialization.json.* classes at compile time, and the build will succeed cleanly. The error only surfaces at runtime on a real Android device when the JVM classloader tries to resolve Lkotlinx/serialization/json/Json; and fails.

Step-by-step proof

  1. App developer installs OneSignalSDK.DotNet 6.1.5 from NuGet.
  2. NuGet resolves the net10.0-android21.0 dependency group and pulls in the eight packages declared in the nuspec — none of which is Xamarin.KotlinX.Serialization.Json.
  3. App calls OneSignal.Initialize(...) on Android.
  4. The 5.8.0 init path schedules a remote feature-flag fetch (per upstream PR #2612 "Turbine remote SDK feature flags and foreground refresh").
  5. FeatureFlagsRefreshService invokes FeatureFlagsJsonParser.parseSuccessful(...).
  6. JVM eagerly resolves the format static field's type: Lkotlinx/serialization/json/Json;.
  7. Classloader fails to find the class in any DEX in the APK (because the package author never declared the dependency, so it was never packaged).
  8. java.lang.NoClassDefFoundError: kotlinx.serialization.json.Json is thrown, propagating up and breaking the SDK init / feature-flag path on every consumer device.

How to fix

Add to the net10.0-android21.0 group of OneSignalSDK.DotNet.nuspec and to OneSignalSDK.DotNet.Android/OneSignalSDK.DotNet.Android.csproj (matching the existing Coroutines/StdLib pattern):

<dependency id="Xamarin.KotlinX.Serialization.Json" version="1.6.3.x" />

(pick the latest Xamarin.KotlinX.Serialization.Json NuGet that wraps kotlinx-serialization-json:1.6.3, matching the upstream POM).

Comment thread versions.json
@@ -1,4 +1,4 @@
{
"android": "5.7.7",
"android": "5.8.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟣 Android SDK 5.8.0's core POM declares com.onesignal:otel:5.8.0 as a runtime dependency, but the .NET binding does not bundle this AAR — update_native_binaries.sh only fetches core/notifications/location/in-app-messages, and there is no OneSignalSDK.DotNet.Android.Otel.Binding project. The bundled core-release.aar holds direct symbolic references to ~11 com.onesignal.otel.* types from classes wired into SDK init (OtelLifecycleManager, OneSignalCrashUploaderWrapper, OneSignalCrashHandlerFactory, AndroidOtelLogger, OtelAnrDetector), so the new 5.8.0 crash-uploader / ANR / OpenTelemetry features will be non-functional and will surface NoClashDefFoundError whenever those code paths are exercised. Pre-existing — the otel split was introduced in 5.7.0 and 6.1.4 already shipped with the same gap, but bumping to 5.8.0 expands the otel surface area, so this release is a natural opportunity to add an Otel.Binding project + curl line + nuspec entry.

Extended reasoning...

What is broken

Starting with Android SDK 5.7.0, OneSignal split its OpenTelemetry / crash-uploader code into a separate Maven artifact, com.onesignal:otel. The com.onesignal:core:5.8.0 POM (https://repo1.maven.org/maven2/com/onesignal/core/5.8.0/core-5.8.0.pom) declares com.onesignal:otel:5.8.0 as a runtime <dependency>. Inside core-release.aar, ~11 distinct com.onesignal.otel.* symbols (IOtelLogger, IOtelCrashHandler, IOtelOpenTelemetryRemote, IOtelPlatformProvider, OtelFactory, crash/IOtelAnrDetector, crash/OtelCrashUploader, etc.) are referenced as method parameters, return types, and field types from compiled classes such as OtelLifecycleManager, OneSignalCrashUploaderWrapper, OneSignalCrashHandlerFactory, AndroidOtelLogger, and OtelAnrDetector. None of those com/onesignal/otel/* classes live anywhere inside the four AARs shipped in this PR.

Why the .NET binding is affected

update_native_binaries.sh (lines 61–78) only curls four artifacts: core, notifications, location, in-app-messages. There is no OneSignalSDK.DotNet.Android.Otel.Binding project, no otel AAR under any Jars/ directory, and no Xamarin/NuGet dependency in the nuspec that would supply the com.onesignal.otel.* package transitively. The bundled AndroidManifest.xml even contains tools:overrideLibrary="com.onesignal.otel", which only makes sense if the otel module is supposed to be linked alongside core.

Step-by-step proof of the runtime crash

  1. Consumer app initializes OneSignal: OneSignal.Default.Initialize(appId).
  2. .NET binding calls into Java com.onesignal.OneSignal, which invokes OneSignalImp.initEssentials(Context).
  3. OneSignalImp.initEssentials bytecode news an OtelLifecycleManager and calls initializeFromCachedConfig() (verified via javap of OneSignalImp.class, constants #452–#463).
  4. OtelLifecycleManager has fields/methods typed as com.onesignal.otel.IOtelCrashHandler, com.onesignal.otel.IOtelOpenTelemetryRemote, com.onesignal.otel.crash.IOtelAnrDetector — first execution of these methods forces the Android verifier/class-loader to resolve com/onesignal/otel/IOtelCrashHandler, which is not present, throwing NoClassDefFoundError.
  5. Independently, OneSignalCrashUploaderWrapper is registered as an IStartableService in the core module and runs at SDK init. On API ≥ 26 (OtelSdkSupport.isSupported) it invokes getUploader(), whose return type is com.onesignal.otel.crash.OtelCrashUploader — same NoClassDefFoundError story.

Addressing the refutation

The refuter argued (a) duplicate of bug_004, (b) pre-existing in 5.7.x without consumer reports, (c) defensively gated behind a feature flag, and therefore not actionable. Points (a) and (b) are accepted — the synthesis description acknowledges this is pre-existing, which is exactly why this report is filed at pre_existing severity rather than normal. On (c): OneSignalCrashUploaderWrapper.start() does have a Throwable catch around its lambda (so that path silently logs "Crash uploader failed to start"), and OtelLifecycleManager.initializeFromCachedConfig will short-circuit when the remote feature flag is off — which is presumably why widespread crash reports have not surfaced. But that defensive behavior depends on (i) Android's lazy class verification not eagerly resolving the missing types and (ii) OneSignal's server keeping the SDK-4363 telemetry flag off for .NET clients. As soon as the flag flips on (or a future version inlines an otel call into a path without a Throwable catch), every .NET consumer will start logging NoClassDefFoundError and lose the advertised 5.8.0 ANR / OpenTelemetry / crash-uploader functionality outright.

How to fix

Add a new OneSignalSDK.DotNet.Android.Otel.Binding project mirroring the existing four binding projects, add a curl line in update_native_binaries.sh for https://repo1.maven.org/maven2/com/onesignal/otel/$ANDROID_VERSION/otel-$ANDROID_VERSION.aar, add the AAR + binding DLL/PDB to OneSignalSDK.DotNet.nuspec, and reference the binding from OneSignalSDK.DotNet.csproj. Since the otel artifact has its own transitive deps (OpenTelemetry-android, etc.), those should also be declared as nuspec dependencies. This release is a natural place to land that work, but if the team prefers to do it in a follow-up, that is reasonable given the long-standing lack of consumer reports.

Why this is filed as pre_existing rather than normal: the gap was introduced in Android SDK 5.7.0 and has shipped in every 6.x .NET release since. This PR does not introduce it; it merely inherits it. The classification follows the synthesis agent's own characterization.

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.

1 participant