diff --git a/android/app/build.gradle b/android/app/build.gradle index 4acf747..4bad09c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -104,6 +104,7 @@ flutter { } dependencies { + implementation 'com.google.android.material:material:1.8.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation platform('com.google.firebase:firebase-bom:30.2.0') implementation 'com.google.firebase:firebase-analytics' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cc9aea6..cacde2d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -31,6 +31,9 @@ android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> + @@ -43,6 +46,7 @@ + - diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef88..e0759f9 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -12,7 +12,7 @@ running. This Theme is only used starting with V2 of Flutter's Android embedding. --> - diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..9625e10 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 54afc67..d592aff 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -216,6 +216,7 @@ }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -230,6 +231,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -339,7 +341,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -417,7 +419,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -466,7 +468,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index dc779fd..1444df1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -63,5 +63,7 @@ + UIApplicationSupportsIndirectInputEvents + diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart index 16846f6..cc758f9 100644 --- a/lib/constants/constants.dart +++ b/lib/constants/constants.dart @@ -3,8 +3,8 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; String address = dotenv.get("BACKEND_ADDRESS"); -final BaseOptions ConnectionOptions = BaseOptions( +final BaseOptions connectionOptions = BaseOptions( baseUrl: address, - connectTimeout: 15000, - receiveTimeout: 13000, + connectTimeout: Duration(seconds: 150), + receiveTimeout: Duration(seconds: 130), ); diff --git a/lib/main.dart b/lib/main.dart index 519a177..6e44815 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,10 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:taxiapp/utils/fcmToken.dart'; +import 'package:taxiapp/utils/pushHandler.dart'; import 'package:taxiapp/utils/token.dart'; import 'package:taxiapp/views/taxiView.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -12,10 +14,10 @@ late AndroidNotificationChannel channel; late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; void main() async { - await dotenv.load(fileName: ".env"); - WidgetsFlutterBinding.ensureInitialized(); + await dotenv.load(fileName: ".env"); + await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); @@ -27,15 +29,6 @@ void main() async { importance: Importance.high, ); - var initializationSettingsAndroid = - const AndroidInitializationSettings('@mipmap/ic_launcher'); - - var initializationSettingsIOS = const IOSInitializationSettings( - requestAlertPermission: true, - requestBadgePermission: true, - requestSoundPermission: true, - ); - flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); await flutterLocalNotificationsPlugin @@ -43,14 +36,7 @@ void main() async { AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); - var initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - iOS: initializationSettingsIOS, - ); - - await flutterLocalNotificationsPlugin.initialize( - initializationSettings, - ); + FirebaseMessaging.onBackgroundMessage(handleMessage); await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, @@ -73,40 +59,10 @@ void main() async { await FcmToken().init(); - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({Key? key}) : super(key: key); - - @override - State createState() => _MyAppState(); + runApp(MyHome()); } -class _MyAppState extends State { - @override - void initState() { - FirebaseMessaging.onMessage.listen((RemoteMessage message) async { - RemoteNotification? notification = message.notification; - AndroidNotification? android = message.notification?.android; - var androidNotiDetails = AndroidNotificationDetails( - channel.id, channel.name, - channelDescription: channel.description); - - var iOSNotiDetails = const IOSNotificationDetails(); - - var details = - NotificationDetails(android: androidNotiDetails, iOS: iOSNotiDetails); - - if (notification != null) { - flutterLocalNotificationsPlugin.show(notification.hashCode, - notification.title, notification.body, details); - } - }); - - super.initState(); - } - +class MyHome extends HookWidget { @override Widget build(BuildContext context) { return MaterialApp( @@ -115,10 +71,12 @@ class _MyAppState extends State { primarySwatch: Colors.blue, ), home: Container( - color: const Color(0xFF6E3647), - child: Container( - child: Container(color: Colors.white, child: TaxiView()), - )), + color: const Color(0xFF6E3647), + child: Container( + color: Colors.white, + child: TaxiView(), + ), + ), ); } } diff --git a/lib/utils/fcmToken.dart b/lib/utils/fcmToken.dart index b7f2e07..7e269da 100644 --- a/lib/utils/fcmToken.dart +++ b/lib/utils/fcmToken.dart @@ -7,7 +7,7 @@ class FcmToken { static FcmToken? _instance; - final Dio _dio = Dio(ConnectionOptions); + final Dio _dio = Dio(connectionOptions); FcmToken._internal({required this.token}); diff --git a/lib/utils/pushHandler.dart b/lib/utils/pushHandler.dart new file mode 100644 index 0000000..1731235 --- /dev/null +++ b/lib/utils/pushHandler.dart @@ -0,0 +1,51 @@ +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:taxiapp/utils/fcmToken.dart'; +import 'package:taxiapp/utils/token.dart'; +import 'package:taxiapp/views/taxiView.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:taxiapp/firebase_options.dart'; +import 'package:http/http.dart' as http; +import 'dart:typed_data'; +import 'dart:math'; + +@pragma('vm:entry-point') +Future handleMessage(RemoteMessage message) async { + var channel = const AndroidNotificationChannel( + 'taxi_channel', + 'taxi_notification', + description: 'This channel is used for taxi notifications', + importance: Importance.high, + ); + + var flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + + ByteArrayAndroidBitmap? largeIcon; + + if (message.data['icon'] != null) { + largeIcon = ByteArrayAndroidBitmap( + await _getByteArrayFromUrl(message.data['icon']), + ); + } + var androidNotiDetails = AndroidNotificationDetails(channel.id, channel.name, + channelDescription: channel.description, largeIcon: largeIcon); + + var iOSNotiDetails = const DarwinNotificationDetails(); + + var details = + NotificationDetails(android: androidNotiDetails, iOS: iOSNotiDetails); + + if (message.data != null) { + flutterLocalNotificationsPlugin.show(Random().nextInt(100000000), + message.data['title'], message.data['body'], details, + payload: message.data['url']); + } +} + +Future _getByteArrayFromUrl(String url) async { + final http.Response response = await http.get(Uri.parse(url)); + return response.bodyBytes; +} diff --git a/lib/utils/token.dart b/lib/utils/token.dart index 60c308c..459bdac 100644 --- a/lib/utils/token.dart +++ b/lib/utils/token.dart @@ -13,7 +13,7 @@ class Token { static Token? _instance; static final _storage = FlutterSecureStorage(); - final Dio _dio = Dio(ConnectionOptions); + final Dio _dio = Dio(connectionOptions); final CookieJar _cookieJar = CookieJar(); Token._internal({required this.accessToken, required this.refreshToken}); @@ -76,7 +76,7 @@ class Token { } if (response.statusCode == 200) { List cookies = await _cookieJar.loadForRequest( - Uri.parse(ConnectionOptions.baseUrl + "auth/app/token/login")); + Uri.parse(connectionOptions.baseUrl + "auth/app/token/login")); for (Cookie cookie in cookies) { if (cookie.name == "connect.sid") { return cookie.value; diff --git a/lib/views/loginView.dart b/lib/views/loginView.dart index 98a749c..e06188d 100644 --- a/lib/views/loginView.dart +++ b/lib/views/loginView.dart @@ -23,7 +23,7 @@ class LoginView extends HookWidget { final _url = Uri.parse(_backUrl).replace(path: "api/auth/app/token/generate"); - final callbackUrlScheme = "org.sparcs.taxi_app"; + const callbackUrlScheme = "org.sparcs.taxiapp"; final result = await FlutterWebAuth.authenticate( url: _url.toString(), @@ -45,23 +45,24 @@ class LoginView extends HookWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Image(image: AssetImage('assets/img/taxiLogoText.png'), height: 60), - Padding(padding: EdgeInsets.only(top: 15)), + const Image( + image: AssetImage('assets/img/taxiLogoText.png'), height: 60), + const Padding(padding: EdgeInsets.only(top: 15)), OutlinedButton( style: ButtonStyle( - fixedSize: MaterialStateProperty.all(Size(250, 45)), + fixedSize: MaterialStateProperty.all(const Size(250, 45)), backgroundColor: - MaterialStateProperty.all(Color(0xFF6E3678)), + MaterialStateProperty.all(const Color(0xFF6E3678)), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), - side: BorderSide(color: Colors.black), + side: const BorderSide(color: Colors.black), ), ), ), child: Text("로그인", style: GoogleFonts.roboto( - textStyle: TextStyle( + textStyle: const TextStyle( color: Colors.white, fontSize: 15, fontWeight: FontWeight.bold))), diff --git a/lib/views/taxiView.dart b/lib/views/taxiView.dart index b7b0428..fc4b439 100644 --- a/lib/views/taxiView.dart +++ b/lib/views/taxiView.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter/material.dart'; @@ -7,15 +8,23 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:package_info/package_info.dart'; import 'package:taxiapp/utils/fcmToken.dart'; +import 'package:taxiapp/utils/pushHandler.dart'; import 'package:taxiapp/views/loadingView.dart'; import 'package:taxiapp/views/loginView.dart'; import 'package:taxiapp/utils/token.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; + import 'package:taxiapp/views/taxiDialog.dart'; class TaxiView extends HookWidget { final CookieManager _cookieManager = CookieManager.instance(); - late InAppWebViewController _controller; + // late InAppWebViewController _controller; + + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + TaxiView(); @override Widget build(BuildContext context) { @@ -24,7 +33,82 @@ class TaxiView extends HookWidget { final isLogin = useState(false); final isAuthLogin = useState(true); final backCount = useState(false); + final isFirstLoaded = useState(0); + final url = useState(''); + final _controller = useRef(null); final isMustUpdate = useState(false); + final pullToRefreshController = + useRef(PullToRefreshController( + onRefresh: () async { + if (Platform.isAndroid) { + _controller.value!.reload(); + } else { + _controller.value!.loadUrl( + urlRequest: URLRequest(url: await _controller.value!.getUrl())); + } + }, + )); + + useEffect(() { + var initializationSettingsAndroid = + const AndroidInitializationSettings('@mipmap/ic_launcher'); + + var initializationSettingsIOS = const DarwinInitializationSettings( + requestAlertPermission: true, + requestBadgePermission: true, + requestSoundPermission: true, + ); + + var initializationSettings = InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsIOS, + ); + + FirebaseMessaging.onMessage.listen((RemoteMessage message) async { + if (message.data['url'] != null) { + if (message.data['url'] == + (await _controller.value!.getUrl()) + ?.path + .replaceAll("chatting", "myroom")) { + return; + } else { + handleMessage(message); + } + } + }); + + flutterLocalNotificationsPlugin.initialize( + initializationSettings, + onDidReceiveNotificationResponse: (details) { + if (details.payload != null) { + String address = dotenv.get("FRONT_ADDRESS"); + url.value = address + details.payload!; + isFirstLoaded.value += 1; + } + }, + ); + + flutterLocalNotificationsPlugin + .getNotificationAppLaunchDetails() + .then((NotificationAppLaunchDetails? details) { + if (details != null) { + if (details.didNotificationLaunchApp && + details.notificationResponse?.payload != null) { + String address = dotenv.get("FRONT_ADDRESS"); + url.value = address + details.notificationResponse!.payload!; + isFirstLoaded.value != 1; + } + } + }); + }, []); + + useEffect(() { + if (url.value != '') { + _controller.value! + .loadUrl(urlRequest: URLRequest(url: Uri.parse(url.value))) + .then((value) {}); + } + }, [isFirstLoaded.value]); final AnimationController aniController = useAnimationController( duration: const Duration(milliseconds: 500), @@ -47,7 +131,7 @@ class TaxiView extends HookWidget { await remoteConfig.setDefaults({"version": value.version}); await remoteConfig.fetchAndActivate(); if (remoteConfig.getString("version") != value.version) { - isMustUpdate.value = true; + // isMustUpdate.value = true; } } catch (e) { print(e); @@ -65,11 +149,11 @@ class TaxiView extends HookWidget { sessionToken.value = value; isLogin.value = true; try { - await _controller.loadUrl( - urlRequest: URLRequest(url: Uri.parse(address))); + await _controller.value! + .loadUrl(urlRequest: URLRequest(url: Uri.parse(address))); } catch (e) { Fluttertoast.showToast( - msg: "로그인 정보 확인에 실패했습니다.", + msg: "초기 페이지 로딩에 실패했습니다.", backgroundColor: Colors.white, toastLength: Toast.LENGTH_SHORT, ); @@ -81,6 +165,7 @@ class TaxiView extends HookWidget { }, [isAuthLogin.value]); useEffect(() { + pullToRefreshController.value.setEnabled(true); Timer(const Duration(seconds: 2), () { isLoaded.value = true; }); @@ -89,84 +174,90 @@ class TaxiView extends HookWidget { return SafeArea( child: Stack(children: [ WillPopScope( - onWillPop: () => _goBack(context, backCount, isAuthLogin), - child: InAppWebView( - initialOptions: InAppWebViewGroupOptions( - crossPlatform: - InAppWebViewOptions(useShouldOverrideUrlLoading: true), - android: - AndroidInAppWebViewOptions(useHybridComposition: true)), - initialUrlRequest: URLRequest(url: Uri.parse(address)), - onWebViewCreated: (InAppWebViewController webcontroller) async { - _controller = webcontroller; - }, - // React Link는 Page를 로드하는 것이 아니라 history를 바꾸는 것이기 때문에 history 변화로 링크 변화를 감지해야함. - onUpdateVisitedHistory: (controller, url, androidIsReload) async { - // 세션이 만료되어 로그인 페이지로 돌아갈 시 자동으로 세션 갱신 - if (url.toString().contains("login") && - isLogin.value && - isAuthLogin.value) { - try { - String? session = await Token().getSession(); - if (session == null) { - isLogin.value = false; - isAuthLogin.value = false; - } else { - sessionToken.value = session; - await _controller.loadUrl( - urlRequest: URLRequest(url: Uri.parse(address))); - } - } catch (e) { - // TODO handle error - Fluttertoast.showToast( - msg: "서버와의 연결에 실패했습니다.", - toastLength: Toast.LENGTH_SHORT, - ); - isAuthLogin.value = false; - } - } - // 로그아웃 감지 시 토큰 지우고 처음 로그인 페이지로 돌아가기 - if (url.toString().contains("logout") && isLogin.value) { - try { - await FcmToken().removeToken(Token().getAccessToken()); - await Token().deleteAll(); + onWillPop: () => + _goBack(context, backCount, isAuthLogin, _controller.value), + child: Scaffold( + body: InAppWebView( + initialOptions: InAppWebViewGroupOptions( + crossPlatform: + InAppWebViewOptions(useShouldOverrideUrlLoading: true), + android: + AndroidInAppWebViewOptions(useHybridComposition: true)), + initialUrlRequest: URLRequest(url: Uri.parse(address)), + onWebViewCreated: (InAppWebViewController webcontroller) async { + _controller.value = webcontroller; + }, + // React Link는 Page를 로드하는 것이 아니라 history를 바꾸는 것이기 때문에 history 변화로 링크 변화를 감지해야함. + onUpdateVisitedHistory: (controller, url, androidIsReload) async { + // 세션이 만료되어 로그인 페이지로 돌아갈 시 자동으로 세션 갱신 + if (url.toString().contains("login") && + isLogin.value && + isAuthLogin.value) { + try { + String? session = await Token().getSession(); + if (session == null) { isLogin.value = false; isAuthLogin.value = false; - } catch (e) { - // TODO - Fluttertoast.showToast( - msg: "서버와의 연결에 실패했습니다.", - toastLength: Toast.LENGTH_SHORT, - ); - isAuthLogin.value = false; + } else { + sessionToken.value = session; + await _controller.value!.loadUrl( + urlRequest: URLRequest(url: Uri.parse(address))); } + } catch (e) { + // TODO handle error + Fluttertoast.showToast( + msg: "서버와의 연결에 실패했습니다.", + toastLength: Toast.LENGTH_SHORT, + ); + isAuthLogin.value = false; } - }, - onLoadStart: (controller, uri) async { - if (sessionToken.value != '') { - try { - await _cookieManager.deleteAllCookies(); - await _cookieManager.setCookie( - url: Uri.parse(address), - name: "connect.sid", - value: sessionToken.value, - ); - await _cookieManager.setCookie( - url: Uri.parse(address), - name: "deviceToken", - value: FcmToken().fcmToken, - ); - } catch (e) { - // TODO : handle error - Fluttertoast.showToast( - msg: "서버와의 연결에 실패했습니다.", - toastLength: Toast.LENGTH_SHORT, - ); - isAuthLogin.value = false; - } + } + // 로그아웃 감지 시 토큰 지우고 처음 로그인 페이지로 돌아가기 + if (url.toString().contains("logout") && isLogin.value) { + try { + await FcmToken().removeToken(Token().getAccessToken()); + await Token().deleteAll(); + isLogin.value = false; + isAuthLogin.value = false; + } catch (e) { + // TODO + Fluttertoast.showToast( + msg: "서버와의 연결에 실패했습니다.", + toastLength: Toast.LENGTH_SHORT, + ); + isAuthLogin.value = false; + } + } + }, + onLoadStart: (controller, uri) async { + _controller.value = controller; + if (sessionToken.value != '') { + try { + await _cookieManager.deleteAllCookies(); + await _cookieManager.setCookie( + url: Uri.parse(address), + name: "connect.sid", + value: sessionToken.value, + ); + await _cookieManager.setCookie( + url: Uri.parse(address), + name: "deviceToken", + value: FcmToken().fcmToken, + ); + } catch (e) { + // TODO : handle error + Fluttertoast.showToast( + msg: "서버와의 연결에 실패했습니다.", + toastLength: Toast.LENGTH_SHORT, + ); + isAuthLogin.value = false; } - }, - onLoadStop: (finish, uri) async {})), + } + }, + onLoadStop: (finish, uri) async { + pullToRefreshController.value.endRefreshing(); + }), + ), isAuthLogin.value ? Stack() : LoginView(isAuthLogin), isLoaded.value ? Stack() @@ -181,9 +272,12 @@ class TaxiView extends HookWidget { ])); } - Future _goBack(BuildContext context, ValueNotifier backCount, - ValueNotifier isAuthLogin) async { - Uri? current_uri = await _controller.getUrl(); + Future _goBack( + BuildContext context, + ValueNotifier backCount, + ValueNotifier isAuthLogin, + InAppWebViewController? _controller) async { + Uri? current_uri = await _controller!.getUrl(); if (await _controller.canGoBack() && (current_uri?.path != '/') && isAuthLogin.value && diff --git a/pubspec.yaml b/pubspec.yaml index f20a46b..480db64 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.1+4 +version: 1.0.1+7 environment: sdk: ">=2.17.5 <3.0.0" @@ -33,19 +33,19 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - flutter_hooks: ^0.18.5+1 - webview_flutter: ^3.0.4 - flutter_inappwebview: ^5.4.3+8 - flutter_secure_storage: ^5.0.2 - dio: ^4.0.6 - firebase_messaging: ^14.2.1 - flutter_local_notifications: ^9.3.2 - firebase_core: ^2.4.0 + flutter_hooks: ^0.18.6 + flutter_inappwebview: ^5.7.2 + flutter_secure_storage: ^8.0.0 + dio: ^5.0.0 + firebase_messaging: ^14.4.0 + flutter_local_notifications: ^13.0.0 + firebase_core: ^2.9.0 flutter_web_auth: ^0.5.0 - firebase_dynamic_links: ^5.0.0 - dio_cookie_manager: ^2.0.0 - google_fonts: ^3.0.1 + dio_cookie_manager: ^2.1.4 + google_fonts: ^4.0.0 fluttertoast: ^8.1.2 + cookie_jar: ^3.0.1 + flutter_dotenv: ^5.0.2 package_info: ^2.0.2 firebase_remote_config: ^3.0.14 launch_review: ^3.0.1 @@ -60,7 +60,6 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.0 - flutter_dotenv: ^5.0.2 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec