Skip to content

Commit

Permalink
chore: adding linking between uno and maui service providers
Browse files Browse the repository at this point in the history
  • Loading branch information
nickrandolph committed Aug 31, 2023
1 parent a8bda1d commit b1dd250
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public static class MauiAppBuilderExtensions
public static MauiAppBuilder UseCustomLibrary(this MauiAppBuilder builder)
{
CustomEntry.Init();
builder.ConfigureEssentials();
builder.Services.AddSingleton(ctx => Accelerometer.Default);
builder.Services.AddSingleton(ctx => Vibration.Default);
builder.ConfigureSyncfusionCore();
return builder;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:supportsRtl="true"></application>
<application android:allowBackup="true" android:supportsRtl="true"></application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using Com.Nostra13.Universalimageloader.Core;
using Microsoft.UI.Xaml.Media;


[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
[assembly: Android.App.UsesPermission(Android.Manifest.Permission.BatteryStats)]
namespace MauiEmbedding.Droid;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<PackageReference Include="Telerik.UI.for.Maui" Condition="$(_UseTelerik)"/>
<PackageReference Include="CommunityToolkit.Maui" />
<PackageReference Include="Uno.UI.Adapter.Microsoft.Extensions.Logging" />
<PackageReference Include="Uno.WinUI.RemoteControl" Condition="'$(Configuration)'=='Debug'" />
<!--<PackageReference Include="Uno.WinUI.RemoteControl" Condition="'$(Configuration)'=='Debug'" />-->
</ItemGroup>
<Choose>
<When Condition="$(IsAndroid)">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Microsoft.Maui.Devices;
using Microsoft.Maui.Devices.Sensors;

namespace MauiEmbedding.Presentation;

public partial class MainViewModel : ObservableObject
Expand All @@ -10,12 +13,22 @@ public partial class MainViewModel : ObservableObject
public MainViewModel(
IStringLocalizer localizer,
IOptions<AppConfig> appInfo,
INavigator navigator)
INavigator navigator,
IAccelerometer accelerometer,
IVibration vibrate)
{
_navigator = navigator;
Title = "Main";
Title += $" - {localizer["ApplicationName"]}";
Title += $" - {appInfo?.Value?.Environment}";
accelerometer.ShakeDetected += Accelerometer_ShakeDetected;
accelerometer.Start(SensorSpeed.Default);
vibrate.Vibrate(3000);
}

private void Accelerometer_ShakeDetected(object? sender, EventArgs e)
{

}
public string? Title { get; }

Expand Down
139 changes: 120 additions & 19 deletions src/Uno.Extensions.Maui.UI/MauiEmbedding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,7 @@ public static partial class MauiEmbedding
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IApplicationBuilder UseMauiEmbedding<TApp>(this IApplicationBuilder builder, Action<MauiAppBuilder>? configure = null)
where TApp : MauiApplication
{
builder.App.UseMauiEmbedding<TApp>(builder.Window, configure);
return builder;
}

/// <summary>
/// Registers Maui embedding in the Uno Platform app builder.
/// </summary>
/// <returns>The updated app builder.</returns>
/// <param name="builder">The IHost builder.</param>
/// <param name="app">The Uno app.</param>
/// <param name="window">The Main Application Window.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null) =>
builder.UseMauiEmbedding<MauiApplication>(app, window, configure);
=> builder.Configure(hostBuilder => hostBuilder.UseMauiEmbedding<TApp>(builder.App, builder.Window, configure));

/// <summary>
/// Registers Maui embedding in the Uno Platform app builder.
Expand All @@ -44,13 +30,24 @@ public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding<TApp>(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null)
where TApp : MauiApplication
=> builder.ConfigureServices(services =>
{
MauiApp? mauiApp = default;
return builder
.UseServiceProviderFactory(ctx => new LinkedServiceProviderFactory(mauiApp!.Services))
//.UseServiceProviderFactory(ctx => new LinkedScopedServiceProviderFactory(mauiApp!.Services))
.ConfigureServices(services =>
{
// Expose the MauiApp to the Uno app via the IHost.Services
var mauiApp = app.UseMauiEmbedding<TApp>(window, configure);
mauiApp = app.UseMauiEmbedding<TApp>(window, configure);
services.AddSingleton(mauiApp);
//services
// .AddSingleton(()=> app.UseMauiEmbedding<TApp>(window, configure))
// .AddHostedService< MauiLoaderService>();

});

}

/// <summary>
/// Registers Maui embedding with WinUI3 and WPF application builder.
/// </summary>
Expand Down Expand Up @@ -83,10 +80,11 @@ public static MauiApp UseMauiEmbedding<TApp>(this Microsoft.UI.Xaml.Application
{
WindowStateManager.Default.OnActivated(window, args);
};
#endif

#endif
return mauiApp;
#else
return default!;
#endif
}

#if MAUI_EMBEDDING
Expand Down Expand Up @@ -168,3 +166,106 @@ public static MauiAppBuilder MapStyleHandler<THandler>(this MauiAppBuilder build
}
*/
}

internal record MauiLoaderService(MauiApp MauiApp) : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

internal class LinkedServiceProviderFactory : IServiceProviderFactory<IServiceCollection>
{
private readonly IServiceProvider _childServiceProvider;

public LinkedServiceProviderFactory(IServiceProvider childServiceProvider)
{
_childServiceProvider = childServiceProvider;
}

public IServiceCollection CreateBuilder(IServiceCollection services)
{
return services
.AddSingleton< IServiceScopeFactory>(sp => new LinkedServiceScopeFactory(sp, _childServiceProvider));
}

public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
return new LinkedServiceProvider(containerBuilder.BuildServiceProvider(), _childServiceProvider);
}
}
internal class LinkedServiceScopeFactory : IServiceScopeFactory
{
private readonly IServiceProvider _childServiceProvider;
private readonly IServiceProvider _serviceProvider;

public LinkedServiceScopeFactory(IServiceProvider serviceProvider, IServiceProvider childServiceProvider)
{
_serviceProvider = serviceProvider;
_childServiceProvider = childServiceProvider;
}

public IServiceScope CreateScope()
{
var scope = _serviceProvider.CreateScope();
return new LinkedServiceScope(scope.ServiceProvider, _childServiceProvider);
}
}

public record LinkedServiceScope(IServiceProvider serviceProvider, IServiceProvider childServiceProvider) : IServiceScope
{
public IServiceProvider ServiceProvider => new LinkedServiceProvider(serviceProvider, childServiceProvider);

public void Dispose() { }
}

//internal class LinkedScopedServiceProviderFactory : IServiceProviderFactory<IServiceScopeFactory>
//{
// private readonly IServiceProvider _childServiceProvider;

// public LinkedScopedServiceProviderFactory(IServiceProvider childServiceProvider)
// {
// _childServiceProvider = childServiceProvider;
// }
// public IServiceScopeFactory CreateBuilder(IServiceCollection services)
// {
// return new DefaultServiceProviderFactory().CreateBuilder(services).BuildServiceProvider().GetRequiredService<IServiceScopeFactory>();
// }

// public IServiceProvider CreateServiceProvider(IServiceScopeFactory containerBuilder)
// {
// return new LinkedServiceProvider(containerBuilder.BuildServiceProvider(), _childServiceProvider);
// //var scope = containerBuilder.CreateScope();
// //var serviceProvider = scope.ServiceProvider;

// //return new LinkedServiceProvider(serviceProvider, _childServiceProvider);
// }
//}

internal class LinkedServiceProvider : IServiceProvider, IDisposable
{
private readonly IServiceProvider _parent;
public readonly IServiceProvider _child;

public LinkedServiceProvider(IServiceProvider parent, IServiceProvider child)
{
_parent = parent;
_child = child;
}

public object? GetService(Type serviceType)
{
if(serviceType == typeof(IServiceScopeFactory))
{
return new LinkedServiceScopeFactory(_parent, _child);
}
return _parent.GetService(serviceType) ?? _child.GetService(serviceType);
}

public void Dispose()
{
if (_parent is IDisposable disposableChild)
{
disposableChild.Dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public static class FrameworkElementExtensions
/// <returns>The attached IServiceProvider instance - scoped for use in this visual hierarchy</returns>
public static IServiceProvider AttachServiceProvider(this UIElement element, IServiceProvider services)
{
var factory = services.GetService<IServiceScopeFactory>();
var scopedServices = services.CreateScope().ServiceProvider;
element.SetServiceProvider(scopedServices);
return scopedServices;
Expand Down
10 changes: 9 additions & 1 deletion src/Uno.Extensions.Navigation.UI/Navigators/ControlNavigator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,15 @@ protected virtual void UpdateRoute(Route? route)

services.AddScopedInstance(request);

var created = services.GetService(mapping!.ViewModel);
object? created = default;
try
{
created = services.GetService(mapping!.ViewModel);
}
catch
{
if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug("Unable to create viewmodel directly via service provider, will fall back to trying the constructor");
}

if (created is not null)
{
Expand Down

0 comments on commit b1dd250

Please sign in to comment.