Skip to content

feat: MAUI support #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cfbfe07
Added setup for MAUI app, before PS is working on it.
Chriztiaan Mar 11, 2025
c9bf567
Merge branch 'main' into maui
Chriztiaan Apr 10, 2025
447cc76
Merge branch 'main' into maui
Chriztiaan May 27, 2025
2c678a1
Added initial Maui package that has extension loading code and factory.
Chriztiaan Jun 5, 2025
d6d60a3
Fixed factory not working. Initial stab for loading extensions via MA…
Chriztiaan Jun 5, 2025
ace6dbf
Setup code for MAUI.
Chriztiaan Jun 9, 2025
a0750d4
Removed unsupported MAUI platforms from Demo.
Chriztiaan Jun 10, 2025
f5bf19e
Ensuring runtimes/platforms are applied to their specific builds. Set…
Chriztiaan Jun 10, 2025
28d6b9b
Priming changelogs.
Chriztiaan Jun 10, 2025
7877784
Clearing mac catalyst support from demo.
Chriztiaan Jun 11, 2025
2c78052
Converted Demo to Lists+Todos design.
Chriztiaan Jun 11, 2025
eb658d3
Changing datamodel to look similar to PowerSync App schema.
Chriztiaan Jun 11, 2025
067d126
Swapped in PowerSync db over base sqlite database.
Chriztiaan Jun 11, 2025
9b0830e
Can show data syncs between demos.
Chriztiaan Jun 11, 2025
f091b52
wip
Chriztiaan Jun 11, 2025
3c223b4
Moved both pages to use a watch query.
Chriztiaan Jun 12, 2025
ad8d205
General cleanup.
Chriztiaan Jun 12, 2025
480e35b
Added sql console. Cleanup.
Chriztiaan Jun 13, 2025
ff93bd7
Working on releasing of dev packages.
Chriztiaan Jun 13, 2025
0494423
Fixing selection issue on Android for list.
Chriztiaan Jun 13, 2025
73cc017
Filter todos by list
benitav Jun 13, 2025
dff49b8
Add Readme
benitav Jun 13, 2025
a29eb7e
Add psql note
benitav Jun 13, 2025
98b53e2
Hook up self-host-demo client with MAUI demo
benitav Jun 13, 2025
df00aea
Update readme with inspection notes
benitav Jun 13, 2025
924e8fe
Fixed connection retry crashing due to serialization issue.
Chriztiaan Jun 14, 2025
0a86c0a
Merge branch 'maui' of https://github.com/powersync-ja/powersync-dotn…
Chriztiaan Jun 14, 2025
f69e0ea
New dev release.
Chriztiaan Jun 14, 2025
d85d796
Remove known issues
benitav Jun 16, 2025
43ba9c2
Not failing on failed package push.
Chriztiaan Jun 24, 2025
ddb26f6
Merge branch 'maui' of https://github.com/powersync-ja/powersync-dotn…
Chriztiaan Jun 24, 2025
763aabb
Updated release workflow to support MAUI.
Chriztiaan Jun 24, 2025
4635569
Release versions in changelog.
Chriztiaan Jun 24, 2025
2fa1a32
Added extension loading for windows target. Added windows platform fi…
Chriztiaan Jul 1, 2025
0813194
Renamed TodoSqlite demo to MAUITodo.
Chriztiaan Jul 1, 2025
b1c0e6e
Updated readme entry for Maui demo.
Chriztiaan Jul 1, 2025
635f18d
Updated windows entry.
Chriztiaan Jul 1, 2025
e5dedc7
Readme polish
benitav Jul 1, 2025
e4f0463
Document frameworks
benitav Jul 1, 2025
0575b9d
Updated MAUI package readme.
Chriztiaan Jul 2, 2025
e28c526
Update PowerSync/PowerSync.Maui/README.md
Chriztiaan Jul 2, 2025
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
35 changes: 25 additions & 10 deletions .github/workflows/dev-packages.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# The version is pulled from the CHANGELOG.md file of the package.
# Add a `-dev.xxx` suffix to the version.
# Add a `-dev.xxx` suffix to the version. Example: `0.0.1-dev.1`
name: Create Dev Release

on: workflow_dispatch
Expand All @@ -24,17 +24,32 @@ jobs:
- name: Restore dependencies
run: dotnet restore

- name: Extract Version from CHANGELOG.md
- name: Extract Common Package Version from CHANGELOG.md
id: extract_version
shell: bash
run: |
VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+-dev(\.[0-9]+)?$/ {print $2; exit}' PowerSync/PowerSync.Common/CHANGELOG.md)
echo "Detected Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
COMMON_VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+-dev(\.[0-9]+)?$/ {print $2; exit}' PowerSync/PowerSync.Common/CHANGELOG.md)
echo "Detected Version: $COMMON_VERSION"
echo "VERSION=$COMMON_VERSION" >> $GITHUB_ENV

- name: Run Pack
run: dotnet pack -c Release -o ${{ github.workspace }}/output
- name: Run Pack For Common
run: dotnet pack PowerSync/PowerSync.Common -c Release -o ${{ github.workspace }}/output

- name: Run Push
run: dotnet nuget push ${{ github.workspace }}\output\*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}

- name: Run Push For Common
continue-on-error: true
run: dotnet nuget push ${{ github.workspace }}\output\PowerSync.Common*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}

- name: Extract MAUI Package Version from CHANGELOG.md
id: extract_maui_version
shell: bash
run: |
MAUI_VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+-dev(\.[0-9]+)?$/ {print $2; exit}' PowerSync/PowerSync.Maui/CHANGELOG.md)
echo "Detected Version: $MAUI_VERSION"
echo "VERSION=$MAUI_VERSION" >> $GITHUB_ENV

- name: Run Pack For MAUI
run: dotnet pack PowerSync/PowerSync.Maui -c Release -o ${{ github.workspace }}/output

- name: Run Push For MAUI
continue-on-error: true
run: dotnet nuget push ${{ github.workspace }}\output\PowerSync.Maui*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
27 changes: 21 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,32 @@ jobs:
- name: Restore dependencies
run: dotnet restore

- name: Extract Version from CHANGELOG.md
- name: Extract Common Package Version from CHANGELOG.md
id: extract_version
shell: bash
run: |
VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+/ {print $2; exit}' PowerSync/PowerSync.Common/CHANGELOG.md)
echo "Detected Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV

- name: Run Pack
run: dotnet pack -c Release -o ${{ github.workspace }}/output
- name: Run Pack for Common
run: dotnet pack PowerSync/PowerSync.Common -c Release -o ${{ github.workspace }}/output

- name: Run Push
run: dotnet nuget push ${{ github.workspace }}\output\*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}

- name: Run Push for Common
continue-on-error: true
run: dotnet nuget push ${{ github.workspace }}\output\PowerSync.Common*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}

- name: Extract MAUI Package Version from CHANGELOG.md
id: extract_maui_version
shell: bash
run: |
MAUI_VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+/ {print $2; exit}' PowerSync/PowerSync.Maui/CHANGELOG.md)
echo "Detected Version: $MAUI_VERSION"
echo "VERSION=$MAUI_VERSION" >> $GITHUB_ENV

- name: Run Pack For MAUI
run: dotnet pack PowerSync/PowerSync.Maui -c Release -o ${{ github.workspace }}/output

- name: Run Push For MAUI
continue-on-error: true
run: dotnet nuget push ${{ github.workspace }}\output\PowerSync.Maui*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ obj/
*.log
*.tlog
*.dmp
*.tmp

# Visual Studio specific
.vscode/
Expand Down Expand Up @@ -61,8 +62,9 @@ TestResults/
*.dylib
*.dll
*.so

*.xcframework
.env
*NativeLibs

# Ignore user id file
user_id.txt
5 changes: 5 additions & 0 deletions PowerSync/PowerSync.Common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# PowerSync.Common Changelog

## 0.0.3-alpha.1
- Minor changes to accommodate PowerSync.MAUI package extension.

## 0.0.2-alpha.2

- Updated core extension to v0.3.14
Expand Down
9 changes: 2 additions & 7 deletions PowerSync/PowerSync.Common/Client/PowerSyncDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ public class DBAdapterSource(IDBAdapter Adapter) : IDatabaseSource
public IDBAdapter Adapter { get; init; } = Adapter;
}

public class OpenFactorySource(ISQLOpenFactory Factory) : IDatabaseSource
{
public ISQLOpenFactory Factory { get; init; } = Factory;
}

public class PowerSyncDatabaseOptions() : BasePowerSyncDatabaseOptions()
{
/// <summary>
Expand Down Expand Up @@ -115,9 +110,9 @@ public PowerSyncDatabase(PowerSyncDatabaseOptions options)
{
Database = adapterSource.Adapter;
}
else if (options.Database is OpenFactorySource factorySource)
else if (options.Database is ISQLOpenFactory factorySource)
{
Database = factorySource.Factory.OpenDatabase();
Database = factorySource.OpenDatabase();
}
else if (options.Database is SQLOpenOptions openOptions)
{
Expand Down
2 changes: 1 addition & 1 deletion PowerSync/PowerSync.Common/Client/SQLOpenFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class SQLOpenOptions : IDatabaseSource
public string? DbLocation { get; set; }
}

public interface ISQLOpenFactory
public interface ISQLOpenFactory: IDatabaseSource
{
/// <summary>
/// Opens a connection adapter to a SQLite Database.
Expand Down
10 changes: 8 additions & 2 deletions PowerSync/PowerSync.Common/DB/Crud/SyncStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ public class SyncDataFlowStatus
[JsonProperty("uploading")]
public bool Uploading { get; set; } = false;

[JsonProperty("downloadError")]
public string? DownloadErrorMessage => DownloadError?.Message;

[JsonProperty("uploadError")]
public string? UploadErrorMessage => UploadError?.Message;

/// <summary>
/// Error during downloading (including connecting).
/// Cleared on the next successful data download.
/// </summary>
[JsonProperty("downloadError")]
[JsonIgnore]
public Exception? DownloadError { get; set; } = null;

/// <summary>
/// Error during uploading.
/// Cleared on the next successful upload.
/// </summary>
[JsonProperty("uploadError")]
[JsonIgnore]
public Exception? UploadError { get; set; } = null;
}

Expand Down
2 changes: 1 addition & 1 deletion PowerSync/PowerSync.Common/MDSQLite/MDSQLiteAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private static SqliteConnection OpenDatabase(string dbFilename)
return connection;
}

private void LoadExtension(SqliteConnection db)
protected virtual void LoadExtension(SqliteConnection db)
{
string extensionPath = PowerSyncPathResolver.GetNativeLibraryPath(AppContext.BaseDirectory);
db.EnableExtensions(true);
Expand Down
4 changes: 2 additions & 2 deletions PowerSync/PowerSync.Common/MDSQLite/MDSQLiteDBOpenFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ public class MDSQLiteOpenFactoryOptions : SQLOpenOptions
public MDSQLiteOptions? SqliteOptions { get; set; }
}

public class MDSqliteDBOpenFactory : ISQLOpenFactory
public class MDSQLiteDBOpenFactory : ISQLOpenFactory
{
private readonly MDSQLiteOpenFactoryOptions options;

public MDSqliteDBOpenFactory(MDSQLiteOpenFactoryOptions options)
public MDSQLiteDBOpenFactory(MDSQLiteOpenFactoryOptions options)
{
this.options = options;
}
Expand Down
15 changes: 8 additions & 7 deletions PowerSync/PowerSync.Common/PowerSync.Common.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net6.0;net8.0;net9.0;net8.0-ios;net8.0-android</TargetFrameworks>
<LangVersion>12</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand All @@ -19,6 +19,7 @@
<PackageIcon>icon.png</PackageIcon>
<NoWarn>NU5100</NoWarn>
<PackageReadmeFile>README.md</PackageReadmeFile>
<DefaultItemExcludes>$(DefaultItemExcludes);runtimes/**/*.*;</DefaultItemExcludes>
</PropertyGroup>

<ItemGroup>
Expand All @@ -29,20 +30,20 @@
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
</ItemGroup>

<!-- For monorepo, test if we can remove this in monorepo -->
<ItemGroup>

<!-- Check allows us to skip for all MAUI targets-->
<!-- For monorepo-->
<ItemGroup Condition="!$(TargetFramework.Contains('-'))">
<Content Include="runtimes\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<!-- For releasing runtimes -->
<ItemGroup>
<ItemGroup Condition="!$(TargetFramework.Contains('-'))">
<None Include="runtimes\**\*.*" Pack="true" PackagePath="runtimes\" />
</ItemGroup>



<ItemGroup>
<None Include="..\..\icon.png" Pack="true" PackagePath=""/>
<None Include="README.md" Pack="true" PackagePath=""/>
Expand Down
9 changes: 9 additions & 0 deletions PowerSync/PowerSync.Maui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# PowerSync.Maui Changelog

## 0.0.1-alpha.1

- Introduce package. Support for iOS/Android use cases.

### Platform Runtime Support Added
* MAUI iOS
* MAUI Android
57 changes: 57 additions & 0 deletions PowerSync/PowerSync.Maui/PowerSync.Maui.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net8.0;net9.0;net8.0-ios;net8.0-android</TargetFrameworks>
<LangVersion>12</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>PowerSync.Maui</PackageId>
<Title>PowerSync.Maui</Title>
<Description>PowerSync.Maui is a package that enables MAUI usage for PowerSync</Description>
<Authors>PowerSync</Authors>
<owners>powersync</owners>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<RepositoryUrl>https://github.com/powersync-ja/powersync-dotnet</RepositoryUrl>
<PackageProjectUrl>https://powersync.com</PackageProjectUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageReleaseNotes>https://github.com/powersync-ja/powersync-dotnet/PowerSync/PowerSync.Maui/CHANGELOG.md</PackageReleaseNotes>
<PackageTags>powersync local-first local-storage state-management offline sql db persistence sqlite sync </PackageTags>
<PackageIcon>icon.png</PackageIcon>
<NoWarn>NU5100</NoWarn>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\PowerSync.Common\PowerSync.Common.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\icon.png" Pack="true" PackagePath=""/>
<None Include="README.md" Pack="true" PackagePath=""/>
<None Update="Platforms\Android\Resources\values\colors.xml">
<SubType>Designer</SubType>
</None>
</ItemGroup>

<!-- For monorepo-->
<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<Content Include="Platforms\Android\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.Contains('-ios'))">
<Content Include="Platforms\iOS\NativeLibs\powersync-sqlite-core.xcframework\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<!-- For releasing runtimes -->
<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<None Include="Platforms\Android\**\*.*" Pack="true" PackagePath="Platforms\Android" />
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.Contains('-ios'))">
<None Include="Platforms\iOS\NativeLibs\powersync-sqlite-core.xcframework\**\*.*" Pack="true" PackagePath="Platforms\iOS" />
</ItemGroup>
</Project>
5 changes: 5 additions & 0 deletions PowerSync/PowerSync.Maui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PowerSync SDK .NET MAUI

## Usage

TBD Factory Example
44 changes: 44 additions & 0 deletions PowerSync/PowerSync.Maui/SQLite/MAUISQLiteAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace PowerSync.Maui.SQLite;

using Microsoft.Data.Sqlite;
using PowerSync.Common.MDSQLite;

// iOS specific imports
#if IOS
using Foundation;
#endif

public class MAUISQLiteAdapter : MDSQLiteAdapter
{
public MAUISQLiteAdapter(MDSQLiteAdapterOptions options) : base(options)
{
}

protected override void LoadExtension(SqliteConnection db)
{
db.EnableExtensions(true);

#if IOS
LoadExtensionIOS(db);
#elif ANDROID
db.LoadExtension("libpowersync");
#else
base.LoadExtension(db);
#endif
}

private void LoadExtensionIOS(SqliteConnection db)
{
#if IOS
var bundlePath = Foundation.NSBundle.MainBundle.BundlePath;
var filePath =
Path.Combine(bundlePath, "Frameworks", "powersync-sqlite-core.framework", "powersync-sqlite-core");

using var loadExtension = db.CreateCommand();
loadExtension.CommandText = "SELECT load_extension(@path, @entryPoint)";
loadExtension.Parameters.AddWithValue("@path", filePath);
loadExtension.Parameters.AddWithValue("@entryPoint", "sqlite3_powersync_init");
loadExtension.ExecuteNonQuery();
#endif
}
}
26 changes: 26 additions & 0 deletions PowerSync/PowerSync.Maui/SQLite/MAUISQLiteDBOpenFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using PowerSync.Common.DB;

namespace PowerSync.Maui.SQLite;

using PowerSync.Common.Client;
using PowerSync.Common.MDSQLite;


public class MAUISQLiteDBOpenFactory : ISQLOpenFactory
{
private readonly MDSQLiteOpenFactoryOptions options;

public MAUISQLiteDBOpenFactory(MDSQLiteOpenFactoryOptions options)
{
this.options = options;
}

public IDBAdapter OpenDatabase()
{
return new MAUISQLiteAdapter(new MDSQLiteAdapterOptions
{
Name = options.DbFilename,
SqliteOptions = options.SqliteOptions
});
}
}
Loading