2026๋…„ .NET MAUI ์™„๋ฒฝ ๊ฐ€์ด๋“œ: ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ๊ณผ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ •๋ฆฌ

.NET MAUI 10์œผ๋กœ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ•ธ๋“ค๋Ÿฌ ์•„ํ‚คํ…์ฒ˜, MVVM, HybridWebView, SafeAreaEdges์™€ ํ•จ๊ป˜ ๋‹ค๋ฃจ๊ณ , 2026๋…„ ๊ธฐ์ˆ  ๋ฉด์ ‘ ํ•ต์‹ฌ ์งˆ๋ฌธ์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

.NET MAUI ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๊ฐœ๋ฐœ: C#์œผ๋กœ Android, iOS, ๋ฐ์Šคํฌํ†ฑ์„ ๋‹จ์ผ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ๊ตฌํ˜„

.NET MAUI(Multi-platform App UI)๋Š” .NET 10๊ณผ ํ•จ๊ป˜ ํ”„๋กœ๋•์…˜ ์ˆ˜์ค€์˜ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์™„์ „ํžˆ ์„ฑ์ˆ™ํ•œ ๋‹จ๊ณ„์— ์ ‘์–ด๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. 2028๋…„ 11์›”๊นŒ์ง€ ์ง€์›๋˜๋Š” LTS(Long-Term Support) ๋ฆด๋ฆฌ์Šค๋กœ ์ถœ์‹œ๋œ .NET MAUI 10์€ ์›Œํฌ๋กœ๋“œ ๋ฐ NuGet ํŒจํ‚ค์ง€ ํ˜•ํƒœ๋กœ ๋ฐฐํฌ๋˜๋ฉฐ, ํ’ˆ์งˆ ๊ฐœ์„ , ์„ฑ๋Šฅ ํ–ฅ์ƒ, HybridWebView ๊ฐ•ํ™” ๋ฐ SafeAreaEdges ๊ฐ™์€ ์‹ ๊ทœ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์•ฑ ๊ตฌ์ถ• ๊ณผ์ •์„ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ดํŽด๋ณด๊ณ , MAUI์˜ ํ•ต์‹ฌ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋ถ„์„ํ•˜๋ฉฐ, 2026๋…„ ์ฑ„์šฉ ํ˜„์žฅ์—์„œ ์‹ค์ œ๋กœ ์ถœ์ œ๋˜๋Š” ๋ฉด์ ‘ ์งˆ๋ฌธ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

.NET MAUI 10 LTS

.NET 10์€ 2028๋…„ 11์›”๊นŒ์ง€ ์ง€์›๋˜๋Š” ์žฅ๊ธฐ ์ง€์›(LTS) ๋ฆด๋ฆฌ์Šค์ž…๋‹ˆ๋‹ค. MAUI 10์€ ์ƒˆ๋กœ์šด UI ์ปจํŠธ๋กค ์ถ”๊ฐ€๋ณด๋‹ค ํ’ˆ์งˆ๊ณผ ์„ฑ๋Šฅ ๊ฐœ์„ ์— ์ง‘์ค‘ํ•˜์—ฌ, ์—ญ๋Œ€ ๊ฐ€์žฅ ์•ˆ์ •์ ์ธ MAUI ๋ฆด๋ฆฌ์Šค๋กœ ํ‰๊ฐ€๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. .NET ์›Œํฌ๋กœ๋“œ์™€ NuGet ํŒจํ‚ค์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฐฐํฌ๋˜์–ด ํ”„๋กœ์ ํŠธ๋ณ„ ๋ฒ„์ „ ๊ณ ์ •(version pinning)์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

.NET MAUI 10 ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ค์ •

MAUI ์•ฑ์„ ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ .NET CLI๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. .NET 10์—์„œ๋Š” .NET Aspire ์„œ๋น„์Šค ๊ธฐ๋ณธ๊ฐ’์ด ํฌํ•จ๋œ ์—…๋ฐ์ดํŠธ๋œ ํ”„๋กœ์ ํŠธ ํ…œํ”Œ๋ฆฟ์ด ๋„์ž…๋˜์–ด, ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ์™€ ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

bash
# Install the MAUI workload (if not already present)
dotnet workload install maui

# Create a new MAUI app
dotnet new maui -n CrossPlatformDemo
cd CrossPlatformDemo

# Run on Android emulator
dotnet build -t:Run -f net10.0-android

๋‹จ์ผ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋Š” ํ”Œ๋žซํผ๋ณ„ ์ฝ”๋“œ๋ฅผ Platforms/ ํด๋” ์•„๋ž˜์— ํ†ตํ•ฉํ•˜๊ณ  ๋‚˜๋จธ์ง€ ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. MauiProgram.cs ํŒŒ์ผ์ด ์ปดํฌ์ง€์…˜ ๋ฃจํŠธ(composition root) ์—ญํ• ์„ ํ•˜๋ฉฐ, ์„œ๋น„์Šค, ํฐํŠธ, ํ•ธ๋“ค๋Ÿฌ ๋“ฑ๋ก์ด ์ด๊ณณ์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

MauiProgram.cscsharp
using Microsoft.Extensions.Logging;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });

        // Register services for dependency injection
        builder.Services.AddSingleton<IApiService, ApiService>();
        builder.Services.AddTransient<MainViewModel>();

#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }
}

MAUI์˜ ์˜์กด์„ฑ ์ฃผ์ž…์€ ASP.NET Core์™€ ๋™์ผํ•œ ํŒจํ„ด์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. Singleton ์„œ๋น„์Šค๋Š” ์•ฑ ์ „์ฒด ์ˆ˜๋ช… ๋™์•ˆ ์œ ์ง€๋˜๊ณ , Transient ์„œ๋น„์Šค๋Š” ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. Scoped ์„œ๋น„์Šค๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, MAUI์—๋Š” HTTP ์š”์ฒญ์ฒ˜๋Ÿผ ๋‚ด์žฅ๋œ ์Šค์ฝ”ํ”„ ๊ฐœ๋…์ด ์—†์œผ๋ฏ€๋กœ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ•ธ๋“ค๋Ÿฌ ์•„ํ‚คํ…์ฒ˜: ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๋ Œ๋”๋ง์˜ ํ•ต์‹ฌ ๊ตฌ์กฐ

MAUI๋Š” Xamarin.Forms์˜ ๋ Œ๋”๋Ÿฌ(Renderer)๋ฅผ ํ•ธ๋“ค๋Ÿฌ(Handler) ์•„ํ‚คํ…์ฒ˜๋กœ ๋Œ€์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ๋Š” ๊ฐ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ปจํŠธ๋กค์„ ์–‡์€ ์ถ”์ƒํ™” ๊ณ„์ธต์„ ํ†ตํ•ด ๋„ค์ดํ‹ฐ๋ธŒ ๋Œ€์‘ ์ปจํŠธ๋กค์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค. ํ•ต์‹ฌ์ ์ธ ์ฐจ์ด์ ์€ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฉฐ(stateless) ๊ฐ€์ƒ ๋ทฐ(virtual view)์™€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค๋Š” ์ ์œผ๋กœ, ์ด๋กœ ์ธํ•ด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ๋” ๋น ๋ฅด๊ณ  ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

CustomEntryHandler.cs โ€” Customizing the Entry control on Androidcsharp
using Microsoft.Maui.Handlers;

public class CustomEntryHandler : EntryHandler
{
    protected override void ConnectHandler(MauiAppCompatEditText platformView)
    {
        base.ConnectHandler(platformView);
        // Remove the default underline on Android
        platformView.SetBackgroundColor(Android.Graphics.Color.Transparent);
    }
}

// Register in MauiProgram.cs
builder.ConfigureMauiHandlers(handlers =>
{
    handlers.AddHandler<Entry, CustomEntryHandler>();
});

.NET 10์—์„œ๋Š” Android์˜ Entry ๋ฐ Editor ์ปจํŠธ๋กค์ด AppCompatEditText์—์„œ MauiAppCompatEditText๋กœ ์ „ํ™˜๋˜์–ด, SelectionChanged ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ์ง€์›์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. .NET 9์—์„œ ๋„์ž…๋œ ๊ฐœ์„ ๋œ CollectionView์™€ CarouselView ํ•ธ๋“ค๋Ÿฌ๋Š” ์ด์ œ iOS ๋ฐ Mac Catalyst์—์„œ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ ์šฉ๋˜์–ด, ์˜ค๋žซ๋™์•ˆ ์ง€์ ๋˜๋˜ ์•ˆ์ •์„ฑ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

CommunityToolkit.Mvvm์„ ํ™œ์šฉํ•œ MVVM ํŒจํ„ด: ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ œ๊ฑฐ

CommunityToolkit.Mvvm ์†Œ์Šค ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด MVVM ํŒจํ„ด ๊ตฌํ˜„์— ํ•„์š”ํ•œ ๋ฐ˜๋ณต ์ฝ”๋“œ๋ฅผ ์•ฝ 80% ์ˆ˜์ค€์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ˆ˜๋™์œผ๋กœ INotifyPropertyChanged๋ฅผ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์ปค๋งจ๋“œ ๋ž˜ํผ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด, ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋งŒ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

MainViewModel.cscsharp
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

public partial class MainViewModel : ObservableObject
{
    private readonly IApiService _apiService;

    public MainViewModel(IApiService apiService)
    {
        _apiService = apiService;
    }

    // Source generator creates the 'Title' property with change notification
    [ObservableProperty]
    private string _title = string.Empty;

    // Source generator creates the 'IsLoading' property
    [ObservableProperty]
    private bool _isLoading;

    // Source generator creates an async ICommand
    [RelayCommand]
    private async Task LoadDataAsync()
    {
        IsLoading = true;
        try
        {
            Title = await _apiService.FetchTitleAsync();
        }
        finally
        {
            IsLoading = false;
        }
    }
}

XAML์—์„œ๋Š” ์ƒ์„ฑ๋œ ํ”„๋กœํผํ‹ฐ์™€ ์ปค๋งจ๋“œ์— ์ง์ ‘ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

xml
<!-- MainPage.xaml -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:CrossPlatformDemo.ViewModels"
             x:DataType="vm:MainViewModel">
    <VerticalStackLayout Padding="20" Spacing="16">
        <Label Text="{Binding Title}"
               FontSize="24"
               HorizontalOptions="Center" />
        <Button Text="Load Data"
                Command="{Binding LoadDataCommand}"
                IsEnabled="{Binding IsLoading, Converter={StaticResource InverseBoolConverter}}" />
        <ActivityIndicator IsRunning="{Binding IsLoading}"
                           IsVisible="{Binding IsLoading}" />
    </VerticalStackLayout>
</ContentPage>

x:DataType ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ์ปดํŒŒ์ผ๋œ ๋ฐ”์ธ๋”ฉ(compiled binding)์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜ ๋ฐ”์ธ๋”ฉ๋ณด๋‹ค ๋น ๋ฅด๋ฉฐ, ๋ฐ”์ธ๋”ฉ ๊ฒฝ๋กœ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ์‹œ์ ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋Ÿฐํƒ€์ž„ ๋ฌธ์ œ๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.NET ๋ฉด์ ‘ ์ค€๋น„๊ฐ€ ๋˜์…จ๋‚˜์š”?

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ, flashcards, ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์—ฐ์Šตํ•˜์„ธ์š”.

.NET 10์˜ HybridWebView: ๋„ค์ดํ‹ฐ๋ธŒ์™€ ์›น์˜ ์—ฐ๊ฒฐ

HybridWebView๋Š” MAUI ์•ฑ ๋‚ด๋ถ€์— ์›น ์ฝ˜ํ…์ธ ๋ฅผ ์‚ฝ์ž…ํ•˜๋ฉด์„œ C#๊ณผ JavaScript ๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ์œ ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. .NET 10์—์„œ๋Š” ์„ธ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Fire-and-forget ๋ฐฉ์‹์˜ JavaScript ํ˜ธ์ถœ, ํ”Œ๋žซํผ๋ณ„ ์„ค์ •์„ ์œ„ํ•œ ์ดˆ๊ธฐํ™” ์ด๋ฒคํŠธ, ๊ทธ๋ฆฌ๊ณ  ์›น ์š”์ฒญ ์ธํ„ฐ์…‰์…˜์ž…๋‹ˆ๋‹ค.

MainPage.xaml.cs โ€” HybridWebView interactioncsharp
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        // Initialization event for platform-specific tweaks
        hybridWebView.WebViewInitialized += (sender, args) =>
        {
            // Access the native platform view after initialization
            System.Diagnostics.Debug.WriteLine("WebView ready");
        };
    }

    // Call JavaScript from C#
    private async void OnCallJsClicked(object sender, EventArgs e)
    {
        var result = await hybridWebView.InvokeJavaScriptAsync<string>(
            "getFormData",  // JS function name
            HybridSampleContext.Default.String  // JSON serialization context
        );
        await DisplayAlert("Result", result, "OK");
    }

    // Fire-and-forget: no return type needed (.NET 10)
    private async void OnResetClicked(object sender, EventArgs e)
    {
        await hybridWebView.InvokeJavaScriptAsync("resetForm");
    }
}

JavaScript ์ธก์—์„œ๋Š” C#์˜ ํ˜ธ์ถœ์„ ์ˆ˜์‹ ํ•˜๊ณ , ๋ฐ˜๋Œ€๋กœ C# ์ธก์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

wwwroot/index.html (HybridWebView content)javascript
function getFormData() {
    return JSON.stringify({
        name: document.getElementById('name').value,
        email: document.getElementById('email').value
    });
}

function resetForm() {
    document.getElementById('name').value = '';
    document.getElementById('email').value = '';
}

InvokeJavaScriptAsync ์‹คํ–‰ ์ค‘ JavaScript์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋Š” ์ด์ œ .NET ์ธก์œผ๋กœ ์ž๋™ ์ „๋‹ฌ๋˜์–ด ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ์ด์ „ ๋ฒ„์ „์—์„œ ๋ฌธ์ œ๊ฐ€ ๋˜๋˜ ์‚ฌ์ผ๋ŸฐํŠธ ์‹คํŒจ(silent failure)๊ฐ€ ์™„์ „ํžˆ ํ•ด์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

SafeAreaEdges: ๋ชจ๋“  ๋””๋ฐ”์ด์Šค์—์„œ ์ •๋ฐ€ํ•œ ๋ ˆ์ด์•„์›ƒ ๊ตฌํ˜„

.NET MAUI 10์€ Layout, ContentView, ContentPage, Border, ScrollView์— SafeAreaEdges ์†์„ฑ์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. None, SoftInput, Container, Default, All ๊ฐ’์„ ์ œ๊ณตํ•˜๋Š” ์ƒˆ๋กœ์šด ์—ด๊ฑฐํ˜•(enum)์€ ๊ธฐ์กด iOS ์ „์šฉ์ด๋˜ Page.UseSafeArea๋ฅผ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๋ฐฉ์‹์œผ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

xml
<!-- Granular safe area control per section -->
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             SafeAreaEdges="All">
    <Grid RowDefinitions="Auto,*,Auto">
        <!-- Header respects all safe areas -->
        <Border Grid.Row="0" SafeAreaEdges="Container">
            <Label Text="Header" />
        </Border>

        <!-- Content scrolls under safe areas -->
        <ScrollView Grid.Row="1" SafeAreaEdges="SoftInput">
            <VerticalStackLayout Padding="16">
                <Entry Placeholder="Type here..." />
            </VerticalStackLayout>
        </ScrollView>

        <!-- Footer avoids home indicator -->
        <Border Grid.Row="2" SafeAreaEdges="Container">
            <Label Text="Footer" />
        </Border>
    </Grid>
</ContentPage>

SoftInput์€ ์†Œํ”„ํŠธ ํ‚ค๋ณด๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚  ๋•Œ ์ฝ˜ํ…์ธ ๋ฅผ ์ž๋™์œผ๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. Container๋Š” ๋…ธ์น˜, ์„ผ์„œ ํ•˜์šฐ์ง•, ํ™ˆ ์ธ๋””์ผ€์ดํ„ฐ ์˜์—ญ์„ ํ”ผํ•ฉ๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋ณ„๋กœ ์ด ๊ฐ’๋“ค์„ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์–ด, ํ—ค๋”๋Š” ์ƒํƒœ ๋ฐ” ์•„๋ž˜์— ์œ„์น˜์‹œํ‚ค๋ฉด์„œ ์ฝ˜ํ…์ธ  ์˜์—ญ์€ ์•ˆ์ „ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ์„ธ๋ฐ€ํ•œ ๋ ˆ์ด์•„์›ƒ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Xamarin.Forms์—์„œ .NET MAUI๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

Xamarin.Forms๋Š” 2024๋…„ 5์›”์— ๊ณต์‹ ์ง€์›์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. MAUI๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ๋‹จ์ˆœํ•œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ณ€๊ฒฝ์„ ๋„˜์–ด ๊ตฌ์กฐ์ ์ธ ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์ „ํ™˜ ๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ ์ •๋ฆฌํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Xamarin ์ง€์› ์ข…๋ฃŒ

Xamarin.Forms๋Š” 2024๋…„ 5์›”๋ถ€ํ„ฐ ์ง€์›์ด ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Xamarin ๊ธฐ๋ฐ˜์œผ๋กœ ์šด์˜ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ณด์•ˆ ๋ฐ ํ˜ธํ™˜์„ฑ ์œ„ํ—˜์„ ์•ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. .NET MAUI 10(LTS, 2028๋…„ 11์›”๊นŒ์ง€ ์ง€์›)์ด ๊ณต์‹ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋Œ€์ƒ์ž…๋‹ˆ๋‹ค.

  1. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ -- ํ”Œ๋žซํผ๋ณ„ ๊ฐœ๋ณ„ ํ”„๋กœ์ ํŠธ๋ฅผ MAUI ๋‹จ์ผ ํ”„๋กœ์ ํŠธ ๋ชจ๋ธ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ณต์œ  ์ฝ”๋“œ๋Š” ๋ฃจํŠธ๋กœ ์ด๋™ํ•˜๊ณ , ํ”Œ๋žซํผ ์ฝ”๋“œ๋Š” Platforms/ ํ•˜์œ„์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋„ค์ž„์ŠคํŽ˜์ด์Šค -- Xamarin.Forms๋ฅผ Microsoft.Maui.Controls๋กœ, Xamarin.Essentials๋ฅผ Microsoft.Maui.Essentials(MAUI์— ๋‚ด์žฅ)๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ Œ๋”๋Ÿฌ์—์„œ ํ•ธ๋“ค๋Ÿฌ๋กœ -- ์ปค์Šคํ…€ ๋ Œ๋”๋Ÿฌ๋Š” ํ•ธ๋“ค๋Ÿฌ๋กœ ์žฌ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ API๊ฐ€ ๋” ๋‹จ์ˆœํ•˜์ง€๋งŒ ๋งคํ•‘ ๋กœ์ง์€ ์ƒ์ดํ•ฉ๋‹ˆ๋‹ค.
  4. ์‹œ์ž‘ ์ฝ”๋“œ -- App.xaml.cs ๊ธฐ๋ฐ˜ ์ดˆ๊ธฐํ™”๋ฅผ ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” MauiProgram.cs๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  5. NuGet ํŒจํ‚ค์ง€ -- Xamarin ์‹œ๋Œ€์˜ ํŒจํ‚ค์ง€ ์ค‘ ์ƒ๋‹น์ˆ˜์— MAUI ๋Œ€์‘ ํŒจํ‚ค์ง€๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์—…๊ทธ๋ ˆ์ด๋“œ ์ „ ํ˜ธํ™˜์„ฑ์„ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  6. ์˜์กด์„ฑ ์ฃผ์ž… -- MAUI๋Š” Microsoft.Extensions.DependencyInjection์„ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„œ๋“œํŒŒํ‹ฐ DI ์ปจํ…Œ์ด๋„ˆ๋‚˜ DependencyService ํ˜ธ์ถœ์€ ๋ชจ๋‘ ๊ต์ฒด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

.NET Upgrade Assistant๊ฐ€ 1-2๋ฒˆ ๋‹จ๊ณ„๋ฅผ ๋ถ€๋ถ„์ ์œผ๋กœ ์ž๋™ํ™”ํ•ด ์ฃผ์ง€๋งŒ, ํ•ธ๋“ค๋Ÿฌ ์ „ํ™˜(3๋ฒˆ)๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์กฐ์ •์€ ์ˆ˜์ž‘์—…์ด ๋ถˆ๊ฐ€ํ”ผํ•ฉ๋‹ˆ๋‹ค.

2026๋…„ .NET MAUI ํ•ต์‹ฌ ๋ฉด์ ‘ ์งˆ๋ฌธ

๋‹ค์Œ์€ .NET 10 ์ƒํƒœ๊ณ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ 2026๋…„ ์ฑ„์šฉ ๋ฉด์ ‘์—์„œ ์‹ค์ œ๋กœ ์ถœ์ œ๋˜๋Š” ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

MAUI ํ•ธ๋“ค๋Ÿฌ ์•„ํ‚คํ…์ฒ˜๋Š” Xamarin.Forms ๋ Œ๋”๋Ÿฌ์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฆ…๋‹ˆ๊นŒ?

Xamarin.Forms์˜ ๋ Œ๋”๋Ÿฌ๋Š” ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ปจํŠธ๋กค๊ณผ ๋„ค์ดํ‹ฐ๋ธŒ ๋ทฐ ์–‘์ชฝ์— ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋œ ์–‘๋ฐฉํ–ฅ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด MAUI์˜ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š”(stateless) ๋งคํผ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ ๋ณ€๊ฒฝ ์•Œ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๊ณ  ๋งคํผ ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋„ค์ดํ‹ฐ๋ธŒ ๋ทฐ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๋กœ ์ธํ•ด ํ•ธ๋“ค๋Ÿฌ๋Š” ํ…Œ์ŠคํŠธ, ํ™•์žฅ, ์žฌ์‚ฌ์šฉ์ด ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค. PropertyMapper์™€ CommandMapper ๋”•์…”๋„ˆ๋ฆฌ๊ฐ€ ๊ธฐ์กด์˜ OnElementPropertyChanged ์˜ค๋ฒ„๋ผ์ด๋“œ ํŒจํ„ด์„ ๋Œ€์ฒดํ•˜๋ฉฐ, switch ๋ฌธ ๋‚ด๋ถ€์— ๋ฌปํ˜€ ์žˆ๋˜ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๋กœ์ง์ด ๋ช…์‹œ์ ์ธ ํ˜•ํƒœ๋กœ ์ „ํ™˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

MAUI์—์„œ DI ์ˆ˜๋ช… ์ฃผ๊ธฐ์™€ ๊ด€๋ จ๋œ ํ•จ์ •์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

MAUI๋Š” Singleton, Transient, Scoped ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜์ง€๋งŒ, Scoped๋Š” ASP.NET Core์™€ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. HTTP ์š”์ฒญ ๊ฐ™์€ ์ž์—ฐ์Šค๋Ÿฌ์šด ์Šค์ฝ”ํ”„ ๊ฒฝ๊ณ„๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. MAUI์—์„œ ๋“ฑ๋ก๋œ Scoped ์„œ๋น„์Šค๋Š” ์ปค์Šคํ…€ ์Šค์ฝ”ํ”„๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” ํ•œ Singleton์ฒ˜๋Ÿผ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ”ํžˆ ๋ฐœ์ƒํ•˜๋Š” ์‹ค์ˆ˜๋กœ๋Š”, ํŽ˜์ด์ง€๋ณ„ ์ƒํƒœ๋ฅผ ๋ณด์œ ํ•˜๋Š” ViewModel์„ Singleton์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž”์กดํ•˜๋Š” ๊ฒฝ์šฐ, ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ Transient๋กœ ๋“ฑ๋กํ•˜์—ฌ ์ปค๋„ฅ์…˜ ํ’€์ด ๊ณ ๊ฐˆ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์›์น™์œผ๋กœ, ViewModel์€ Transient, ์„œ๋น„์Šค๋Š” Singleton์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , Scoped๋Š” ์Šค์ฝ”ํ”„ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ํ•œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

๋ฉด์ ‘ ํŒ

DI ๊ด€๋ จ ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•  ๋•Œ๋Š” MAUI์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๊ฐ€ ASP.NET Core์˜ ์š”์ฒญ ๊ธฐ๋ฐ˜ ์Šค์ฝ”ํ”„ ๋ชจ๋ธ๊ณผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฉด์ ‘๊ด€์€ ์žฅ์‹œ๊ฐ„ ์‹คํ–‰๋˜๋Š” ๋ชจ๋ฐ”์ผ ์•ฑ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์™€ ์ƒํƒœ ๋ถˆ์ผ์น˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ธ์‹ ์ˆ˜์ค€์„ ์ฃผ๋กœ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ปดํŒŒ์ผ๋œ ๋ฐ”์ธ๋”ฉ(Compiled Binding)๊ณผ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜ ๋ฐ”์ธ๋”ฉ์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜ ๋ฐ”์ธ๋”ฉ์€ ๋Ÿฐํƒ€์ž„์— System.Reflection์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ ๊ฒฝ๋กœ๋ฅผ ํ•ด์„ํ•˜๋ฏ€๋กœ, ์†๋„๊ฐ€ ๋А๋ฆฌ๊ณ  ์˜คํƒ€๋กœ ์ธํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋Ÿฐํƒ€์ž„์—์„œ๋งŒ ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค. x:DataType๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•˜๋Š” ์ปดํŒŒ์ผ๋œ ๋ฐ”์ธ๋”ฉ์€ ๋ฐ”์ธ๋”ฉ ๊ฒฝ๋กœ๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ํ•ด์„ํ•ฉ๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ฆฌํ”Œ๋ ‰์…˜์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ์ง์ ‘ ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ, ์‹œ์ž‘ ์‹œ๊ฐ„ ๋‹จ์ถ•, ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๊ฐ์†Œ, ๋นŒ๋“œ ์‹œ์  ๋ฐ”์ธ๋”ฉ ์˜ค๋ฅ˜ ๊ฐ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. .NET 10์—์„œ๋Š” ์ƒˆ๋กœ์šด XAML ์†Œ์Šค ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๊ฐ€ XAML์„ ๋Ÿฐํƒ€์ž„ ํŒŒ์‹ฑ ๋Œ€์‹  ๋นŒ๋“œ ์‹œ์ ์— ์ปดํŒŒ์ผํ•˜์—ฌ ์ด ์ตœ์ ํ™”๋ฅผ ๋”์šฑ ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

MAUI ์•ฑ๊ณผ ASP.NET Core ๋ฐฑ์—”๋“œ ๊ฐ„ ์ฝ”๋“œ ๊ณต์œ  ์ „๋žต์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ถŒ์žฅ๋˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์€ DTO, ์œ ํšจ์„ฑ ๊ฒ€์ฆ ๋กœ์ง, ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ํฌํ•จํ•˜๋Š” ๊ณต์œ  ํด๋ž˜์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. MAUI ์•ฑ๊ณผ ASP.NET Core ๋ฐฑ์—”๋“œ๊ฐ€ ๋ชจ๋‘ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. .NET 10์€ MAUI์šฉ .NET Aspire ํ†ตํ•ฉ์„ ํ†ตํ•ด ์ด ํŒจํ„ด์„ ๋”์šฑ ๊ฐ•ํ™”ํ•˜๋ฉฐ, ๋ชจ๋ฐ”์ผ๊ณผ ๋ฐฑ์—”๋“œ ํ”„๋กœ์ ํŠธ ๊ฐ„ ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ์™€ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. System.Text.Json ์†Œ์Šค ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•œ ๊ณต์œ  ๊ณ„์•ฝ(contract)์œผ๋กœ ์ง๋ ฌํ™” ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ต์‹ฌ ์ œ์•ฝ ์‚ฌํ•ญ์€ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ”Œ๋žซํผ๋ณ„ TFM์ด ์•„๋‹Œ net10.0์„ ํƒ€๊ฒŸ์œผ๋กœ ํ•ด์•ผ ์ด์‹์„ฑ์ด ์œ ์ง€๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

HybridWebView์™€ BlazorWebView๋Š” ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

BlazorWebView๋Š” MAUI ์•ฑ ๋‚ด๋ถ€์—์„œ ์™„์ „ํ•œ Blazor ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ˜ธ์ŠคํŒ…ํ•ฉ๋‹ˆ๋‹ค. Razor ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‚ด์žฅ WebView์— ๋ Œ๋”๋ง๋˜์ง€๋งŒ, .NET ๋Ÿฐํƒ€์ž„์€ WebAssembly๊ฐ€ ์•„๋‹Œ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. HybridWebView๋Š” ์ด๋ณด๋‹ค ๊ฐ€๋ฒผ์šด ๊ตฌ์„ฑ์œผ๋กœ, ์ •์  HTML/CSS/JS ์ฝ˜ํ…์ธ ๋ฅผ ๋กœ๋“œํ•˜๊ณ  Blazor ํ”„๋ ˆ์ž„์›Œํฌ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์ด C#-JavaScript ๊ฐ„ ์ธํ„ฐ๋กญ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์„ ํƒ ๊ธฐ์ค€์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. BlazorWebView๋Š” ๊ธฐ์กด Blazor ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์œ ํ•œ ํŒ€์ด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ์›ํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. HybridWebView๋Š” ๋Œ€์‹œ๋ณด๋“œ, ์ง€๋„, ์—๋””ํ„ฐ ๊ฐ™์€ ๊ธฐ์กด ์›น ์ฝ˜ํ…์ธ ๋ฅผ ์ „์ฒด ํ”„๋ ˆ์ž„์›Œํฌ ์—†์ด ๋„ค์ดํ‹ฐ๋ธŒ์— ํ†ตํ•ฉํ•ด์•ผ ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

SharpSkill .NET ๋ฉด์ ‘ ์—ฐ์Šต์—์„œ ์ด๋Ÿฌํ•œ ๊ฐœ๋…์„ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์—ฐ์Šต ๋ฌธ์ œ๋กœ ์‹ฌํ™” ํ•™์Šตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

๊ฒฐ๋ก 

  • .NET MAUI 10์€ LTS ๋ฆด๋ฆฌ์Šค(2028๋…„ 11์›”๊นŒ์ง€ ์ง€์›)๋กœ, ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋ณด๋‹ค ์•ˆ์ •์„ฑ๊ณผ ์„ฑ๋Šฅ์— ์ง‘์ค‘ํ•˜์—ฌ ํ”„๋กœ๋•์…˜ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์•ฑ์— ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค
  • ํ•ธ๋“ค๋Ÿฌ ์•„ํ‚คํ…์ฒ˜๋Š” Xamarin ๋ Œ๋”๋Ÿฌ๋ฅผ ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š” ๋งคํผ๋กœ ๋Œ€์ฒดํ•˜์—ฌ, PropertyMapper์™€ CommandMapper๋ฅผ ํ†ตํ•œ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ๊ณผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํŽธ์˜์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค
  • CommunityToolkit.Mvvm ์†Œ์Šค ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” MVVM ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๋ฅผ ๋Œ€ํญ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. [ObservableProperty]์™€ [RelayCommand] ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ์ˆ˜๋™ INotifyPropertyChanged ๋ฐ ์ปค๋งจ๋“œ ๊ตฌํ˜„์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค
  • .NET 10์˜ HybridWebView๋Š” fire-and-forget JavaScript ํ˜ธ์ถœ, ์ดˆ๊ธฐํ™” ์ด๋ฒคํŠธ, ์š”์ฒญ ์ธํ„ฐ์…‰์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ-์›น ํ†ตํ•ฉ์„ ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค
  • SafeAreaEdges๋Š” ๋””๋ฐ”์ด์Šค ๋…ธ์น˜, ํ‚ค๋ณด๋“œ, ์‹œ์Šคํ…œ ๋ฐ”์— ๋Œ€ํ•œ ์„ธ๋ฐ€ํ•œ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๊ธฐ์กด iOS ์ „์šฉ์ด๋˜ UseSafeArea๋ฅผ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค
  • Xamarin.Forms ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์—๋Š” ํ•ธ๋“ค๋Ÿฌ ์žฌ์ž‘์„ฑ๊ณผ ์‹œ์ž‘ ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•˜๋ฉฐ, .NET Upgrade Assistant๊ฐ€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ณ€๊ฒฝ์€ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ ์ปค์Šคํ…€ ๋ Œ๋”๋Ÿฌ์— ๋Œ€ํ•œ ์ˆ˜์ž‘์—…์€ ๋ถˆ๊ฐ€ํ”ผํ•ฉ๋‹ˆ๋‹ค
  • ๋ฉด์ ‘ ์ค€๋น„ ์‹œ ํ•ธ๋“ค๋Ÿฌ ๋Œ€ ๋ Œ๋”๋Ÿฌ ์•„ํ‚คํ…์ฒ˜, ์žฅ์‹œ๊ฐ„ ์‹คํ–‰ ์•ฑ์—์„œ์˜ DI ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ•จ์ •, ์ปดํŒŒ์ผ๋œ ๋ฐ”์ธ๋”ฉ, HybridWebView์™€ BlazorWebView์˜ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„์— ์ง‘์ค‘ํ•˜๋Š” ๊ฒƒ์ด ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค

์—ฐ์Šต์„ ์‹œ์ž‘ํ•˜์„ธ์š”!

๋ฉด์ ‘ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ธฐ์ˆ  ํ…Œ์ŠคํŠธ๋กœ ์ง€์‹์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

ํƒœ๊ทธ

#.net maui
#cross-platform
#tutorial
#interview
#xamarin migration
#.net 10
#mobile development

๊ณต์œ 

๊ด€๋ จ ๊ธฐ์‚ฌ

C# ๋ฐ .NET ๋ฉด์ ‘ ์งˆ๋ฌธ - ์™„๋ฒฝ ๊ฐ€์ด๋“œ

C# ๋ฐ .NET ๋ฉด์ ‘ ์งˆ๋ฌธ: 2026๋…„ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

๊ฐ€์žฅ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” C# ๋ฐ .NET ๋ฉด์ ‘ ์งˆ๋ฌธ 17์„ ์ž…๋‹ˆ๋‹ค. LINQ, async/await, ์˜์กด์„ฑ ์ฃผ์ž…, Entity Framework, ASP.NET Core ๋“ฑ ์ƒ์„ธํ•œ ๋‹ต๋ณ€๊ณผ ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

ASP.NET Core ๋ฉด์ ‘ ๋Œ€๋น„: ๋ฏธ๋“ค์›จ์–ด, ์˜์กด์„ฑ ์ฃผ์ž…, Minimal API

ASP.NET Core ๋ฉด์ ‘ ์งˆ๋ฌธ 25์„ : ๋ฏธ๋“ค์›จ์–ด, DI, Minimal API ์™„๋ฒฝ ์ •๋ฆฌ

ASP.NET Core ๋ฉด์ ‘์—์„œ ์ž์ฃผ ์ถœ์ œ๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด ํŒŒ์ดํ”„๋ผ์ธ, ์˜์กด์„ฑ ์ฃผ์ž… ์ƒ๋ช…์ฃผ๊ธฐ, Minimal API์— ๊ด€ํ•œ 25๊ฐ€์ง€ ํ•ต์‹ฌ ์งˆ๋ฌธ๊ณผ ์‹ค๋ฌด ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

.NET 9 Blazor United๋ฅผ ํ™œ์šฉํ•œ ๋‹ค์ค‘ ๋ Œ๋”๋ง ๋ชจ๋“œ ํ’€์Šคํƒ ๊ฐœ๋ฐœ

.NET 9 Blazor: Blazor United๋ฅผ ํ™œ์šฉํ•œ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ๊ฐ€์ด๋“œ 2026

.NET 9 Blazor United๋Š” ์ •์  SSR, Server, WebAssembly ๋ Œ๋”๋ง ๋ชจ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ๋ชจ๋“œ ํ™œ์šฉ๋ฒ•, ์ŠคํŠธ๋ฆฌ๋ฐ ๋ Œ๋”๋ง, ์ƒ์„ฑ์ž ์ฃผ์ž…, ํ”„๋กœ๋•์…˜ ํŒจํ„ด์„ ์‹ค์Šต ์ค‘์‹ฌ์œผ๋กœ ๋‹ค๋ฃจ๋Š” ํŠœํ† ๋ฆฌ์–ผ์ž…๋‹ˆ๋‹ค.