Flutter Friendly
1.04K subscribers
188 photos
71 videos
1 file
149 links
Канал Friflex о разработке на Flutter. Обновления, плагины, полезные материалы — превращаем знания в реальный опыт, доступный каждому разработчику.

🔗 Наш канал для разработчиков: @friflex_dev
🔗 Канал о продуктовой разработке: @friflex_product
Download Telegram
🙂Присоединяетесь, у нас тут Flutter-утренник

А пока вы готовите костюмы, хотим поздравить с Новым годом!

Больше инновационных проектов и вдохновения для их реализации
Больше стабильных релизов и довольных пользователей
И конечно, больше времени на творчество, изучение нового и отдых
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
14😁5🔥4👍1
💡Устроим небольшую проверку изученного за год? На новогодних праздниках вас будет ждать небольшая викторина от Розы, Кати и Анны
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2
Какие три основных подхода существуют для работы с иконками во Flutter?
Anonymous Quiz
4%
PNG, JPG, GIF
60%
Icon Fonts, SVG, Vector Graphics
33%
Material Icons, Cupertino Icons, Font Awesome
2%
Bitmap, Vector
Какой виджет позволяет дочернему элементу выходить за границы родителя?
Anonymous Quiz
84%
OverflowBox
3%
AspectRatio
11%
Expanded
2%
Align
Какие модификаторы можно комбинировать?
Anonymous Quiz
22%
base и final
27%
abstract и base
13%
sealed и base
39%
abstract и mixin
Какой Sliver позволяет вставить обычный виджет в CustomScrollView?
Anonymous Quiz
15%
SliverList
76%
SliverToBoxAdapter
4%
SliverAppBar
5%
SliverGrid
😎Надеемся, вы отлично отдыхаете!

За этот год во @flutterfriendly вышло 222 публикации, а вы поставили более 3800 реакций. Решили вспомнить посты, которые вы больше всего читали и которыми активно делились за 2025 год:

Аудит безопасности мобильных приложений: виды и этапы

Использование ARB-формата

Обновление Android Studio без ошибок

Как пользоваться режимом выбора виджетов

Пакет meta

Оптимизация списков: как сделать скролл плавным и эффективным

Виджеты для управления размерами

Работа с иконками

Библиотека dartx

FutureOr в Dart

gRPC во Flutter: эффективная коммуникация между клиентом и сервером

Модификаторы классов в Dart

Тестирование кода: виды и для чего это нужно

Режимы сборки: debug, profile и release

Friflex Flutter Starter

Паттерн Strategy

Запись митапа: способы темизации и кастомизации мобильных приложений

Создание виджетов поверх существующего интерфейса

Определение местоположение пользователя: интеграция в приложение

Как быстро развернуть сайт документации с помощью Docusaurus

Адаптивная верстка: что это такое и как реализовать

Утечки памяти во Flutter-приложениях

Техническое собеседование: как подготовиться начинающим разработчикам

Hot Restart и Hot Reload: в чем отличия и как работают
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥94
Какой принцип SOLID нарушен, если класс UserManager одновременно валидирует данные, сохраняет в БД и отправляет email?
Anonymous Quiz
2%
Принцип открытости/закрытости (O)
96%
Принцип единственной ответственности (S)
2%
Принцип инверсии зависимостей (D)
1%
Принцип подстановки Лисков (L)
Какой виджет лучше всего подходит для длинных списков с большим количеством простых элементов?
Anonymous Quiz
12%
SingleChildScrollView
14%
CustomScrollView
4%
Column
70%
ListView
Какой ключ лучше использовать для элементов списка с уникальным id из объекта item?
Anonymous Quiz
19%
UniqueKey
4%
GlobalKey
5%
ObjectKey(item)
💭Привет, это Катя, Flutter Dev Friflex

Сегодня поговорим про push‑уведомления в реальном проекте: как работать с FCM, показывать локальные уведомления в foreground, обрабатывать background‑события, реализовать deep links по клику и корректно запрашивать разрешения.

Так как это первая статья в новом году, поздравляю всех с праздниками! Желаю вам продуктивного и приятного 2026‑го: чтобы баги фиксились легко, а фичи шли в прод. Уже все вернулись к работе или кто‑то все еще лежит на диване?🌟

Что и зачем:
◾️
FCM (Firebase Cloud Messaging) — транспорт: доставляет уведомления/дату на устройство. Поддерживает notification (авто‑показ) и data‑messages (передача произвольных данных)
◾️flutter_local_notifications — показывает локальное нотификационное состояние, полезно, когда приложение на foreground (FCM обычно не показывает системное уведомление, если приложение активно)
◾️Deep links — позволяют при клике на уведомление перейти в конкретный экран приложения (через data payload или динамические ссылки)

Код: инициализация и обработка
Пакеты: firebase_core, firebase_messaging, flutter_local_notifications, (go_router / navigatorKey для навигации).

Простой пример:
// main.dart (сокращённо)
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

final FlutterLocalNotificationsPlugin localNotif = FlutterLocalNotificationsPlugin();

Future<void> _bgHandler(RemoteMessage m) async {
  await Firebase.initializeApp();
  // Лёгкая логика: запись в БД или планирование локальной нотификации
  print('BG message ${m.messageId}');
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FirebaseMessaging.onBackgroundMessage(_bgHandler);

  await localNotif.initialize(
    const InitializationSettings(
      android: AndroidInitializationSettings('@mipmap/ic_launcher'),
      iOS: DarwinInitializationSettings(),
    ),
    onDidReceiveNotificationResponse: (resp) {
      final p = resp.payload;
      if (p != null) navigatorKey.currentState?.pushNamed(p);
    },
  );

  runApp(MyApp());
}

final GlobalKey<NavigatorState> navigatorKey = GlobalKey();

class MyApp extends StatefulWidget { @override State createState() => _MyAppState(); }
class _MyAppState extends State<MyApp> {
  final FirebaseMessaging fm = FirebaseMessaging.instance;

  @override
  void initState() {
    super.initState();
    _requestPermissions();
    FirebaseMessaging.onMessage.listen(_onMessage);
    FirebaseMessaging.onMessageOpenedApp.listen((m) => _handleData(m.data));
    _checkInitialMessage();
  }

  Future<void> _requestPermissions() async {
    if (Platform.isIOS) {
      await fm.requestPermission(alert: true, badge: true, sound: true);
    } else {
      // Android 13+: POST_NOTIFICATIONS нужно в Manifest + runtime request (permission_handler)
      await fm.requestPermission();
    }
  }

  void _onMessage(RemoteMessage m) {
    // в foreground показываем локальную нотификацию
    final t = m.notification?.title ?? m.data['title'];
    final b = m.notification?.body ?? m.data['body'];
    localNotif.show(m.hashCode, t, b, const NotificationDetails(
      android: AndroidNotificationDetails('ch', 'Channel', importance: Importance.max),
    ), payload: m.data['deeplink']);
  }

  Future<void> _checkInitialMessage() async {
    final m = await fm.getInitialMessage();
    if (m != null) _handleData(m.data);
  }

  void _handleData(Map<String, dynamic> d) {
    final deeplink = d['deeplink'] ?? d['url'] ?? d['screen'];
    if (deeplink != null) navigatorKey.currentState?.pushNamed(deeplink);
  }

  @override
  Widget build(BuildContext c) => MaterialApp(navigatorKey: navigatorKey, home: Scaffold(body: Center(child: Text('Ready'))));
}


Продолжение — в комментариях 👇
Please open Telegram to view this post
VIEW IN TELEGRAM
52🔥1