⚠️ This project is discontinued as Microsoft now support Blazor Web through native directly with .NET MAUI Blazor ⚠️
Links for .NET MAUI:
.NET MAUI Blazor - Build Hybrid Mobile, Desktop, and Web apps - By Daniel Roth: Youtube linkIntroduction to .NET MAUI Blazor | The Xamarin Show: Microsoft Docs
BlazorMobile
Create full C# driven hybrid-apps for iOS, Android, UWP & Desktop with Blazor!
BlazorMobile - is a set of Nuget packages & project templates for embedding a Blazor web application as a standalone mobile application, hosted in Xamarin.
Difference between BlazorMobile & Progressive Web Apps (PWA)
Both creating an application as PWA or using BlazorMobile can be an option with Blazor
The main differences / advantages of BlazorMobile are:
Access to native
Access from Web to native both in C#
More control about your application behaviors, depending your needs and complexity, some type of integration may be difficult with PWA. Still i think the majority of things can be done with PWA only.
You can support old versions of Android where WebAssembly was even not present. Actually because the WebView component used in the plugin is the excellent Mozilla GeckoView instead, so giving you some consistency accross Android devices. On the other side, PWA will never work on older devices, because of lack of PWA support, or because the browser implementation of the system does not have any support of WebAssembly, required by Blazor.
If you are good at designing your application, you can even make your application PWA and BlazorMobile compatible, as you can work intensively with DependencyInjection for services, and so, have multiple implementations of your app services in one or another use case !
Getting started from sample
First install the template model with the following command from a command prompt:
dotnet new -i BlazorMobile.Templates::3.2.8
Then go the folder where you want your project to be created, and from a command prompt type the following command, and of course replace MyProjectName to your desired project name:
dotnet new blazormobile -n MyProjectName
If you plan to also use the Desktop project using Electron.NET, you must first execute this command in order to install the Electron tool on your system:
Then from your Desktop project directory, execute the following command:
electronize init
Open you newly created solution, and you are good to go!
Linking your Blazor app to your Xamarin project
Getting started from a fresh install
Beginning from a freshly installed BlazorMobile template, everything is already set by default.
The following informations only explains how your Xamarin.Forms project load your Blazor WebAssembly application.
How it works
This are informational bits about the project structure:
If you plan to use the BlazorMobile platforms only (iOS, Android, UWP):
You can follow the structure in this guide, embedding your Blazor app in the Xamarin.Forms shared project
If you plan to use the ElectronNET platform in addition of BlazorMobile platforms:
Embed your Blazor app package in an assembly outside the Xamarin.Forms shared project, and call the package
registration, with WebApplicationFactory.RegisterAppStreamResolver, in each device root project.
This is not mandatory but highly recommended, as this configuration prevent to ship your BlazorMobile application twice
on ElectronNET, otherwise it would contain the packaged app, not used with ElectronNET implementation, and the regular app project.
In order to ship your Blazor application within your Xamarin apps, you need to pack it and make it available to it.
Your Blazor app will be automatically packaged thanks to the BlazorMobile.Build NuGet package, that must be already installed on your Blazor web application project. The package location will be written in the build output after the Blazor build mecanism.
The filename should be YourBlazorProjectName.zip.
The steps to easily link it in Xamarin:
Add your package as a link in your Xamarin.Forms shared project, formerly YourAppName, from the Blazor web app bin directory.
Set the property of your package file as an Embedded Resource from Visual Studio property window.
Recommended: Add a dependency on your Xamarin.Forms shared project, and tick your Blazor web application as a build dependency. This way you will be assured that even if there is no direct reference between the Xamarin.Forms shared project and the blazor web application assembly, the blazor project and the zip are always updated before building your mobile application project.
Set the path to your package in your Xamarin.Forms shared project. In the App.xaml.cs file, set the path in your RegisterAppStreamResolver delegate.
As seen on the BlazorMobile.Sample project, assuming a file linked in a virtual folder called Package, we would have a code like this:
namespaceBlazorMobile.Sample
{
publicpartialclassApp : BlazorApplication
{
publicconststringBlazorAppPackageName="BlazorMobile.Sample.Blazor.zip";
publicApp()
{
InitializeComponent();
//Some code//Register Blazor application package resolverWebApplicationFactory.RegisterAppStreamResolver(() =>
{
//This app assemblyvarassembly=typeof(App).Assembly;
//Name of our current Blazor package in this project, stored as an "Embedded Resource"//The file is resolved through AssemblyName.FolderAsNamespace.YourPackageNameFile//In this example, the result would be BlazorMobile.Sample.Package.BlazorMobile.Sample.Blazor.zipreturnassembly.GetManifestResourceStream($"{assembly.GetName().Name}.Package.{BlazorAppPackageName}");
});
//Some codeMainPage=newMainPage();
}
}
}
Detecting Runtime Platform
Just call:
BlazorDevice.RuntimePlatform
In order to retrieve the current device runtime platform.
Note that the BlazorMobilService.Init() has an onFinish callback delegate. Every call to BlazorDevice.RuntimePlatform before the onFinish delegate call will return BlazorDevice.Unkown instead of the detected platform.
Communication between Blazor & Native
Using the ProxyInterface API
ProxyInterface API usages and limitations:
Blazor to Xamarin communication
Unidirectional workflow: The Blazor application is always the call initiator
Ideal for Business logic with predictable results
API calls from Blazor to native are awaitable from a Task object
Usage of interface contracts
How-to use
In the project shared between Blazor & Xamarin, formerly YourAppName.Common create an interface, and add the [ProxyInterface] attribute on top of it. Assuming using the sample IXamarinBridge interface, present by default on YourAppName.Common project, your interface may look like this:
In your Xamarin shared application project, formerly YourAppName project:
Create your implementation class
Inherit your previously created interface on this class
Implement your native code behavior
Call DependencyService.Register and register your interface and class implementation during your application startup.
NOTE: If you plan to ship on UWP, the last statement is important. Because if using the Xamarin attribute method instead,
UWP native toolchain will strip your services registration when compiling in Release mode with .NET Native.
It's so highly recommended to keep the DependencyService.Register route.
Your implementation may look like this. Here a kind of simple example:
Xamarin to Blazor communication only with CallJSInvokableMethod method
Xamarin to Blazor & Blazor to Blazor with PostMessage method
Message broadcasting only
Unidirectional workflow: The message sender cannot wait for any return value
Ideal for Business logic with unpredictable results: The native side can post messages to the Blazor application, according to some external events
API calls are not awaitable
PostMessage only: Messages are limited to one parameter
PostMessage only: Allow to forward messages to static & instanciated method delegates
CallJSInvokableMethod only: Messages can have any parameters, but should match the expected method signature
CallJSInvokableMethod only: Allow to forward message to static JSInvokable methods only
How-to use
CallJSInvokableMethod - Allow to call a Blazor static JSInvokable method
From the IBlazorWebView object retrieved when launching your BlazorMobile application, you should be able to call CallJSInvokableMethod.
This is self explanatory about it's usage, as it look like signature you can find on the InvokeAsyncMethod in Javascript in a regular Blazor application.
/// <summary>/// Call a static JSInvokable method from native side/// </summary>/// <paramname="assembly">The assembly of the JSInvokable method to call</param>/// <paramname="method">The JSInvokable method name</param>/// <paramname="args">Parameters to forward to Blazor app. Check that your parameters are serializable/deserializable from both native and Blazor sides.</param>/// <returns></returns>voidCallJSInvokableMethod(stringassembly,stringmethod, paramsobject[] args);
An usage could look like this:
webview=BlazorWebViewFactory.Create();
//Assuming that we know that the Blazor application already startedwebview.CallJSInvokableMethod("MyBlazorAppAssemblyName", "MyJSInvokableMethodName", "param1", "param2", "param3");
Your JSInvokable method on Blazor side will then be called.
PostMessage - Allow to post a message to a static or instanciated delegate method
This API is in two parts, one in the native side, the other one on the Blazor side.
Messages sent will be received:
Only by the Blazor side
And forwarded to delegates methods registered with a matching message name to listen and matching expected parameter type
Native side
From the IBlazorWebView object retrieved when launching your BlazorMobile application, you should be able to call PostMessage.
/// <summary>/// Post a message to the Blazor app. Any objects that listen to a specific message name by calling BlazorMobileService.MessageSubscribe will trigger their associated handlers./// </summary>/// <paramname="messageName"></param>/// <paramname="args"></param>voidPostMessage<TArgs>(stringmessageName, TArgsargs);
An usage could look like this:
webview=BlazorWebViewFactory.Create();
//Assuming that we know that the Blazor application already startedwebview.PostMessage<string>("myNotification", "my notification value");
Your message will be sent to the Blazor app.
Blazor side
In order to receive message notifications on Blazor side, you should subscribe to the message to listen, with the expected argument type.
Here are the three static methods usable from the BlazorMobileService static class in the Blazor app, for Message API:
/// <summary>/// Subscribe to a specific message name sent from native side with PostMessage, and forward the event to the specified delegate if received/// </summary>/// <paramname="messageName">The message name to subscribe to</param>/// <paramname="handler">The delegate action that must be executed at message reception</param>staticvoidMessageSubscribe<TArgs>(stringmessageName, Action<TArgs> handler);
/// <summary>/// Unsubscribe to a specific message name sent from native side with PostMessage/// </summary>/// <paramname="messageName">The message name to unsubscribe to</param>/// <paramname="handler">The delegate action that must be unsubscribed</param>staticvoidMessageUnsubscribe<TArgs>(stringmessageName, Action<TArgs> handler);
/// <summary>/// Allow to post a message to any delegate action registered through MessageSubscribe./// This method behavior is similar to the IBlazorWebView.PostMessage method on the native side,/// except that you send message from within your Blazor app instead sending it from native side./// </summary>/// <typeparamname="TArgs">The paramter expected type</typeparam>/// <paramname="messageName">The message name to target</param>/// <paramname="value">The value to send in the message</param>staticvoidPostMessage<TArgs>(stringmessageName, TArgsvalue);
In order to receive the message sent from the native side in our previous example we could do this in a Blazor page:
publicvoidOnMessageReceived(stringpayload)
{
//Stuff here will be called when receiving the message
}
BlazorMobileService.MessageSubscribe<string>("myNotification", OnMessageReceived);
NOTE: If you are subscribing an instance method member like in this example, to the MessageSubscribe method,
it's highly recommended to cleanly unregister it when you know that your object instance will be disposed.
In this example, from a Razor page you could do something like this:
If there is no IDisposable mecanism on the C# component you are working on, you may also just unregister at Destructor level.
See the following example:
publicclassMyClass()
{
publicvoidOnMessageReceived(stringpayload)
{
//Stuff here will be called when receiving the message
}
//ConstructorMyClass()
{
BlazorMobileService.MessageSubscribe<string>("myNotification", OnMessageReceived<
请发表评论