Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e7476f7
chore(*): maui sdk
Alexays May 22, 2026
79bc8f0
ci: add MAUI build job to CI
Alexays May 22, 2026
4d6d09b
fix(sdk-maui): upgrade target frameworks from net8.0 to net9.0
Alexays May 22, 2026
9c5ad7f
fix(sdk-maui): add missing NuGet packages for transitive Android Mave…
Alexays May 22, 2026
013d16d
fix(sdk-maui): exclude platform-specific and test files from default …
Alexays May 22, 2026
62ea3ee
fix(sdk-maui): use IDictionary<string,JavaObject> and KotlinResultCal…
Alexays May 22, 2026
ebcd3e0
fix(sdk-maui): fix iOS build — xcframework download, Content→None, bg…
Alexays May 22, 2026
8532d22
refactor(sdk-maui): extract OnMain helpers to eliminate TCS boilerplate
Alexays May 22, 2026
3053efb
ci(sdk-maui): download latest ios-public release instead of hardcoded…
Alexays May 22, 2026
1dab658
chore(sdk-maui): ignore build artifacts (bin/, obj/)
Alexays May 22, 2026
2cda743
feat(sdk-maui): read sdk version dynamically from assembly
Alexays May 22, 2026
a810bb3
fix(sdk-maui): hook cleanup on CloseSdk, static handler, RunContinuat…
Alexays May 22, 2026
de5d40f
chore(example-maui): upgrade to net9.0, set channel ID
Alexays May 22, 2026
be96462
chore(example-maui): ignore bin/obj, add Platforms, fix namespace
Alexays May 22, 2026
5efbf52
fix(example-maui): remove NavigationPage, move InitSdk to OnStart wit…
Alexays May 22, 2026
840a9ec
fix(sdk-maui): update iOS binding selectors to match Swift @objcMembe…
Alexays May 22, 2026
8b2e18c
fix(sdk-maui): revert iOS binding selectors to stable explicit names
Alexays May 22, 2026
ca02ebd
fix(example-maui): bump Android minSdk to 24, pin SavedState.Ktx to f…
Alexays May 22, 2026
2b23aa8
fix(example-maui): fix Android grey screen + SDK init timing
Alexays May 22, 2026
b07491c
fix(example-maui): add MainApplication to bootstrap MAUI on Android
Alexays May 22, 2026
2d3276a
docs(sdk-maui): update README with Android/iOS setup, full API reference
Alexays May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,29 @@ jobs:
channel: 'stable'
- run: cd packages/sdk-flutter && flutter pub get
- run: cd packages/sdk-flutter && flutter analyze

maui:
name: .NET MAUI SDK
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Install MAUI workloads
run: dotnet workload install android ios
- name: Download Screeb iOS XCFramework
run: |
SCREEB_IOS_URL=$(curl -sL https://api.github.com/repos/ScreebApp/sdk-ios-public/releases/latest | python3 -c "import sys,json; print(next(a['browser_download_url'] for a in json.load(sys.stdin)['assets'] if a['name']=='Screeb.zip'))")
curl -sL "$SCREEB_IOS_URL" -o /tmp/Screeb.zip
unzip -q /tmp/Screeb.zip -d /tmp/screeb_ios
mkdir -p packages/sdk-maui/native/ios
cp -r /tmp/screeb_ios/Screeb.xcframework packages/sdk-maui/native/ios/
- name: Restore
run: dotnet restore packages/sdk-maui/ScreebMaui.csproj
- name: Build Android
run: dotnet build packages/sdk-maui/ScreebMaui.csproj -f net9.0-android --no-restore
- name: Build iOS
run: dotnet build packages/sdk-maui/ScreebMaui.csproj -f net9.0-ios --no-restore
- name: Run unit tests
run: dotnet test packages/sdk-maui/tests/ScreebUtilsTests.csproj
42 changes: 42 additions & 0 deletions .github/workflows/publish-maui.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Publish Screeb.Maui

on:
push:
tags:
- 'sdk-maui/v*'

jobs:
publish:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

- name: Install MAUI workloads
run: dotnet workload install android ios

- name: Download Screeb iOS XCFramework
run: |
SCREEB_IOS_URL=$(curl -sL https://api.github.com/repos/ScreebApp/sdk-ios-public/releases/latest | python3 -c "import sys,json; print(next(a['browser_download_url'] for a in json.load(sys.stdin)['assets'] if a['name']=='Screeb.zip'))")
curl -sL "$SCREEB_IOS_URL" -o /tmp/Screeb.zip
unzip -q /tmp/Screeb.zip -d /tmp/screeb_ios
mkdir -p packages/sdk-maui/native/ios
cp -r /tmp/screeb_ios/Screeb.xcframework packages/sdk-maui/native/ios/

- name: Restore
run: dotnet restore packages/sdk-maui/ScreebMaui.csproj

- name: Build Android
run: dotnet build packages/sdk-maui/ScreebMaui.csproj -f net9.0-android -c Release --no-restore

- name: Build iOS
run: dotnet build packages/sdk-maui/ScreebMaui.csproj -f net9.0-ios -c Release --no-restore

- name: Pack
run: dotnet pack packages/sdk-maui/ScreebMaui.csproj -c Release --no-build -o ./nupkg

- name: Push to NuGet
run: dotnet nuget push ./nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ yarn-error.log*
.config.env

.vscode

# MAUI SDK - native binaries (downloaded at build time)
packages/sdk-maui/native/ios/Screeb.xcframework/
packages/sdk-maui/native/ios/Screeb.zip
packages/sdk-maui/native/ios/sdk-ios-public-*/

# .NET build artifacts
packages/sdk-maui/bin/
packages/sdk-maui/obj/
examples/example-maui/bin/
examples/example-maui/obj/
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@ npx lerna version --scope=@screeb/sdk-browser

# Flutter
# 1. Bump version in packages/sdk-flutter/pubspec.yaml
# 2. git tag sdk-flutter/vX.Y.Z && git push --tags
git tag sdk-flutter/vX.Y.Z && git push --tags

# MAUI (NuGet)
git tag sdk-maui/v0.1.0 && git push --tags
```
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Public SDKs for [Screeb](https://screeb.app) — the Product Discovery platform.
| Vue | [`@screeb/sdk-vue`](packages/sdk-vue) | [npm](https://www.npmjs.com/package/@screeb/sdk-vue) | [Install](https://developers.screeb.app/sdk-vue/install) |
| Ionic | Uses `@screeb/sdk-angular` / `@screeb/sdk-react` / `@screeb/sdk-browser` | — | [Install](https://developers.screeb.app/sdk-js/sdk-ionic) |
| React Native | [`@screeb/react-native`](packages/sdk-reactnative) | [npm](https://www.npmjs.com/package/@screeb/react-native) | [Install](https://developers.screeb.app/sdk-react-native/install) |
| .NET MAUI | [`Screeb.Maui`](packages/sdk-maui) | [NuGet](https://www.nuget.org/packages/Screeb.Maui) | [Install](https://developers.screeb.app/sdk-maui/install) |
| Flutter | [`plugin_screeb`](packages/sdk-flutter) | [pub.dev](https://pub.dev/packages/plugin_screeb) | [Install](https://developers.screeb.app/sdk-flutter/install) |
| iOS | Closed source ([`sdk-ios-public`](https://github.com/ScreebApp/sdk-ios-public) — SPM mirror) | [SPM](https://github.com/ScreebApp/sdk-ios-public) | [Install](https://developers.screeb.app/sdk-ios/install) |
| Android | Closed source | [Maven](https://central.sonatype.com/artifact/app.screeb.sdk/survey) | [Install](https://developers.screeb.app/sdk-android/install) |
Expand All @@ -29,6 +30,7 @@ Public SDKs for [Screeb](https://screeb.app) — the Product Discovery platform.
| Ionic | Angular 16 + Capacitor | [`examples/example-ionic`](examples/example-ionic) |
| Expo | React Native + Expo | [`examples/example-expo`](examples/example-expo) |
| React Native | React Native CLI | [`examples/example-reactnative`](examples/example-reactnative) |
| .NET MAUI | .NET MAUI | [`examples/example-maui`](examples/example-maui) |
| Flutter | Flutter | [`examples/example-flutter`](examples/example-flutter) |
| Android | Android (Kotlin) | [`examples/example-android`](examples/example-android) |
| iOS | iOS (Swift) | [`examples/example-ios`](examples/example-ios) |
Expand Down
4 changes: 3 additions & 1 deletion commitlint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ module.exports = {
"sdk-angular",
"example-angular",
"sdk-vue",
"example-vue"
"example-vue",
"sdk-maui",
"example-maui"
]],
"scope-empty": [2, "never"],
"scope-min-length": [2, "always", 1],
Expand Down
10 changes: 10 additions & 0 deletions examples/example-maui/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ExampleMaui.App">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="ScreebPurple">#6200EE</Color>
</ResourceDictionary>
</Application.Resources>
</Application>
27 changes: 27 additions & 0 deletions examples/example-maui/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using static Screeb.Maui.Screeb;

namespace ExampleMaui;

public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}

protected override async void OnStart()
{
base.OnStart();
await InitSdk(
channelId: "0e2b609a-8dce-4695-a80f-966fbfa87a88",
userId: "maui-user-123",
properties: new Dictionary<string, object>
{
["platform"] = "maui",
["plan"] = "free"
},
initOptions: new Screeb.Maui.ScreebInitOptions { IsDebugMode = true }
);
}
}
24 changes: 24 additions & 0 deletions examples/example-maui/MainPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ExampleMaui.MainPage"
Title="Screeb MAUI Example"
BackgroundColor="White">
<ScrollView>
<VerticalStackLayout Padding="20" Spacing="10">
<Label Text="Screeb .NET MAUI SDK" FontSize="24" FontAttributes="Bold" HorizontalOptions="Center" />
<Label Text="SDK initialized on startup (see MauiProgram.cs)" HorizontalOptions="Center" />

<Button Text="Track Event" Clicked="OnTrackEventClicked" BackgroundColor="#6200EE" TextColor="White" />
<Button Text="Track Screen" Clicked="OnTrackScreenClicked" BackgroundColor="#6200EE" TextColor="White" />
<Button Text="Set Identity" Clicked="OnSetIdentityClicked" BackgroundColor="#6200EE" TextColor="White" />
<Button Text="Reset Identity" Clicked="OnResetIdentityClicked" BackgroundColor="#9E9E9E" TextColor="White" />
<Button Text="Get Identity" Clicked="OnGetIdentityClicked" BackgroundColor="#6200EE" TextColor="White" />
<Button Text="Assign Group" Clicked="OnAssignGroupClicked" BackgroundColor="#6200EE" TextColor="White" />
<Button Text="Start Survey" Clicked="OnStartSurveyClicked" BackgroundColor="#03DAC5" TextColor="Black" />
<Button Text="Start Message" Clicked="OnStartMessageClicked" BackgroundColor="#03DAC5" TextColor="Black" />

<Label x:Name="StatusLabel" Text="Ready" HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
115 changes: 115 additions & 0 deletions examples/example-maui/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using static Screeb.Maui.Screeb;

namespace ExampleMaui;

public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}

private async void OnTrackEventClicked(object sender, EventArgs e)
{
try
{
await TrackEvent("button_clicked", new Dictionary<string, object> { ["button"] = "track_event" });
StatusLabel.Text = "Event tracked ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnTrackScreenClicked(object sender, EventArgs e)
{
try
{
await TrackScreen("MainPage");
StatusLabel.Text = "Screen tracked ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnSetIdentityClicked(object sender, EventArgs e)
{
try
{
await SetIdentity("maui-user-123", new Dictionary<string, object> { ["plan"] = "premium" });
StatusLabel.Text = "Identity set ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnResetIdentityClicked(object sender, EventArgs e)
{
try
{
await ResetIdentity();
StatusLabel.Text = "Identity reset ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnGetIdentityClicked(object sender, EventArgs e)
{
try
{
var identity = await GetIdentity();
StatusLabel.Text = $"Identity: {identity?.Count ?? 0} props";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnAssignGroupClicked(object sender, EventArgs e)
{
try
{
await AssignGroup("company", "Screeb", new Dictionary<string, object> { ["plan"] = "enterprise" });
StatusLabel.Text = "Group assigned ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnStartSurveyClicked(object sender, EventArgs e)
{
try
{
await StartSurvey("<YOUR_SURVEY_ID>");
StatusLabel.Text = "Survey started ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}

private async void OnStartMessageClicked(object sender, EventArgs e)
{
try
{
await StartMessage("<YOUR_MESSAGE_ID>");
StatusLabel.Text = "Message started ✓";
}
catch (Exception ex)
{
StatusLabel.Text = $"Error: {ex.Message}";
}
}
}
18 changes: 18 additions & 0 deletions examples/example-maui/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.Logging;

namespace ExampleMaui;

public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();
}
}
15 changes: 15 additions & 0 deletions examples/example-maui/Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Android.App;
using Android.Content.PM;

namespace ExampleMaui;

[Activity(
Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
ConfigChanges.UiMode | ConfigChanges.ScreenLayout |
ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}
15 changes: 15 additions & 0 deletions examples/example-maui/Platforms/Android/MainApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Android.App;
using Android.Runtime;

namespace ExampleMaui;

[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}

protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
14 changes: 14 additions & 0 deletions examples/example-maui/Platforms/iOS/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using UIKit;

namespace ExampleMaui;

public class Program
{
static void Main(string[] args) =>
UIApplication.Main(args, null, typeof(AppDelegate));
}

public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
20 changes: 20 additions & 0 deletions examples/example-maui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# example-maui

Example .NET MAUI app demonstrating the Screeb SDK.

## Run

```bash
# Android (API 24+)
dotnet build -t:Run -f net9.0-android

# iOS (macOS only, iOS 14+)
dotnet build -t:Run -f net9.0-ios
```

The channel ID is configured in `App.xaml.cs`.

## Notes

- Android requires `Platforms/Android/MainApplication.cs` (already included) to bootstrap the MAUI runtime.
- iOS requires the `Screeb.xcframework` binary in `packages/sdk-maui/native/ios/` (see SDK README for setup).
Loading
Loading