Impeller Flutter: Nowa era mobilnej grafiki
Mateusz Kędziora

Hej programiści Fluttera! Chcecie, żeby Wasze aplikacje działały płynniej, miały lepszą grafikę i wykorzystywały nowoczesne API? To dobrze trafiliście! W tym artykule przyjrzymy się Impellerowi – nowemu silnikowi renderującemu w Flutterze, który ma za zadanie zrewolucjonizować sposób, w jaki aplikacje są wyświetlane na ekranach.
Co to jest Impeller i dlaczego powstał?
Do niedawna Flutter polegał na silniku Skia do renderowania grafiki. Skia to bardzo wszechstronne i dojrzałe rozwiązanie, ale ma swoje ograniczenia. Przede wszystkim, Skia kompiluje shading w momencie uruchomienia aplikacji. To, z kolei, prowadzi do janków, czyli krótkotrwałych spadków wydajności, które są szczególnie uciążliwe w animacjach. Wyobraź sobie, że budujesz skomplikowaną animację, ale co jakiś czas widzisz przeskok. Frustrujące, prawda?
Impeller został stworzony, aby rozwiązać ten problem i zapewnić:
- Przewidywalną wydajność: Kompilacja shaderów odbywa się wcześniej – podczas budowania aplikacji (AOT – Ahead-Of-Time), a nie w trakcie jej działania. To eliminuje janki spowodowane kompilacją shaderów w locie.
- Ulepszoną grafikę: Impeller został zaprojektowany z myślą o nowoczesnych API graficznych, takich jak Metal (iOS) i Vulkan (Android). Pozwala to na pełne wykorzystanie możliwości tych API i rendering bardziej skomplikowanych i efektownych efektów wizualnych.
- Lepszą kontrolę: Impeller daje deweloperom większą kontrolę nad całym procesem renderowania.
Krótko mówiąc, Impeller to gruntowna przebudowa silnika renderującego, która ma na celu poprawę wydajności, jakości grafiki i kontroli deweloperów nad procesem renderowania w Flutterze.
Impeller vs. Skia: Porównanie
| Funkcja | Skia | Impeller |
|---|---|---|
| Kompilacja shaderów | JIT (Just-In-Time) – podczas działania | AOT (Ahead-Of-Time) – podczas budowania |
| API Graficzne | OpenGL ES (głównie) | Metal, Vulkan |
| Janki | Potencjalne (kompilacja shaderów) | Zminimalizowane |
| Wydajność | Zależna od urządzenia i złożoności grafiki | Bardziej przewidywalna i stabilna |
| Kontrola | Mniejsza | Większa |
Jak widzisz, Impeller oferuje szereg zalet w porównaniu ze Skia, szczególnie w kontekście wydajności i nowoczesnych API graficznych.
Cele Impellera: Przewidywalna wydajność, ulepszona grafika i nowoczesne API
Główne cele Impellera to:
- Przewidywalna wydajność: Eliminacja janków i zapewnienie płynnych animacji, niezależnie od urządzenia i złożoności grafiki.
- Ulepszona grafika: Wykorzystanie nowoczesnych API graficznych (Metal, Vulkan) do renderingu bardziej skomplikowanych i efektownych efektów wizualnych.
- Obsługa nowoczesnych API graficznych: Pełne wykorzystanie możliwości Metal (iOS) i Vulkan (Android) do optymalizacji renderowania.
- Lepsza debugowalność: Ułatwienie diagnozowania problemów związanych z renderowaniem i optymalizacja wydajności.
- Rozszerzalność: Ułatwienie dodawania nowych funkcji i optymalizacji w przyszłości.
Dostępność Impellera na różnych platformach
Obecnie (stan na maj 2025) Impeller jest dostępny na następujących platformach:
- iOS: W pełni obsługiwany i domyślnie włączony.
- Android: W pełni obsługiwany i domyślnie włączony (zależnie od konfiguracji urządzenia i wersji Fluttera).
- Web (CanvasKit): Planowana obsługa, ale na maj 2025 nie jest jeszcze domyślnie włączona.
- macOS: Eksperymentalna obsługa. Może wymagać włączenia flagą konfiguracyjną.
- Windows: Eksperymentalna obsługa. Może wymagać włączenia flagą konfiguracyjną.
- Linux: Planowana obsługa.
Ważne: Dostępność i status włączenia Impellera mogą się zmieniać w kolejnych wersjach Fluttera. Zawsze sprawdzaj najnowszą dokumentację Fluttera, aby uzyskać aktualne informacje.
Włączanie i Wyłączanie Impellera
iOS:
Od Flutter 3.16, Impeller jest domyślnie włączony dla iOS. Nie ma potrzeby ręcznego włączania. Aby go wyłączyć (tylko w celach testowych lub debugowania), możesz dodać następujący klucz do pliku Info.plist w katalogu ios/Runner/:
<key>FLTEnableImpeller</key>
<false/>Android:
Impeller na Androidzie jest domyślnie włączony, pod warunkiem spełnienia pewnych wymagań:
- Urządzenie musi mieć Androida w wersji 10 (API level 29) lub nowszej.
- Urządzenie musi obsługiwać Vulkan 1.1 lub nowszą.
Aby sprawdzić, czy Impeller jest włączony na Androidzie, możesz użyć polecenia:
adb shell getprop ro.gfx.driver.impellerJeśli polecenie zwróci 1, Impeller jest włączony.
Jeśli chcesz eksperymentalnie włączyć Impeller na Androidzie, nawet jeśli nie spełnia on wymagań domyślnych (uważaj, może to spowodować problemy!), możesz spróbować:
Dodaj następujący kod do pliku
android/app/src/main/AndroidManifest.xmlw tagu<application>:<meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="true" />Uruchom aplikację.
Ważne: Włączanie Impellera na urządzeniach, które nie spełniają minimalnych wymagań, może prowadzić do problemów z wydajnością lub stabilnością.
Web (CanvasKit):
Obecnie nie ma domyślnej obsługi Impellera w CanvasKit. Należy śledzić oficjalne komunikaty od zespołu Fluttera odnośnie przyszłej implementacji.
macOS i Windows:
Na tych platformach Impeller jest w fazie eksperymentalnej i może wymagać włączenia poprzez flagę konfiguracyjną podczas uruchamiania aplikacji. Dokładne instrukcje znajdziesz w dokumentacji Fluttera dotyczącej budowania aplikacji na te platformy. Zazwyczaj wygląda to tak:
flutter run --enable-impeller # macOS
flutter run --enable-impeller # WindowsKorzyści wydajnościowe: Płynniejsze animacje i redukcja zacięć
Główną korzyścią wynikającą z używania Impellera jest poprawa wydajności, a w szczególności:
- Płynniejsze animacje: Eliminacja janków spowodowanych kompilacją shaderów w locie skutkuje płynniejszymi animacjami, co znacząco poprawia wrażenia użytkownika.
- Redukcja zacięć: Ogólna poprawa wydajności renderowania prowadzi do zmniejszenia liczby zacięć i opóźnień, szczególnie w skomplikowanych interfejsach użytkownika.
- Bardziej przewidywalna wydajność: Dzięki kompilacji shaderów AOT, wydajność aplikacji jest bardziej przewidywalna i mniej zależna od specyfikacji urządzenia.
- Lepsza wydajność na starszych urządzeniach: Impeller może poprawić wydajność aplikacji na starszych urządzeniach, które mogą mieć problemy z wydajnym renderowaniem grafiki za pomocą Skia.
Przykład:
Wyobraź sobie, że masz złożoną animację przejścia między ekranami, która wykorzystuje wiele warstw i efektów wizualnych. Na urządzeniu z Skia możesz zauważyć sporadyczne janki podczas uruchamiania animacji po raz pierwszy. Z Impellerem animacja powinna działać płynniej i bardziej stabilnie, bez względu na to, ile razy ją uruchamiasz.
Rozwiązywanie problemów z Impellerem
Jeśli napotkasz problemy z Impellerem, oto kilka kroków, które możesz podjąć:
- Sprawdź, czy Impeller jest włączony: Upewnij się, że Impeller jest włączony na Twojej platformie (zgodnie z instrukcjami powyżej).
- Zaktualizuj Fluttera: Używaj najnowszej stabilnej wersji Fluttera. Nowe wersje często zawierają poprawki błędów i optymalizacje związane z Impellerem.
- Sprawdź logi: Przejrzyj logi aplikacji w poszukiwaniu błędów lub ostrzeżeń związanych z renderowaniem grafiki.
- Wyłącz Impeller (tymczasowo): Jeśli podejrzewasz, że Impeller powoduje problemy, możesz go tymczasowo wyłączyć (zgodnie z instrukcjami powyżej) i sprawdzić, czy problem zniknie. Jeśli tak, prawdopodobnie znalazłeś błąd związany z Impellerem.
- Użyj narzędzi debugowania grafiki: Użyj narzędzi debugowania grafiki (np. RenderDoc) aby zbadać proces renderowania i zidentyfikować potencjalne problemy.
- Przetestuj na różnych urządzeniach: Sprawdź, czy problem występuje tylko na konkretnym urządzeniu, czy na wszystkich urządzeniach.
Zgłaszanie błędów związanych z Impellerem
Jeśli zidentyfikujesz błąd związany z Impellerem, ważne jest, aby go zgłosić zespołowi Fluttera. Oto jak to zrobić:
- Stwórz minimalny przykład kodu: Spróbuj stworzyć minimalny przykład kodu, który odtwarza problem. Im prostszy przykład, tym łatwiej będzie zespołowi Fluttera zdiagnozować i naprawić błąd.
- Sprawdź istniejące zgłoszenia: Przed zgłoszeniem nowego błędu, sprawdź, czy ktoś inny nie zgłosił już tego samego problemu. Możesz przeszukać repozytorium Fluttera na GitHubie, używając słów kluczowych związanych z Twoim problemem.
- Zgłoś błąd na GitHubie: Jeśli nie znajdziesz istniejącego zgłoszenia, zgłoś nowy błąd w repozytorium Fluttera na GitHubie.
- Podaj szczegółowy opis problemu.
- Dołącz minimalny przykład kodu, który odtwarza problem.
- Podaj informacje o swoim środowisku (wersja Fluttera, system operacyjny, urządzenie).
- Dołącz logi aplikacji.
Im więcej informacji podasz, tym łatwiej będzie zespołowi Fluttera pomóc.
Przykład zgłoszenia błędu:
Tytuł: Jank podczas animacji przejścia na iOS z Impellerem
Opis: Podczas animacji przejścia między ekranami na iOS (iPhone 13, iOS 16.4, Flutter 3.10.0, Impeller włączony) zauważam sporadyczne janki. Problem występuje tylko z Impellerem. Po wyłączeniu Impellera animacja działa płynnie.
Przykład kodu:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FirstScreen(),
);
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Pierwszy ekran')),
body: Center(
child: ElevatedButton(
child: Text('Przejdź do drugiego ekranu'),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => SecondScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
),
);
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Drugi ekran')),
body: Center(
child: Text('To jest drugi ekran'),
),
);
}
}Logi:
(Dołącz logi aplikacji z momentu wystąpienia problemu)
Informacje o środowisku:
- Flutter: 3.10.0
- System operacyjny: iOS 16.4
- Urządzenie: iPhone 13
- Impeller: Włączony
Przykłady kodu i implementacji
Oto kilka przykładów kodu, które pokazują, jak używać Impellera w praktyce (pamiętaj, że w większości przypadków nie musisz nic robić, Impeller powinien działać automatycznie!):
Przykład 1: Prosta animacja z użyciem AnimatedBuilder
Ten przykład pokazuje, jak stworzyć prostą animację z użyciem AnimatedBuilder. Impeller powinien renderować tę animację płynniej niż Skia.
import 'package:flutter/material.dart';
class AnimatedSquare extends StatefulWidget {
@override
_AnimatedSquareState createState() => _AnimatedSquareState();
}
class _AnimatedSquareState extends State<AnimatedSquare> with SingleTickerProviderStateMixin {
AnimationController? _controller;
Animation<double>? _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = Tween<double>(begin: 0, end: 2 * 3.14159).animate(_controller!)
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller!.repeat();
} else if (status == AnimationStatus.dismissed) {
_controller!.forward();
}
});
_controller!.forward();
}
@override
void dispose() {
_controller!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Transform.rotate(
angle: _animation!.value,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
}
}Wyjaśnienie:
AnimatedSquaretoStatefulWidget, który zawiera animację obracającego się kwadratu.AnimationControllerkontroluje postęp animacji.Tweendefiniuje zakres wartości animacji (od 0 do 2π radianów).Transform.rotateobraca kwadrat o kąt określony przez wartość animacji.setState(() {})powoduje przebudowanie widgetu przy każdej zmianie wartości animacji.
Przykład 2: Użycie ShaderMask
Ten przykład pokazuje, jak użyć ShaderMask do stworzenia efektu maskowania. Impeller powinien renderować ten efekt wydajniej niż Skia.
import 'package:flutter/material.dart';
class ShaderMaskExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.black, Colors.transparent],
).createShader(bounds);
},
blendMode: BlendMode.dstIn,
child: Image.network(
'https://via.placeholder.com/300x200',
width: 300,
height: 200,
),
),
);
}
}Wyjaśnienie:
ShaderMaskpozwala na maskowanie widgetu za pomocą shadera.shaderCallbackdefiniuje shader, który będzie używany do maskowania. W tym przypadku używamy gradientu liniowego.blendModeokreśla sposób łączenia shadera z widgetem. W tym przypadku używamyBlendMode.dstIn, który powoduje, że widoczne są tylko te obszary widgetu, które są pokryte przez shader.
Pamiętaj: Te przykłady mają na celu pokazanie, jak używać standardowych widgetów Fluttera. Impeller powinien automatycznie optymalizować rendering tych widgetów, bez konieczności wprowadzania jakichkolwiek zmian w kodzie.
Podsumowanie
Impeller to obiecująca inicjatywa, która ma potencjał, aby znacząco poprawić wydajność i jakość grafiki w aplikacjach Fluttera. Chociaż jest to stosunkowo nowy silnik renderujący, warto się nim zainteresować i eksperymentować z nim w swoich projektach.
Przydatne linki
- Oficjalna dokumentacja Fluttera: https://flutter.dev/ (szukaj informacji o Impellerze w najnowszych dokumentach)
- Repozytorium Fluttera na GitHubie: https://github.com/flutter/flutter (do zgłaszania błędów)
- Śledzenie postępów prac nad Impellerem: https://github.com/flutter/flutter/labels/engine%3A%20impeller (filtry na GitHubie pozwalają na bieżąco śledzić rozwój silnika)
Dalsza nauka
Zachęcam Cię do dalszego eksplorowania tematu Impellera. Przeczytaj oficjalną dokumentację Fluttera, śledź postępy prac na GitHubie i eksperymentuj z Impellerem w swoich projektach. Pamiętaj, że jest to wciąż rozwijający się projekt, więc bądź na bieżąco z najnowszymi informacjami. Powodzenia!
Mam nadzieję że ten artykuł był dla Ciebie pomocny. Zapraszam do czytania innych postów na naszym blogu!
Chroń swój komputerPolecane artykuły
Moje Projekty 3D: MakerWorld i Printables
Odkryj fizyczne projekty 3D stworzone przezemnie. Modele do druku 3D na MakerWorld i Printables. Połącz kodowanie z namacalną innowacją.
Mateusz Kędziora
Bubble Drop: Merge Challenge – Nowa Wciągająca Gra Mobilna na Androida
Zagraj w Bubble Drop: Merge Challenge – moją nową, uzależniającą grę mobilną na Androida! Zrzucaj, łącz i buduj strategie, by przetrwać kulkowy armagedon.
Mateusz Kędziora
Flutter DevTools: Debugowanie UI
Debugowanie układu UI we Flutterze z Flutter DevTools. Praktyczne wskazówki i techniki dla developerów.
Mateusz Kędziora


