Never give up

Flutter - RouteObserver 본문

Flutter

Flutter - RouteObserver

대기만성 개발자 2022. 9. 8. 13:57
반응형

화면 이동을 tracking 하는 용도로 사용할 때 RouteObserver를 사용하면 간단합니다

void main() {
  runApp(MaterialApp(
    home: const MyApp(),
    navigatorObservers: [CommonRouteObserver()],
  ));
}

MaterialApp의 navigatorObservers에  등록을 해주고

 

RouteObserver를 상속받은 클래스의 기능을 정의해줍니다

class CommonRouteObserver extends RouteObserver<PageRoute<dynamic>> {
  void _saveScreenView(
      {PageRoute<dynamic>? oldRoute,
      PageRoute<dynamic>? newRoute,
      String? routeType}) {
    debugPrint(
        '[track] screen old : ${oldRoute?.settings.name}, new : ${newRoute?.settings.name}');
  }

  PageRoute? checkPageRoute(Route<dynamic>? route) {
    return (route is PageRoute) ? route : null;
  }

  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didPush(route, previousRoute);
    _saveScreenView(
      newRoute: checkPageRoute(route),
      oldRoute: checkPageRoute(previousRoute),
      routeType: 'push',
    );
  }

  @override
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
    _saveScreenView(
      newRoute: checkPageRoute(newRoute),
      oldRoute: checkPageRoute(oldRoute),
      routeType: 'replace',
    );
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didPop(route, previousRoute);
    _saveScreenView(
      newRoute: checkPageRoute(previousRoute),
      oldRoute: checkPageRoute(route),
      routeType: 'pop',
    );
  }

  @override
  void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didPop(route, previousRoute);
    _saveScreenView(
      newRoute: checkPageRoute(route),
      oldRoute: checkPageRoute(previousRoute),
      routeType: 'remove',
    );
  }
}

먼저 자주(?) 사용하는 기능들을 override해서

 

이전에 기존에 있던 위치 그리고 이동할 위치를 각각 정의해줍니다

 

여기서 주의할 부분은 didPop은 route가 반대입니다

 

그리고 테스트에 사용할 view들을 간단하게(?) 만들어봤습니다

// MyApp class
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  final List<Widget> _list = const [Route1(), Route2()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('UUID Example'),
      ),
      body: ListView.builder(
        itemCount: _list.length,
        itemBuilder: (_, index) {
          return ListTile(
            title: Text('Route - $index'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => _list[index],
                  settings: RouteSettings(name: '/Route - $index'),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

// Route1 class
class Route1 extends StatelessWidget {
  const Route1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: ElevatedButton(
        child: const Text('뒤로가기'),
        onPressed: () {
          Navigator.pop(context);
        },
      ),
    ));
  }
}

// Route2 class
class Route2 extends StatelessWidget {
  const Route2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: ElevatedButton(
        child: const Text('뒤로가기'),
        onPressed: () {
          Navigator.pop(context);
        },
      ),
    ));
  }
}

이동할 route의 이름을 정의해주는 부분이 있는데

 

namedRoute를 사용하면 routeSetting부분을 생략해도 됩니다

 

그리고 간단하게 push/pop 하는 구조로 만들어서 테스트를 해보면

< Route 이동 위치 >

잘 작동하는것을 확인할 수 있습니다

 

FirebaseAnalytics를 이용하신다면

 

saveScreenView 부분에

FirebaseAnalytics.instance.logScreenView(screenName: '${newRoute?.settings.name}');

해당 부분을 넣어주면 route가 이동할 때마다 FirebaseAnalytics에 트래킹이 가능합니다

반응형
Comments