Aplikacje mobilne · Multimedia
Multimedia w .NET MAUI: odtwarzanie dźwięku
Odtwarzacz muzyki, nauka wymowy, gra z efektami dźwiękowymi: wszystkie potrzebują dźwięku. W przeciwieństwie do WPF (gdzie jest MediaElement) MAUI nie ma wbudowanej kontrolki audio. Użyjesz darmowego pakietu Plugin.Maui.Audio, który działa w pełni offline.
- około 45 minut
- .NET MAUI · Plugin.Maui.Audio · MauiAsset
- INF.04.6.2
Po tej lekcji: dodać plik dźwiękowy do projektu (Resources/Raw, MauiAsset), zarejestrować AudioManager i odtworzyć dźwięk w kodzie, tworząc odtwarzacz tylko raz.
Odtwarzacz z regulacją głośności
Przycisk Play nie wystarczy: trzeba otworzyć zasób, utworzyć odtwarzacz i zwolnić go po opuszczeniu strony. Zrobimy prosty panel bez pozostawiania dźwięku w tle.
Najpierw uruchomisz mały ekran. Potem połączysz go z kodem i sprawdzisz konkretne wyniki. Dodatki wykonuj dopiero, gdy wersja podstawowa działa. Quiz i oceniane zadania pozostają w biurku po zalogowaniu.
Laboratorium · ćwiczenie w przeglądarce, do którego odsyłają rozgrzewki na końcu lekcji
2 · Sprawdź w działaniu
Zepsuj każdy krok po kolei
Odtwórz dźwięk przy poprawnych ustawieniach (usłyszysz cichy ton). Potem wyłączaj kolejne wymagania: rejestrację AudioManager, MauiAsset, wielkość liter w nazwie na Androidzie i sprawdzanie _player == null. Przeczytaj komunikaty.
Najpierw przewidź, potem sprawdź: W modelu audio porównaj Play, Stop i zmianę głośności. To model sterowania; prawdziwą obsługę formatu i urządzenia sprawdzisz w uruchomionej aplikacji.
Najczęstsze błędy to brak rejestracji AudioManager, zły Build Action i wielkie litery w nazwie pliku (psują tylko Androida). Model pomaga zobaczyć mechanizm; właściwą aplikację uruchomisz z plików poniżej.
1. Przygotuj miejsce pracy
Co dodajesz, a co podmieniasz?
Stronę dodaj przez Projekt → Dodaj → Nowy element → .NET MAUI ContentPage (XAML). Powstaje para .xaml i .xaml.cs. Dla ContentView wybierz szablon ContentView; dla modeli i serwisów zwykłą klasę. Jeśli plik już istnieje, podmień wskazaną zawartość — nie twórz drugiej klasy o tej samej nazwie.
| Plik | Rola w ćwiczeniu |
|---|---|
| MauiProgram.cs | Logika i obsługa danych |
| MainPage.xaml | Wygląd strony lub kontrolki |
| MainPage.xaml.cs | Logika i obsługa danych |
| projekt.csproj (fragment szablonu) | Fragment w istniejącym pliku |
| App.xaml.cs | Logika i obsługa danych |
Zanim uruchomisz: trzy połączenia
x:Class="MojaAplikacja.NazwaStrony" w XAML musi zgadzać się z namespace MojaAplikacja i nazwą klasy C#. InitializeComponent() tworzy kontrolki opisane w XAML.
x:Name="PoleImie" daje kodowi C# dostęp przez PoleImie.Text. Z kolei Clicked="Zapisz_Clicked" wskazuje metodę o tej nazwie w pliku .xaml.cs. Sam napis przycisku w Text niczego nie podpina.
Gdy dodajesz XAML z obsługą zdarzeń, od razu uzupełnij też odpowiadający C#. Uruchamiaj dopiero po skończeniu oznaczonej pary plików; brakujący handler nie jest błędem środowiska.
2. Uruchom sam wygląd — jeszcze bez logiki
W świeżym projekcie zastąp MainPage.xaml poniższym ekranem. W MainPage.xaml.cs zachowaj konstruktor z InitializeComponent(); usuń szablonowy licznik i OnCounterClicked, bo nie ma ich już w XAML. Na tym etapie App i AppShell pozostają z szablonu. To pełny, tymczasowy XAML — później świadomie go podmienisz, nie dokleisz do drugiego ContentPage.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MojaAplikacja.MainPage">
<VerticalStackLayout Padding="24" Spacing="14">
<Label Text="Mój odtwarzacz" FontSize="24" />
<Button Text="Play — podłączymy za chwilę" />
<Slider Minimum="0" Maximum="1" Value="0.5" />
</VerticalStackLayout>
</ContentPage>
- Pierwsza próba Uruchom. Zobaczysz kontrolki, ale przyciski bez Clicked jeszcze nic nie robią. Sprawdź rozmiar i kolejność elementów. Zatrzymaj aplikację przed następnym etapem.
Zacznijmy od wymowy
Nagranie, które gra bez internetu
Aplikacja do nauki języka odtwarza nagranie wymowy po kliknięciu „Odsłuchaj”, a prosta gra efekt dźwiękowy po trafieniu. W obu przypadkach plik audio jest dołączony do aplikacji i działa całkowicie offline.
Temat rzadziej spotykany na egzaminie niż formularze czy listy, ale wymieniony w podstawie programowej obok grafiki i animacji.
1 · Zanim zagra pierwszy dźwięk
Lista kontrolna odtwarzania audio
Pominięcie któregokolwiek kroku kończy się ciszą albo błędem. Zaznaczaj kroki w trakcie.
4. Połącz wygląd z działaniem
Teraz zbuduj docelowy przykład. Pełne pliki poniżej zastępują swoje wcześniejsze wersje. Przeczytaj opis nad kodem i objaśnienia pod nim; potem sprawdź przepływ danych, nie tylko brak czerwonych podkreśleń.
Gdy przykład ma kilka plików zależnych od siebie, najpierw dodaj wszystkie wskazane typy, a potem uruchom całość. Ustaw breakpoint w obsłudze głównego przycisku i prześledź jedną próbę.
Budowa krok po kroku
MauiProgram.cs
Instalację Plugin.Maui.Audio wykonaj przed tym krokiem. AddSingleton udostępnia menedżera audio, a AddTransient pozwala DI utworzyć MainPage z argumentem konstruktora.
Rejestrujemy IAudioManager i MainPage. Kontener DI tworzy stronę, a nie ręczne new MainPage() bez argumentów. Pakiet Plugin.Maui.Audio dodaj przez NuGet (ten przykład kontrolnie kompilowano z wersją4.0.0).
using Microsoft.Extensions.Logging;
using Plugin.Maui.Audio;
namespace MojaAplikacja;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Bez tej linii dźwięk się nie uruchomi
builder.Services.AddSingleton<IAudioManager>(AudioManager.Current);
builder.Services.AddTransient<MainPage>();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
using Plugin.Maui.Audio;Przestrzeń nazw pakietu.builder.Services.AddSingleton(AudioManager.Current)Rejestruje jedną, wspólną instancję menedżera. Bez tej linii dźwięk się nie uruchomi.
Budowa krok po kroku
MainPage.xaml
Dodaj lub otwórz MainPage.xaml i podmień jego zawartość. Najpierw odszukaj kontener, potem nazwane kontrolki oraz wskazane zdarzenia. Pozostaw zgodne x:Class i nazwę klasy w pliku .xaml.cs.
Dwa przyciski i suwak głośności (zakres 0 do 1, taki jak właściwość Volume).
<?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"
x:Class="MojaAplikacja.MainPage">
<VerticalStackLayout Padding="30" Spacing="20">
<Label Text="Odtwarzanie dźwięku" FontSize="22" HorizontalOptions="Center" />
<Button Text="Odtwórz dźwięk" Clicked="Play_Clicked" />
<Button Text="Zatrzymaj" Clicked="Stop_Clicked" />
<Slider x:Name="SuwakGlosnosci" Minimum="0" Maximum="1" Value="0.5"
ValueChanged="SuwakGlosnosci_ValueChanged" />
<Button Text="Ekran próbny — sprawdź powrót" Clicked="OtworzProbe_Clicked" />
</VerticalStackLayout>
</ContentPage>
- Przeczytaj powiązanie x:Name identyfikuje kontrolkę, a Binding odczytuje właściwość obiektu ustawionego jako BindingContext. To dwa różne mechanizmy.
Budowa krok po kroku
MainPage.xaml.cs
Najpierw otwieramy plik, potem tworzymy player i uruchamiamy Play. ?. pomija wywołanie przy null. Dispose zwalnia zasób, więc po powrocie tworzymy player ponownie.
Audio i strumień zwalniamy po opuszczeniu strony. Flaga chroni przed podwójnym rozpoczęciem wczytywania, a numer wersji widoku nie pozwala uruchomić odtwarzania, jeśli uczeń zdążył opuścić stronę podczas await. Plik Resources/Raw/audio.mp3 musi istnieć; to nie URL do filmu.
using Plugin.Maui.Audio;
namespace MojaAplikacja;
public partial class MainPage : ContentPage
{
private readonly IAudioManager _audioManager;
private IAudioPlayer? _player;
private Stream? _strumien;
private bool _wczytywanie;
private int _wersjaWidoku;
public MainPage(IAudioManager audioManager)
{
InitializeComponent();
_audioManager = audioManager;
}
private async void Play_Clicked(object sender, EventArgs e)
{
if (_wczytywanie) return;
_wczytywanie = true;
int wersja = _wersjaWidoku;
try
{
if (_player is null)
{
Stream otwarty = await FileSystem.OpenAppPackageFileAsync("audio.mp3");
if (wersja != _wersjaWidoku) { otwarty.Dispose(); return; }
_strumien = otwarty;
_player = _audioManager.CreatePlayer(_strumien);
}
_player.Volume = SuwakGlosnosci.Value;
_player.Play();
}
catch (Exception)
{
ZwolnijAudio();
await DisplayAlertAsync("Dźwięk", "Sprawdź plik audio.mp3 i jego akcję MauiAsset.", "OK");
}
finally { _wczytywanie = false; }
}
private void Stop_Clicked(object sender, EventArgs e) => _player?.Stop();
private void SuwakGlosnosci_ValueChanged(object sender, ValueChangedEventArgs e)
{ if (_player is not null) _player.Volume = e.NewValue; }
private void ZwolnijAudio()
{
_player?.Stop();
_player?.Dispose();
_player = null;
_strumien?.Dispose();
_strumien = null;
}
protected override void OnDisappearing()
{
_wersjaWidoku++;
ZwolnijAudio();
base.OnDisappearing();
}
private async void OtworzProbe_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new ContentPage
{
Title = "Ekran próbny",
Content = new Label { Text = "Wróć strzałką wstecz.", Margin = 24 }
});
}
}
IAudioManager audioManagerZależność przekazana przez konstruktor. Kontener znajduje ją dzięki rejestracji w MauiProgram.Dispose()Zwalnia zasoby playera i strumienia; Stop samo w sobie nie zwalnia całego odtwarzacza._wersjaWidokuProsty znacznik: gdy strona zniknie podczas wczytywania, rezultat jest odrzucany. To nie pełny system anulowania operacji.
Budowa krok po kroku
Dołączanie plików z Resources/Raw
Najpierw sprawdź istniejący wpis MauiAsset w projekcie. Jeśli szablon ma ten glob, nie dodawaj go drugi raz. Plik audio.mp3 umieść w Resources/Raw.
Szablon MAUI już zawiera ten wpis. Dlatego każdy plik wrzucony do Resources/Raw dostaje Build Action = MauiAsset i trafia do pakietu aplikacji.
<ItemGroup>
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
Budowa krok po kroku
Strona startowa otrzymana przez DI
App też dostaje MainPage przez konstruktor. Kontener DI tworzy zależności; new MainPage() nie pasuje do konstruktora wymagającego IAudioManager.
Zachowaj App.xaml z szablonu. AppShell nie jest w tej wersji stroną startową.
namespace MojaAplikacja;
public partial class App : Application
{
private readonly MainPage _strona;
public App(MainPage strona) { InitializeComponent(); _strona = strona; }
protected override Window CreateWindow(IActivationState? activationState)
=> new Window(new NavigationPage(_strona));
}
5. Odbiór: czy naprawdę działa?
Wykonaj próby w swojej aplikacji, nie tylko w modelu na stronie. Zaznaczaj dopiero po sprawdzeniu wyniku. Funkcje urządzenia wymagają testu na właściwej platformie.
7 · Czego unikać
Trzy błędy z dźwiękiem
Brak rejestracji `AudioManager`
// w MauiProgram.cs brak: builder.Services.AddSingleton(AudioManager.Current);Wyjątek albo ciche niedziałanie. To najczęstszy błąd.
builder.Services.AddSingleton(AudioManager.Current);Pakiet wymaga rejestracji w kontenerze usług.
Zły Build Action
Plik w Resources/Raw bez MauiAssetOpenAppPackageFileAsync nie znajdzie pliku w gotowej aplikacji, choć widać go w Eksploratorze rozwiązań.
Build Action: MauiAssetTylko zasoby MauiAsset trafiają do pakietu.
Wielkie litery w nazwie pliku
// w projekcie: Audio.mp3
await FileSystem.OpenAppPackageFileAsync("audio.mp3");Błąd „plik nie znaleziony” tylko na Androidzie. Na Windows może zadziałać, co mąci diagnozę.
Nazwa małymi literami i identyczna w kodzie: audio.mp3Nazwy zasobów na Androidzie rozróżniają wielkość liter.
Ćwiczenie z pomocą · samodzielna praca
6. Mała zmiana, którą zrobisz samodzielnie
Dodaj przycisk Pauza, który pozwoli później wznowić odtwarzanie.
Dodaj przycisk Pauza, który pozwoli później wznowić odtwarzanie. Dotychczasowe działanie ma pozostać poprawne.
? Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź
Dodaj Button i handler.
Krok 2 — pokaż podpowiedź
Wywołaj Pause na istniejącym _player tylko wtedy, gdy nie jest null.
Krok 3 — pokaż podpowiedź
Porównaj Pause i Stop: po pauzie Play ma kontynuować, a nie otwierać nowy plik.
Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.
8 · Sprawdź się
Dlaczego dźwięk nie gra?
Cztery sytuacje.
Podsumowanie
Co warto zapamiętać
- MAUI nie ma wbudowanej kontrolki audio, więc używasz pakietu **
Plugin.Maui.Audio** (offline). - Plik w **
Resources/Raw**,Build Action = MauiAsset, nazwa małymi literami. - Obowiązkowa rejestracja:
builder.Services.AddSingleton(AudioManager.Current). - Odtwarzanie:
OpenAppPackageFileAsync→CreatePlayer(stream)→Play(). Odtwarzacz twórz raz. Volumema zakres 0 do 1._player?.Stop()chroni przednull.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →