Skip to content

Modernize hello-dotnet-client: .NET 8, GitHub Actions CI, MAUI apps, hello-apps spec#17

Merged
kinyoklion merged 14 commits intomainfrom
devin/1772650677-modernize-hello-dotnet-client
Mar 5, 2026
Merged

Modernize hello-dotnet-client: .NET 8, GitHub Actions CI, MAUI apps, hello-apps spec#17
kinyoklion merged 14 commits intomainfrom
devin/1772650677-modernize-hello-dotnet-client

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 4, 2026

Modernize hello-dotnet-client: .NET 8, GitHub Actions CI, MAUI apps, hello-apps spec

Summary

This PR modernizes the hello-dotnet-client repository to comply with the HELLO-hello-apps spec and adds .NET MAUI example apps for Android and iOS.

Console app modernization

  • Removed CircleCI — Replaced with GitHub Actions CI
  • Removed deprecated Xamarin projects — XamarinAndroidApp, XamarinIOSApp, and Shared project
  • Updated .NET version — From netcoreapp3.1 to net8.0
  • Implemented spec requirements:
    • Flag key changed to sample-feature (default)
    • Environment variables: LAUNCHDARKLY_MOBILE_KEY, LAUNCHDARKLY_FLAG_KEY, CI
    • Continuous mode with FlagValueChanged listener (disabled when CI env var is set)
    • ASCII art (Unicode full-block ██ characters) displayed when flag evaluates to true
    • Output format: The <flagKey> feature flag evaluates to <flagValue>. (lowercase true/false)
    • Context: key = "example-user-key", name = "Sandy"
  • Added GitHub Actions workflow — Uses verify-hello-app-v2.0.1 action
  • Updated README — Follows spec template

.NET MAUI app (new)

  • Single MAUI project (MauiApp/) targeting net8.0-android and net8.0-ios
  • OS-conditional TargetFrameworks — On Linux, only net8.0-android is included (iOS cannot build on Linux). On macOS/Windows, both targets are included. Controlled via MSBuild conditions in the csproj.
  • Spec-compliant UI: Background toggles between #373841 (flag false) and #00844B (flag true), white text, displays flag value
  • LaunchDarkly SDK integration: Async initialization, FlagValueChanged listener for real-time updates, thread-safe UI updates via MainThread.BeginInvokeOnMainThread()
  • Configuration via appsettings.json — Mobile key and flag key are read from a Resources/Raw/appsettings.json file (bundled as a MauiAsset, loaded at runtime via FileSystem.OpenAppPackageFileAsync). An appsettings.example.json template is committed; the actual appsettings.json is gitignored to prevent committing keys.
  • CI builds both platforms: Android on ubuntu-latest, iOS on macos-latest
  • Android emulator verification in CI — The Android app is installed on an API 29 x86_64 emulator and verified to display the correct flag evaluation text using uiautomator dump. This uses LaunchDarkly mobile key and flag key from AWS SSM Parameter Store (fetched via release-secrets action).
  • Added global.json to pin .NET 8 SDK — required because CI runners default to .NET 10, which rejects net8.0 targets as out-of-support
  • Namespace is HelloDotNetClient (not MauiApp) to avoid conflict with Microsoft.Maui.Hosting.MauiApp

CI & security

  • All GitHub Actions are pinned to full commit SHAs (per semgrep recommendation) with version comments for maintainability
  • MAUI builds leverage the conditional TargetFrameworks in the csproj — Linux builds Android only by default, macOS builds both Android and iOS
  • EmbedAssembliesIntoApk=true is set for Android CI builds to ensure assemblies are packaged in the APK (Debug builds use "fast deployment" by default which breaks emulator installation via adb install)

Updates since last revision

Android emulator verification (fourth reviewer comment)

Per the fourth reviewer comment, the Android MAUI app now runs on an emulator in CI and verifies flag evaluation:

  • macOS job now builds both Android AND iOS (previously only built iOS)
  • Ubuntu CI job installs and runs the Android APK on an API 29 x86_64 emulator using android-emulator-runner action
  • Verification script (.github/scripts/verify-maui-android.sh) installs APK, launches app, waits for SDK initialization with retries (4 attempts × 15s), captures logcat for crash debugging, and uses uiautomator dump to verify flag evaluation text appears in the UI
  • LaunchDarkly credentials are fetched from AWS SSM Parameter Store via release-secrets action and written to appsettings.json before building
  • Emulator performance optimizations: KVM permissions set, disk space freed (with dotnet: false to preserve .NET SDK)
  • Fixed native crash on emulator launch — Debug MAUI builds use "fast deployment" which doesn't embed assemblies in the APK, causing mono.MonoPackageManager.LoadApplication to crash. Fixed by adding -p:EmbedAssembliesIntoApk=true to the build command.

CI result: Android emulator test now passes ✅. The app launches successfully, initializes the SDK, and displays the correct flag evaluation text.

Threading fix (Devin Review finding)

  • Fixed UI thread safety issue in MainPage.xaml.cs:51-52 — The initial UpdateUI() call after await LdClient.InitAsync() could resume on a background thread (if the SDK uses ConfigureAwait(false) internally), causing potential crashes when accessing UI elements. Now correctly marshalled to main thread via MainThread.BeginInvokeOnMainThread(), consistent with other UI update paths.

Review & Testing Checklist for Human

  • Test MAUI iOS app on actual device/simulator — iOS has only been build-verified, never run. Test on an iPhone simulator or device to verify:
    • App launches without crashing
    • The appsettings.json file is correctly bundled and loaded
    • Flag value displays correctly with lowercase true/false
    • Background color toggles between dark (#373841) and green (#00844B) when flag changes
    • Real-time flag updates work
  • Test MAUI Android app on physical device — CI runs on API 29 x86_64 emulator successfully, but testing on real Android hardware (various API levels, architectures) is recommended to catch device-specific issues (native library incompatibilities, rendering differences, etc.)
  • Verify emulator test reliability — The CI emulator test retries 4 times with 15s waits. On slow runners, the SDK may not initialize within 60s. Monitor for flakiness over the next few runs.
  • Test conditional TargetFrameworks — Open the MAUI project in Visual Studio on macOS/Windows and verify both Android and iOS targets appear correctly. On Linux, verify only Android appears.
  • Verify global.json doesn't break developer workflows — The repo now requires .NET 8 SDK. Developers with only .NET 9/10 will need to install 8.0. Confirm this aligns with team standards.

Notes

  • The solution file now contains DotNetConsoleApp and MauiApp (Xamarin projects removed)
  • All GitHub Actions are pinned to commit SHAs with version tags in comments (e.g., @<sha> # v4)
  • SDK version uses 5.* wildcard to auto-update to latest 5.x releases per spec
  • MAUI app uses FlagTracker.FlagValueChanged (not FlagChanged) per SDK v5 API, same as console app
  • When CI env var is set, the console app runs once and exits; otherwise it runs continuously
  • There are benign XA0101 warnings from LaunchDarkly SDK content files on Android builds — these are from the SDK package metadata, not our code
  • Both console app and MAUI app use identical context configuration and SDK initialization patterns for consistency (example-user-key/Sandy)
  • The MauiApp/ directory uses namespace HelloDotNetClient — the directory name doesn't match the namespace to avoid conflict with framework types
  • The conditional TargetFrameworks approach uses RuntimeInformation.IsOSPlatform() — this is evaluated at build time, not runtime
  • MAUI configuration approach: The app reads MobileKey and FlagKey from appsettings.json using System.Text.Json. The file is loaded via FileSystem.OpenAppPackageFileAsync() (standard MAUI raw asset access). If the file is missing or the key equals the placeholder "my-mobile-key", an error message is shown.
  • Emulator verification approach: Uses uiautomator dump to capture the Android UI hierarchy as XML, then greps for the expected flag evaluation text. This works because MAUI renders Labels as native Android TextViews. The same technique is used by the hello-android reference repo.
  • Threading model: InitializeLaunchDarkly() is async void (required for event handler pattern from constructor). All UI updates are marshalled to main thread via MainThread.BeginInvokeOnMainThread(). Exceptions during SDK init are caught and displayed in UI.

Session: https://app.devin.ai/sessions/4f95213b47cd415e9a9628ab59d12bba
Requested by: rlamb@launchdarkly.com


Open with Devin

…I, comply with hello-apps spec

- Remove CircleCI configuration
- Remove deprecated Xamarin Android/iOS projects
- Remove Shared project, inline code into single Program.cs file
- Update target framework from netcoreapp3.1 to net8.0
- Update flag key to 'sample-feature' per spec
- Add environment variable support for mobile key (LAUNCHDARKLY_MOBILE_KEY) and flag key (LAUNCHDARKLY_FLAG_KEY)
- Add continuous mode with flag change listener (FlagValueChanged)
- Add CI mode (CI env var) to disable continuous behavior
- Add ASCII art display when flag evaluates to true
- Update output format to 'The <flagKey> feature flag evaluates to <flagValue>.'
- Add required code comments per spec
- Add GitHub Actions workflow using verify-hello-app action
- Update README.md to follow spec template
- Simplify solution file to single project

Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

- Use .ToString().ToLowerInvariant() for bool output to match spec's 'true'/'false'
- Use Unicode full-block characters (U+2588) for ASCII art per spec

Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
semgrep-code-launchdarkly[bot]

This comment was marked as resolved.

devin-ai-integration bot and others added 2 commits March 4, 2026 19:15
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
…th -p:TargetFrameworks

Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
@devin-ai-integration devin-ai-integration bot changed the title Modernize hello-dotnet-client: update to .NET 8, add GitHub Actions CI, comply with hello-apps spec Modernize hello-dotnet-client: .NET 8, GitHub Actions CI, MAUI apps, hello-apps spec Mar 4, 2026
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
…on macOS

Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
run: dotnet workload install maui

- name: Build MAUI app (Android)
run: dotnet build MauiApp -f net8.0-android
Copy link
Member

Choose a reason for hiding this comment

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

This is maybe a bit redundant. But it does help ensure things are working on mac.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed — it's a useful cross-platform sanity check to verify the Android build works on macOS too, even though the main Android build + emulator test runs on Ubuntu. I'll keep it as-is.

devin-ai-integration bot and others added 4 commits March 4, 2026 22:31
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Co-Authored-By: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
@kinyoklion kinyoklion self-requested a review March 5, 2026 00:06
@kinyoklion kinyoklion merged commit 3640614 into main Mar 5, 2026
4 checks passed
@kinyoklion kinyoklion deleted the devin/1772650677-modernize-hello-dotnet-client branch March 5, 2026 16:27
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