- [Flutter] "Do it! 플러터 앱 프로그래밍" - 파이어베이스와 광고 수입 얻기 | 애널리틱스 사용, minSdk version 에러/FirebaseAnalytics() 문법 에러 처리2022년 02월 21일 13시 19분 10초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
"조준수. (2021). Do it! 플러터 앱 프로그래밍. 이지스퍼블리싱", 13장 중 파이어베이스 설정과 애널리틱스(analytics)를 실습하였다. 애널리틱스는 앱의 사용자를 분석해 주는 도구이다.
파이어베이스 설정하기
안드로이드 앱에 파이어베이스를 추가하는 과정으로 "google-services.json"을 android/app 폴더에 추가한다. "SDK 안내 보기"를 참고하여 android/build.gradle와 android/app/build.gradle 파일을 각각 수정한다.
위 과정이 완료되면 gradle sync를 해주어야 한다. VSCode에서 gradle sync를 하는 방법은 터미널에서 android 폴더로 이동 후 다음의 명령을 실행하면 된다.
.\gradlew --refresh-dependencies
애널리틱스 사용하기
구글 파이어베이스에서 프로젝트를 생성하고 앱을 연동해야 한다. 그 과정 중 파이어베이스 코어와 애널리틱스 패키지를 설치해야 한다.
firebase_core 패키지 설치
pub.dev에서 파이어베이스 코어 패키지를 찾아 설치한다(https://pub.dev/packages/firebase_core/install).
flutter pub add firebase_core
firebase_analytics 패키지 설치
pub.dev에서 파이어베이스 애널리틱스 패키지를 찾아 설치한다(https://pub.dev/packages/firebase_analytics/install).
flutter pub add firebase_analytics
minSdk version 에러
애널리틱스 이벤트 보내기 실습 도중 만난 에러이다.
Launching lib\main.dart on sdk gphone x86 in debug mode... lib\main.dart:1 C:\Users\J\Documents\GitHub\Do it Flutter\Flutter\flutter_firebase_example\android\app\src\debug\AndroidManifest.xml Error: uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:firebase_analytics] C:\Users\J\Documents\GitHub\Do it Flutter\Flutter\flutter_firebase_example\build\firebase_analytics\intermediates\library_manifest\debug\AndroidManifest.xml as the library might be using APIs not available in 16 Suggestion: use a compatible library with a minSdk of at most 16, or increase this project's minSdk version to at least 19, or use tools:overrideLibrary="io.flutter.plugins.firebase.analytics" to force usage (may lead to runtime failures) FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:processDebugMainManifest'. > Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:firebase_analytics] C:\Users\J\Documents\GitHub\Do it Flutter\Flutter\flutter_firebase_example\build\firebase_analytics\intermediates\library_manifest\debug\AndroidManifest.xml as the library might be using APIs not available in 16 Suggestion: use a compatible library with a minSdk of at most 16, or increase this project's minSdk version to at least 19, or use tools:overrideLibrary="io.flutter.plugins.firebase.analytics" to force usage (may lead to runtime failures)
구글링 후 얻게된 해결 방법은 android/app/build.gradle의 defalutConfig의 minSdkVersion의 값을 변경하는 것이다.
defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.flutter_firebase_example" // minSdkVersion flutter.minSdkVersion // 기존 minSdkVersion 19 // 변경 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName }
FirebaseAnalytics() 문법 에러
analytics 객체를 생성할 때 책 본문대로 코딩하게 되면 FirebaseAnalytics()에 빨간 줄이 그어지는 문법 에러가 발생하게 된다. 구글링해 FirebaseAnalytics.instance로 수정하면 해결된다. 하지만 실행 시 다음과 같은 에러가 발생한다.
Exception has occurred. FirebaseException ([core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp())
구글링으로 찾은 해법은 main 함수에 에 Firebase.initializeApp()를 추가해 주는 것이다. [그림 1]의 결과를 얻기까지 꽤 긴 시간 애를 먹었다. 정상 작동하는 코드는 다음과 같다.
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/observer.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; // 추가 void main() async { // async 추가 WidgetsFlutterBinding.ensureInitialized(); // 추가 await Firebase.initializeApp(); // 추가 runApp(MyApp()); } class MyApp extends StatelessWidget { // static FirebaseAnalytics analytics = FirebaseAnalytics(); // 본문의 코드. FirebaseAnalytics()에서 문법 에러 발생 static FirebaseAnalytics analytics = FirebaseAnalytics.instance; // FirebaseAnalytics()를 FirebaseAnalytics.instance로 수정 static FirebaseAnalyticsObserver observer = FirebaseAnalyticsObserver(analytics: analytics); @override Widget build(BuildContext context) { return MaterialApp( title: 'Firebase Example', theme: ThemeData( primarySwatch: Colors.blue, ), navigatorObservers: <NavigatorObserver>[observer], home: FirebaseApp( analytics: analytics, observer: observer, ), ); } } class FirebaseApp extends StatefulWidget { FirebaseApp({Key? key, required this.analytics, required this.observer}) : super(key: key); final FirebaseAnalytics analytics; final FirebaseAnalyticsObserver observer; @override _FirebaseAppState createState() => _FirebaseAppState(analytics, observer); } class _FirebaseAppState extends State<FirebaseApp> { _FirebaseAppState(this.analytics, this.observer); final FirebaseAnalyticsObserver observer; final FirebaseAnalytics analytics; String _message = ''; void setMessage(String message) { setState(() { _message = message; }); } Future<void> _sendAnalyticsEvent() async { // 애널리틱스의 logEvent를 호출해 test_event라는 키값으로 데이터 저장 await analytics.logEvent( name: 'test_event', parameters: <String, dynamic>{ 'string': 'hello flutter', 'int': 100, }, ); setMessage('Analytics 보내기 성공'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Firebase Example'), ), body: Center( child: Column( children: <Widget>[ ElevatedButton( child: Text('테스트'), onPressed: _sendAnalyticsEvent, ), Text(_message, style: const TextStyle(color: Colors.blueAccent)), ], mainAxisAlignment: MainAxisAlignment.center, ), ), floatingActionButton: FloatingActionButton(child: const Icon(Icons.tab), onPressed: () {}), ); } }
Observer 사용하기
FirebaseAnalyticsObserver는 사용자가 어떤 화면을 보고 있는지, 어떤 화면을 클릭했는지 등을 알고 싶을 때 사용한다.
// main.dart import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/observer.dart'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; // 추가 import 'tabsPage.dart'; void main() async { // async 추가 WidgetsFlutterBinding.ensureInitialized(); // 추가 await Firebase.initializeApp(); // 추가 runApp(MyApp()); } class MyApp extends StatelessWidget { // static FirebaseAnalytics analytics = FirebaseAnalytics(); // 본문의 코드. FirebaseAnalytics()에서 문법 에러 발생 static FirebaseAnalytics analytics = FirebaseAnalytics .instance; // FirebaseAnalytics()를 FirebaseAnalytics.instance로 수정 static FirebaseAnalyticsObserver observer = FirebaseAnalyticsObserver(analytics: analytics); @override Widget build(BuildContext context) { return MaterialApp( title: 'Firebase Example', theme: ThemeData( primarySwatch: Colors.blue, ), navigatorObservers: <NavigatorObserver>[observer], home: FirebaseApp( analytics: analytics, observer: observer, ), ); } } class FirebaseApp extends StatefulWidget { FirebaseApp({Key? key, required this.analytics, required this.observer}) : super(key: key); final FirebaseAnalytics analytics; final FirebaseAnalyticsObserver observer; @override _FirebaseAppState createState() => _FirebaseAppState(analytics, observer); } class _FirebaseAppState extends State<FirebaseApp> { _FirebaseAppState(this.analytics, this.observer); final FirebaseAnalyticsObserver observer; final FirebaseAnalytics analytics; String _message = ''; void setMessage(String message) { setState(() { _message = message; }); } Future<void> _sendAnalyticsEvent() async { // 애널리틱스의 logEvent를 호출해 test_event라는 키값으로 데이터 저장 await analytics.logEvent( name: 'test_event', parameters: <String, dynamic>{ 'string': 'hello flutter', 'int': 100, }, ); setMessage('Analytics 보내기 성공'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Firebase Example'), ), body: Center( child: Column( children: <Widget>[ ElevatedButton( child: Text('테스트'), onPressed: _sendAnalyticsEvent, ), Text(_message, style: const TextStyle(color: Colors.blueAccent)), ], mainAxisAlignment: MainAxisAlignment.center, ), ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.tab), // 플로팅 버튼을 눌렀을 때 라우트 기능을 이용해 tabsPage로 이동하는 코드 onPressed: () { Navigator.of(context).push(MaterialPageRoute<TabsPage>( settings: RouteSettings(name: '/tab'), builder: (BuildContext context) { return TabsPage(observer); })); }), ); } }
// tabsPage.dart import 'package:flutter/material.dart'; import 'package:firebase_analytics/observer.dart'; class TabsPage extends StatefulWidget { TabsPage(this.observer); // FirebaseAnalyticsObserver는 사용자가 어떤 화면을 보고 있는지, 어떤 화면을 클릭했는지 등을 알고 싶을 때 사용한다. final FirebaseAnalyticsObserver observer; @override State<StatefulWidget> createState() => _TabsPage(observer); } class _TabsPage extends State<TabsPage> with SingleTickerProviderStateMixin, RouteAware { _TabsPage(this.observer); final FirebaseAnalyticsObserver observer; TabController? _controller; int selectedIndex = 0; final List<Tab> tabs = <Tab>[ const Tab( text: '1번', icon: Icon(Icons.looks_one), ), const Tab( text: '2번', icon: Icon(Icons.looks_two), ), ]; @override void initState() { super.initState(); _controller = TabController( vsync: this, length: tabs.length, initialIndex: selectedIndex, ); // 탭을 클릭했을 때 발생하는 이벤트를 addListener 함수로 처리 _controller!.addListener(() { setState(() { if (selectedIndex != _controller!.index) { selectedIndex = _controller!.index; _sendCurrentTab(); } }); }); } // Observer를 이용하려면 FirebaseAnalyticsObserver를 사용한다고 앱에 알려야 한다. 이를 구독(subscribe)라고 한다. // state의 생명주기에서 didChangeDependencies는 initState 함수 다음에 상태에 변화가 생겼을 때와 dispose 함수가 호출되기 전에 호출되는 함수이다. // didChangeDependencies 함수를 재정의해 구독 @override void didChangeDependencies() { super.didChangeDependencies(); } // dispose 함수를 재정의해 구독 해지 @override void dispose() { observer.unsubscribe(this); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( bottom: TabBar( controller: _controller, tabs: tabs, ), ), body: TabBarView( controller: _controller, children: tabs.map((Tab tab) { return Center(child: Text(tab.text!)); }).toList(), ), ); } // 현재 화면 이름을 파이어베이스 애널리틱스에 보낸다. void _sendCurrentTab() { observer.analytics.setCurrentScreen( screenName: 'tab/$selectedIndex', ); } }
728x90반응형'언어·프레임워크 > Flutter' 카테고리의 다른 글
댓글