I have dll library let's name it "LibraryA". I've attached it to Application/Resources/Raw/LibraryA.dll
. I just want to register all the services and interfaces from that library like:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiCommunityToolkit()
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
fonts.AddFont("Roboto-Regular.ttf", "RobotoRegular");
fonts.AddFont("Roboto-Medium.ttf", "RobotoMedium");
fonts.AddFont("Roboto-Light.ttf", "RobotoLight");
})
;
RegisterServicesAsync(builder.Services);
builder.Services.AddSingleton<App>();
var app = builder.Build();
return app;
}
private static void RegisterServices(IServiceCollection services)
{
string dllFileName = "LibraryA.dll";
var dllPath = Path.Combine(FileSystem.AppDataDirectory, dllFileName);
var assembly = Assembly.LoadFrom(dllPath);
var serviceTypes = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any());
foreach (var implementationType in serviceTypes)
{
var interfaceType = implementationType.GetInterfaces().FirstOrDefault();
if (interfaceType != null)
{
var descriptor = services.FirstOrDefault(d => d.ServiceType == interfaceType);
if (descriptor != null)
{
services.Remove(descriptor);
}
services.AddSingleton(interfaceType, implementationType);
}
}
}
}
And there is an exception thrown because there is no LibraryA.dll
file in path:
'/data/user/0/com.application/files/LibraryA.dll'
. When I copy LibraryA.dll to that path everything works. But I can't achieve that with
using var stream = await FileSystem.OpenAppPackageFileAsync(dllFileName);
using var fileStream = File.Create(dllPath);
await stream.CopyToAsync(fileStream);
, because that code is asynchronous and there is a System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'
because services didn't register. There is the code with copy file to device:
private static async Task RegisterServicesAsync(IServiceCollection services)
{
string dllFileName = "LibraryA.dll";
var dllPath = Path.Combine(FileSystem.AppDataDirectory, dllFileName);
****added code below****
using var stream = await FileSystem.OpenAppPackageFileAsync(dllFileName);
using var fileStream = File.Create(dllPath);
await stream.CopyToAsync(fileStream);
**********************
var assembly = Assembly.LoadFrom(dllPath);
var serviceTypes = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any());
foreach (var implementationType in serviceTypes)
{
var interfaceType = implementationType.GetInterfaces().FirstOrDefault();
if (interfaceType != null)
{
var descriptor = services.FirstOrDefault(d => d.ServiceType == interfaceType);
if (descriptor != null)
{
services.Remove(descriptor);
}
services.AddSingleton(interfaceType, implementationType);
}
}
}
Should I copy LibraryA.dll
to android device by hand? How can I handle that?
Try to set up Build Action for your LibraryA.dll in .csproj file like this:
<ItemGroup>
<EmbeddedResource Include="LibraryA.dll" />
</ItemGroup>
<ItemGroup>
<None Remove="LibraryA.dll" />
</ItemGroup>
It worked for me to move my file into apk bundle of application. And then in code to EXTRACT FILE FROM APK BUNDLE and MOVE FILE INTO APK FOLDER I do:
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
using (var fileStream = new FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.Write))
{
resourceStream.CopyTo(fileStream);
}
}
where resourceName
= $"{nameof(SolutionName)}.LibraryA.dll"
and destinationPath
where to move this file = Path.Combine(appDataDirectory, "LibraryA.dll")
. appDataDirectory
in Xamarin.Forms
is FileSystem.AppDataDirectory
I don't which is for MAUI but I think the same.
Hope this hepls. If you have any questions please leave a comment.