Coder Social home page Coder Social logo

stanislous / hybridsharedui Goto Github PK

View Code? Open in Web Editor NEW

This project forked from bethmassi/hybridsharedui

0.0 0.0 0.0 1.14 MB

This is an example of a starter solution that sets up a MAUI hybrid app and a Blazor web app that shares all of its UI

JavaScript 0.90% C# 31.88% CSS 38.55% HTML 28.66%

hybridsharedui's Introduction

Setting up a solution for MAUI hybrid and Blazor web with shared UI

(Rendering mode: Server - Global)

This repo demonstrates a starter solution that contains a MAUI hybrid (native, cross-platform) app, a Blazor web app and a Razor class library that contains all the shared UI that is used by both native and web apps.

Apps running on Windows, Android, and Web with shared UI

It also demonstrates how to use Blazor render modes on the web app but ignore them in the MAUI app. It does this by setting up a helper class in the RCL called InteractiveRenderSettings that has properties that are used as render mode in the components while running in the web app. The MauiProgram.cs sets these properties to null so they are ignored on the client instead of throwing an exception.

Manually setting up the solution

To manually set this up yourself in Visual Studio, follow these steps

  1. Create an empty Solution and name it MyApp

  2. Add new project MAUI Blazor Hybrid app and name it MyApp.MAUI

  3. Add new project Blazor Web App and name it MyApp.Web. Select the following options:

    a. Authentication type = none

    b. Configure for HTTPS is checked

    c. Interactive render mode = Server

    d. Interactivity location = Global <-- This setting is important because hybrid apps always run interactive and will throw errors on pages or components that explicitly specify a render mode. See #51235. If you do not use a global render mode, you will need to implement the pattern shown in this repository.

    e. Uncheck Include sample pages

  4. Add new project Razor Class Library (RCL) and name it MyApp.Shared

    a. don't select "support pages and views" (default)

  5. Now add project references to MyApp.Shared from both MyApp.MAUI & MyApp.Web project

  6. Move the Components folder and all of its contents from MyApp.MAUI to MyApp.Shared (Ctrl+X, Ctrl+V)

  7. Move wwwroot/css folder and all of its contents from from MyApp.MAUI to MyApp.Shared (Ctrl+X, Ctrl+V)

  8. Move _Imports.razor from MyApp.MAUI to MyApp.Shared (overwrite the one that is there) and rename the last two @usings to MyApp.Shared

...
@using MyApp.Shared
@using MyApp.Shared.Components
  1. Open the _Imports.razor in MyApp.Web add a @using to MyApp.Shared
...
@using MyApp.Shared
  1. Move Routes.razor from MyApp.MAUI to MyApp.Shared (Ctrl+X, Ctrl+V).

  2. Open the Routes.razor file and change MauiProgram to Routes:

<Router AppAssembly="@typeof(Routes).Assembly">
...
  1. Open the MainPage.xaml in the MyApp.MAUI project and add a xmlns:shared reference to the MyApp.Shared RCL and update the BlazorWebView RootComponent ComponentType from local to shared:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MyApp.MAUI"
             xmlns:shared="clr-namespace:MyApp.Shared;assembly=MyApp.Shared" 
             x:Class="MyApp.MAUI.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <BlazorWebView x:Name="blazorWebView" HostPage="wwwroot/index.html">
        <BlazorWebView.RootComponents>
            <RootComponent Selector="#app" ComponentType="{x:Type shared:Routes}" />
        </BlazorWebView.RootComponents>
    </BlazorWebView>
</ContentPage>
  1. In the MyApp.MAUI project open wwwroot/index.html and change stylesheets to point to _content/MyApp.Shared/:
<link rel="stylesheet" href="_content/MyApp.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/MyApp.Shared/css/app.css" />
  1. Open App.razor from MyApp.Web project Components folder and add the stylesheet references to the MyApp.Shared there too:
<link rel="stylesheet" href="_content/MyApp.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/MyApp.Shared/css/app.css" />   
  1. In the MyApp.Web project, delete files Routes.razor, Layouts folder & all its contents, and Pages\Home.razor (leave the Error.razor page)

  2. Open MyApp.Web project Program.cs file and AddAddionalAssemblies to MapRazorComponents:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddAdditionalAssemblies(typeof(MyApp.Shared._Imports).Assembly);

You should now be all set! F5 and party on.

Using Interfaces to support different device implementations

This sample also shows how to use interfaces on the UI to call into different implementations across the web app and the native (MAUI Hybrid) app. We will make a component that displays the device form factor. We can use the MAUI abstraction layer for all the native apps but we will need to provide our own implementation for the web app.

  1. In the MyApp.Shared project, create an Interfaces folder and add file called IFormFactor.cs with the following code:
namespace MyApp.Shared.Interfaces
{
    public interface IFormFactor
    {
        public string GetFormFactor();
        public string GetPlatform();
    }
}
  1. Move Component1.razor in the MyApp.Shared project to Components folder and add the following code:
@using MyApp.Shared.Interfaces
@inject IFormFactor FormFactor

<div class="my-component">
    <p>You are running on:</p>

    <h3>@factor</h3>
    <h3>@platform</h3>

    <em>This component is defined in the <strong>MyApp.Shared</strong> library.</em>
</div>

@code {
    private string factor => FormFactor.GetFormFactor();
    private string platform => FormFactor.GetPlatform();
}
  1. Now that we have the interface defined we need to provide implementations in the web and native apps. In the MyApp.Web project, add a folder called Services and add a file called FormFactor.cs. Add the following code:
using MyApp.Shared.Interfaces;

namespace MyApp.Web.Services
{
    public class FormFactor : IFormFactor
    {
        public string GetFormFactor()
        {
            return "Web";
        }
        public string GetPlatform()
        {
            return Environment.OSVersion.ToString();
        }
    }
}
  1. Now in the MyApp.MAUI project, add a folder called Services and add a file called FormFactor.cs. We can use the MAUI abstractions layer to write code that will work on all the native device platforms. Add the following code:
using MyApp.Shared.Interfaces;

namespace MyApp.MAUI.Services
{
    public class FormFactor : IFormFactor
    {
        public string GetFormFactor()
        {
            return DeviceInfo.Idiom.ToString();
        }
        public string GetPlatform()
        {
            return DeviceInfo.Platform.ToString() + " - " + DeviceInfo.VersionString;
        }
    }
}
  1. Use dependency injection to get the implementations of these services into the right place. In the MyApp.MAUI project open MauiProgram.cs and add the usings at the top:
using Microsoft.Extensions.Logging;
using MyApp.MAUI.Services;
using MyApp.Shared.Interfaces;
  1. And right before the call to builder.Build(); add the following code:
...
// Add device specific services used by Razor Class Library (MyApp.Shared)
builder.Services.AddSingleton<IFormFactor, FormFactor>();

return builder.Build();
  1. Similarly, in the MyApp.Web project, open the Program.cs and right before the call to builder.Build(); add the usings at the top:
using MyApp.Web.Components;
using MyApp.Shared.Interfaces;
using MyApp.Web.Services;  
  1. And right before the call to builder.Build(); add the following code:
...
// Add device specific services used by Razor Class Library (MyApp.Shared)
builder.Services.AddScoped<IFormFactor, FormFactor>();

var app = builder.Build();

You can also use compiler preprocessor directives in your RCL to implement different UI depending on the device you are running on. In that case you need to multi-target your RCL like you do in your MAUI app. For an example of that see: BethMassi/BethTimeUntil repo.

That's it! Have fun.

hybridsharedui's People

Contributors

bethmassi avatar eilon avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.