My app is already live on the Play Store, but it takes almost 15-20 seconds to fully open and get to the home screen. I am using Firebase for backend with my flutter app. I have included step by step code that executes when my app starts.
main.dart
AndroidNotificationChannel channel = const AndroidNotificationChannel(
'high_importance_channel',
'High Importance Notifications',
description: 'This channel is used for high importance notifications',
importance: Importance.max,
playSound: true,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Firebase App
await Firebase.initializeApp();
// Activate Firebase App Check
await FirebaseAppCheck.instance.activate(
androidProvider: AndroidProvider.playIntegrity,
);
// Initialize Google Mobile Ads
await MobileAds.instance.initialize();
// Set preferred device orientation
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// Initialize Flutter Local Notifications Plugin
// FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
// Set foreground notification presentation options
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AppNavigationProvider(),
),
ChangeNotifierProvider(
create: (_) => SellerFormProvider(),
),
ChangeNotifierProvider(
create: (_) => LocationProvider(),
),
],
child: const MyApp(),
),
);
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
registerMessaging();
}
void registerMessaging() async {
await compute(_registerMessaging, null);
}
static Future<void> _registerMessaging(void _) async {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final RemoteNotification? notification = message.notification;
final AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
playSound: true,
importance: Importance.max,
priority: Priority.high,
color: greenColor,
icon: '@mipmap/ic_launcher',
),
),
);
}
});
}
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'App name',
color: blueColor,
themeMode: ThemeMode.light,
theme: ThemeData(fontFamily: 'Rubik'),
debugShowCheckedModeBanner: false,
home: const LoadingScreen(),
onUnknownRoute: (RouteSettings settings) {
return MaterialPageRoute(
settings: settings,
builder: (BuildContext context) => const ErrorScreen(),
);
},
);
}
}
loading_screen.dart
class LoadingScreen extends StatefulWidget {
const LoadingScreen({Key? key}) : super(key: key);
@override
State<LoadingScreen> createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
@override
void initState() {
super.initState();
//check whether user is logged in or not. Then navigate her accordingly.
FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user != null) {
Get.offAll(() => const MainScreen(selectedIndex: 0));
} else {
Get.offAll(() => const LandingScreen());
}
});
}
@override
Widget build(BuildContext context) {
return const Scaffold(
backgroundColor: whiteColor,
body: Center(
child: CustomLoadingIndicator(),
),
);
}
}
main_screen.dart
class MainScreen extends StatefulWidget {
final int selectedIndex;
const MainScreen({super.key, required this.selectedIndex});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
final FirebaseServices _services = FirebaseServices();
final User? user = FirebaseAuth.instance.currentUser;
late StreamSubscription<ConnectivityResult> subscription;
bool isDeviceConnected = false;
bool isAlertSet = false;
@override
void initState() {
super.initState();
getConnectivity();
}
showNetworkError() {
showModalBottomSheet(
context: context,
backgroundColor: transparentColor,
isDismissible: false,
enableDrag: false,
isScrollControlled: false,
builder: (context) {
return SafeArea(
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
color: whiteColor,
),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom + 15,
left: 15,
right: 15,
top: 15,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Center(
child: Text(
'Network Connection Lost',
style: GoogleFonts.interTight(
fontSize: 20,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
),
const SizedBox(
height: 15,
),
Image.asset(
'assets/no-network.png',
fit: BoxFit.contain,
semanticLabel: 'no network connection',
width: MediaQuery.of(context).size.width * 0.8,
height: MediaQuery.of(context).size.height * 0.2,
),
const SizedBox(
height: 15,
),
Container(
padding: const EdgeInsets.all(15),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: greyColor,
),
child: Text(
'Please check your internet connection',
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.interTight(
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(
height: 10,
),
CustomButtonWithoutIcon(
text: 'Re-Connect',
onPressed: () async {
Get.back();
setState(() {
isAlertSet = false;
});
isDeviceConnected =
await InternetConnectionChecker().hasConnection;
if (!isDeviceConnected) {
showNetworkError();
setState(() {
isAlertSet = true;
});
}
},
borderColor: redColor,
bgColor: redColor,
textIconColor: whiteColor,
),
],
),
),
);
},
);
}
Future<void> getConnectivity() async {
await for (final _ in Connectivity().onConnectivityChanged) {
isDeviceConnected = await InternetConnectionChecker().hasConnection;
if (!isDeviceConnected && !isAlertSet) {
showNetworkError();
setState(() => isAlertSet = true);
}
}
}
Future<void> onSellButtonClicked() async {
final userData = await _services.getCurrentUserData();
if (userData['location'] != null) {
Get.to(
() => const SellerCategoriesListScreen(),
);
} else {
Get.to(() => const LocationScreen(isOpenedFromSellButton: true));
showSnackBar(
content: 'Please set your location to sell products',
color: redColor,
);
}
}
@override
void dispose() {
subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer2<LocationProvider, AppNavigationProvider>(
builder: (context, locationProv, mainProv, child) {
final int selectedIndex = mainProv.currentPageIndex;
final List<Widget> pages = [
HomeScreen(
locationData: locationProv.locationData,
),
const MyChatsScreen(),
const MyFavoritesScreen(),
const MyProfileScreen(),
];
const List<IconData> iconsList = [
MdiIcons.homeOutline,
MdiIcons.chatOutline,
MdiIcons.heartOutline,
MdiIcons.accountCircleOutline,
];
const List<IconData> selectedIconsList = [
MdiIcons.home,
MdiIcons.chat,
MdiIcons.heart,
MdiIcons.accountCircle,
];
const List<String> titlesList = [
'Explore',
'Chats',
'Favorites',
'Account',
];
void onItemTapped(int index) {
mainProv.switchToPage(index);
}
void onFloatingActionButtonPressed() {
if (!user!.emailVerified &&
user!.providerData[0].providerId == 'password') {
Get.to(() => const EmailVerificationScreen());
} else {
onSellButtonClicked();
}
}
return Scaffold(
backgroundColor: whiteColor,
body: IndexedStack(
index: selectedIndex,
children: pages,
),
floatingActionButton: FloatingActionButton(
backgroundColor: blueColor,
elevation: 0,
tooltip: 'List a product',
enableFeedback: true,
onPressed: onFloatingActionButtonPressed,
child: const Center(
child: Icon(
MdiIcons.plus,
size: 35,
),
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
onTap: onItemTapped,
gapLocation: GapLocation.center,
activeIndex: selectedIndex,
backgroundColor: greyColor,
elevation: 5,
height: 55,
leftCornerRadius: 10,
rightCornerRadius: 10,
notchSmoothness: NotchSmoothness.defaultEdge,
splashColor: transparentColor,
itemCount: pages.length,
tabBuilder: (index, isActive) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
selectedIndex == index
? selectedIconsList[index]
: iconsList[index],
size: 24,
color: blackColor,
),
AutoSizeText(
titlesList[index],
maxLines: 1,
style: TextStyle(
fontSize: 12,
fontWeight: selectedIndex == index
? FontWeight.w600
: FontWeight.w500,
color: blackColor,
),
)
],
);
},
),
);
},
);
}
}
home_screen.dart
class HomeScreen extends StatefulWidget {
final LocationData? locationData;
const HomeScreen({
super.key,
this.locationData,
});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen>
with SingleTickerProviderStateMixin {
late TabController tabBarController;
final _services = FirebaseServices();
final User? user = FirebaseAuth.instance.currentUser;
String area = '';
String city = '';
String state = '';
bool isLocationEmpty = false;
bool isLoading = true;
late DateTime currentBackPressTime;
@override
void initState() {
super.initState();
tabBarController = TabController(
length: 3,
vsync: this,
);
_getCurrentUserData();
}
void _getCurrentUserData() async {
final value = await _services.getCurrentUserData();
if (value['location'] == null) {
_getEmptyLocationUI();
} else {
_getAddressToUI(value);
}
setState(() {
isLoading = false;
});
}
void _getAddressToUI(DocumentSnapshot<Object?> value) {
if (mounted) {
setState(() {
area = value['location']['area'];
city = value['location']['city'];
state = value['location']['state'];
});
}
}
_getEmptyLocationUI() {
if (mounted) {
setState(() {
isLocationEmpty = true;
tabBarController.index = 1;
});
}
}
@override
void dispose() {
tabBarController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: whiteColor,
body: AppBody(),
);
}
}
I have tried everything to my knowledge, but still the launch time isn't getting shortened. Reducing the time by just 5-10% would make a huge difference in user retention rate of my app.
Please help.
from How can I improve the launch time of my flutter firebase app?
No comments:
Post a Comment