• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Daddoon/BlazorMobile: Create full C# driven hybrid-apps for iOS, Android, UWP &a ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

Daddoon/BlazorMobile

开源软件地址(OpenSource Url):

https://github.com/Daddoon/BlazorMobile

开源编程语言(OpenSource Language):

C# 78.3%

开源软件介绍(OpenSource Introduction):

⚠️ 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 link Introduction 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.

Framework requirement

  • Blazor 3.2.0
  • .NET Core 3.1

Platform requirements

  • Android: 4.4 or greater
  • iOS: 12.0 or greater
  • UWP: Build 16299 or greater
  • Windows: Electron.NET
  • Linux: Electron.NET
  • macOS: Electron.NET

Additional platform notes

Android support

Universal Windows Platform

  • BlazorMobile has been tested working on Windows 10! - minimum version: 10.16299
  • BlazorMobile has been tested working on Xbox One! - minimum version: 10.18362

ElectronNET support

Summary

Troubleshoot

Updates and Migrations guides

See the Migration guide page

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:

dotnet tool install ElectronNET.CLI --version 5.30.1 -g

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:

namespace BlazorMobile.Sample
{
	public partial class App : BlazorApplication
	{
        public const string BlazorAppPackageName = "BlazorMobile.Sample.Blazor.zip";

        public App()
        {
            InitializeComponent();

            //Some code

            //Register Blazor application package resolver
            WebApplicationFactory.RegisterAppStreamResolver(() =>
            {
                //This app assembly
                var assembly = 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.zip
                return assembly.GetManifestResourceStream($"{assembly.GetName().Name}.Package.{BlazorAppPackageName}");
            });

            //Some code

            MainPage = new MainPage();
        }
    }
}

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:

using BlazorMobile.Common.Attributes;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace BlazorMobile.Sample.Common.Interfaces
{
    [ProxyInterface]
    public interface IXamarinBridge
    {
        Task<List<string>> DisplayAlert(string title, string msg, string cancel);
    }
}

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:

using BlazorMobile.Sample.Common.Interfaces;
using BlazorMobile.Sample.Services;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace BlazorMobile.Sample.Services
{
    public class XamarinBridge : IXamarinBridge
    {
        public async Task<List<string>> DisplayAlert(string title, string msg, string cancel)
        {
            await App.Current.MainPage.DisplayAlert(title, msg, cancel);

            List<string> result = new List<string>()
            {
                "Lorem",
                "Ipsum",
                "Dolorem",
            };

            return result;
        }
    }
}

In your Blazor project, you only have two things to do:

  • Call services.AddBlazorMobileNativeServices<Startup>(); from ConfigureServices in Startup.cs
  • Inject your interface in your pages and call the methods whenever you want!

Starting from the template, as a convinience, adding BlazorMobile natives services from ServicesHelper.ConfigureCommonServices.

using Microsoft.Extensions.DependencyInjection;

namespace BlazorMobile.Sample.Blazor.Helpers
{
    public static class ServicesHelper
    {
        public static void ConfigureCommonServices(IServiceCollection services)
        {
            //Add services shared between multiples project here
            services.AddBlazorMobileNativeServices<Startup>();
        }
    }
}

Then if you want to use any of your Blazor to native interface, it's as simple as this:

@page  "/blazormobile"

@using BlazorMobile.Common
@using BlazorMobile.Sample.Common.Interfaces
@inject IXamarinBridge XamarinBridge

<h1>BlazorMobile</h1>

<button class="btn btn-primary" @onclick="@ShowPlatform">Show Runtime platform in a native dialog</button>

@code {

    async void ShowPlatform()
    {
        await XamarinBridge.DisplayAlert("Platform identity", $"Current platform is {BlazorDevice.RuntimePlatform}", "Great!");
    }
}

Using the Message API

Message API usages and limitations:

  • 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>
/// <param name="assembly">The assembly of the JSInvokable method to call</param>
/// <param name="method">The JSInvokable method name</param>
/// <param name="args">Parameters to forward to Blazor app. Check that your parameters are serializable/deserializable from both native and Blazor sides.</param>
/// <returns></returns>
void CallJSInvokableMethod(string assembly,string method, params object[] args);

An usage could look like this:

webview = BlazorWebViewFactory.Create();

//Assuming that we know that the Blazor application already started
webview.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>
/// <param name="messageName"></param>
/// <param name="args"></param>
void PostMessage<TArgs>(string messageName, TArgs args);

An usage could look like this:

webview = BlazorWebViewFactory.Create();

//Assuming that we know that the Blazor application already started
webview.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>
/// <param name="messageName">The message name to subscribe to</param>
/// <param name="handler">The delegate action that must be executed at message reception</param>
static void MessageSubscribe<TArgs>(string messageName, Action<TArgs> handler);

/// <summary>
/// Unsubscribe to a specific message name sent from native side with PostMessage
/// </summary>
/// <param name="messageName">The message name to unsubscribe to</param>
/// <param name="handler">The delegate action that must be unsubscribed</param>
static void MessageUnsubscribe<TArgs>(string messageName, 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>
/// <typeparam name="TArgs">The paramter expected type</typeparam>
/// <param name="messageName">The message name to target</param>
/// <param name="value">The value to send in the message</param>
static void PostMessage<TArgs>(string messageName, TArgs value);

In order to receive the message sent from the native side in our previous example we could do this in a Blazor page:

public void OnMessageReceived(string payload)
{
   //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:

@page "/myPage"
@implements IDisposable

//Some code

@code {
    //Some code

    public void Dispose()
    {
        BlazorMobileService.MessageUnsubscribe<string>("myNotification", OnMessageReceived);
    }
}

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:

public class MyClass()
{
    public void OnMessageReceived(string payload)
    {
       //Stuff here will be called when receiving the message
    }

    //Constructor
    MyClass()
    {
        BlazorMobileService.MessageSubscribe<string>("myNotification", OnMessageReceived< 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap