Flutter - Other

Download files with Cloud Storage

Create a Reference

To download a file, first create a Cloud Storage reference to the file you want to download.


You can create a reference by appending child paths to the root of your Cloud Storage bucket, or you can create a reference from an existing gs:// or https:// URL referencing an object in Cloud Storage.

// Create a storage reference from our app
final storageRef = FirebaseStorage.instance.ref();

// Create a reference with an initial file path and name
final pathReference = storageRef.child("images/stars.jpg");

// Create a reference to a file from a Google Cloud Storage URI
final gsReference =
    FirebaseStorage.instance.refFromURL("gs://YOUR_BUCKET/images/stars.jpg");

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
final httpsReference = FirebaseStorage.instance.refFromURL(
    "https://firebasestorage.googleapis.com/b/YOUR_BUCKET/o/images%20stars.jpg");


Download in memory

Download the file to a UInt8List with the getData() method. This is the easiest way to download a file, but it must load the entire contents of your file into memory. If you request a file larger than your app's available memory, your app will crash. To protect against memory issues, getData() takes a maximum amount of bytes to download. Set the maximum size to something you know your app can handle, or use another download method.

final islandRef = storageRef.child("images/island.jpg");

try {
  const oneMegabyte = 1024 * 1024;
  final Uint8List? data = await islandRef.getData(oneMegabyte);
  // Data for "images/island.jpg" is returned, use this as needed.
} on FirebaseException catch (e) {
  // Handle any errors.
}


Download to a local file

The writeToFile() method downloads a file directly to a local device. Use this if your users want to have access to the file while offline or to share the file in a different app. writeToFile() returns a DownloadTask which you can use to manage your download and monitor the status of the download.

final islandRef = storageRef.child("images/island.jpg");

final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/images/island.jpg";
final file = File(filePath);

final downloadTask = islandRef.writeToFile(file);
downloadTask.snapshotEvents.listen((taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      // TODO: Handle this case.
      break;
    case TaskState.paused:
      // TODO: Handle this case.
      break;
    case TaskState.success:
      // TODO: Handle this case.
      break;
    case TaskState.canceled:
      // TODO: Handle this case.
      break;
    case TaskState.error:
      // TODO: Handle this case.
      break;
  }
});


Download Data via URL

If you already have download infrastructure based around URLs, or just want a URL to share, you can get the download URL for a file by calling the getDownloadURL() method on a Cloud Storage reference.

final imageUrl =
    await storageRef.child("users/me/profile.png").getDownloadURL();


Handle Errors

There are a number of reasons why errors may occur on download, including the file not existing, or the user not having permission to access the desired file. More information on errors can be found in the Handle Errors section of the docs.

final islandRef = storageRef.child("images/island.jpg");

final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/images/island.jpg";
final file = File(filePath);

final downloadTask = islandRef.writeToFile(file);
downloadTask.snapshotEvents.listen((taskSnapshot) {
  switch (taskSnapshot.state) {
    case TaskState.running:
      // TODO: Handle this case.
      break;
    case TaskState.paused:
      // TODO: Handle this case.
      break;
    case TaskState.success:
      // TODO: Handle this case.
      break;
    case TaskState.canceled:
      // TODO: Handle this case.
      break;
    case TaskState.error:
      // TODO: Handle this case.
      break;
  }
});

Easier Assets Management

Do

Image.asset(AppAssets.appLogo);


Don't

Image.asset("assets/images/app_logo.png");


Conclusions: Managing assets can be very hard. If you want to use an image several times in your app, you have to specify the path again. But there is a much easier solution for this. Create an App Assets class where all your app assets are stored. Now you can easily call your assets with AppAssets.appLogo.

Enable code obfuscation

Update your pubspec.yaml to enable obfuscation.


environment:
  sdk: ">=2.12.0 <3.0.0"

flutter:
  obfuscate: true
  split-debug-info: /path/to/debug-info

Entry name *** collided

Add android.useNewApkCreator=false to android\local.properties.

execution failed for task ':gradle:compilegroovy'. > bug!

Open android folder of your project and the gradle folder and then open gradle-wrapper.properties file you need to update distributionUrl in gradle-wrapper.properties file.


Your Project Old distributionUrl is


distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip


Just change the version of distributionUrl with new distributionUrl


distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip (copy this and replace with old distributionurl)


After paste the new distributionUrl in gradle-wrapper.properties file open terminal of your IDE type cd android and then paste this ./gradlew signingReport.


It take 10 to 15 minutes your error will solved and you can easily generate SHA1 key for your project.

File and Code Templates (Android Studio)

Open Settings -> File and Code Templates -> Create Template


Now apply the following setting in the template.

  • Add name of the template.
  • Set extension to dart
  • File name to ${NAME}


Stateless Widget

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")
#end

#set( $list = ${NAME.split("_")} )
#set( $className = "" )
#set( $item = "" )

#foreach( $item in $list )
    #set($str = ${item.substring(0,1).toUpperCase()} )
    #set($str2 = ${item.substring(1).toLowerCase()} )
    #set($className = "${className}${str}${str2}" )
 #end


import "package:flutter/material.dart";

class $className extends StatelessWidget {
  const $className({super.key});

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}


Stateful Widget

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")
#end

#set( $list = ${NAME.split("_")} )
#set( $className = "" )
#set( $item = "" )

#foreach( $item in $list )
    #set($str = ${item.substring(0,1).toUpperCase()} )
    #set($str2 = ${item.substring(1).toLowerCase()} )
    #set($className = "${className}${str}${str2}" )
 #end


import "package:flutter/material.dart";

class $className extends StatefulWidget {
  const $className({super.key});

  @override
  State<$className> createState() => _${className}State();
}

class _${className}State extends State<$className> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}


Empty Class

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")
#end

#set( $list = ${NAME.split("_")} )
#set( $className = "" )
#set( $item = "" )

#foreach( $item in $list )
    #set($str = ${item.substring(0,1).toUpperCase()} )
    #set($str2 = ${item.substring(1).toLowerCase()} )
    #set($className = "${className}${str}${str2}" )
 #end



class $className{
  
}

flutter doctor --android-licenses gives a java error

  1. Right-click on "This PC" or "My Computer" and select Properties.
  2. Click on Advanced system settings.
  3. Click on the Environment Variables button.
  4. Under System variables, click New.
  5. Enter SKIP_JDK_VERSION_CHECK as the variable name and true as the variable value.
  6. Click OK to close each dialog box.
  7. Restart your Command Prompt or PowerShell to apply the changes.


By following these steps, you can bypass the Java version check when running flutter doctor --android-licenses on Windows.

Flutter Log Extension

import 'dart:io';

enum LogLevel {
  debug("💬", "\x1B[37m"), // White
  info("ℹ️", "\x1B[36m"), // Cyan
  warning("⚠️", "\x1B[33m"), // Yellow
  error("❌", "\x1B[31m"); // Red

  final String emoji;
  final String colorCode;

  const LogLevel(this.emoji, this.colorCode);
}

extension LogExtension on Object {
  void log({
    String tag = "APP",
    LogLevel level = LogLevel.debug,
    bool enableColors = true,
    bool showCallerInfo = false,
  }) {
    final now = DateTime.now().toIso8601String();

    final color = (enableColors && _supportsAnsiColors) ? level.colorCode : '';
    final reset = (enableColors && _supportsAnsiColors) ? "\x1B[0m" : '';

    final callerInfo = showCallerInfo ? _getCallerInfo() : '';
    final callerSection = callerInfo.isNotEmpty ? " $callerInfo" : '';

    final message = "${level.emoji} [$tag:$callerSection] $now $this";
    debugPrint("$color$message$reset");
  }

  bool get _supportsAnsiColors =>
      !Platform.isWindows || stdout.supportsAnsiEscapes;

  String _getCallerInfo() {
    try {
      final line = StackTrace.current.toString().split("\n")[2].trim();
      final match = RegExp(r'\((.+?):(\d+):\d+\)$').firstMatch(line);
      if (match != null) {
        final file =
            match.group(1)?.split(Platform.pathSeparator).last ?? 'unknown';
        final lineNum = match.group(2) ?? '0';
        return "$file:$lineNum";
      }
    } catch (_) {}
    return '';
  }
}


If you want to change colors of logs you can follow this link for the ansi codes.


Usage

// Usage 
void main() {
  "Fetching user data...".log(
    tag: "USER",
    level: LogLevel.info,
    showCallerInfo: true,
  );
  "Missing token!".log(tag: "AUTH", level: LogLevel.warning);
  "Something exploded!".log(tag: "CORE", level: LogLevel.error);


Output

...

Flutter Terminal Commands

  1. flutter pub get - Get packages in a Flutter project.
  2. flutter create <app_name> - Create a new Flutter project.
  3. flutter analyze - Analyze the project's dart code.
  4. flutter clean - Delete the build/ and.dart tool/ directories.
  5. flutter devices - List all connected devices.
  6. flutter test - Run Flutter unit tests for the current project.
  7. flutter run - Run your Flutter app on an attached device.
  8. flutter build apk - Build an Android APK file from your app.
  9. flutter upgrade - Upgrade your copy of Flutter.
  10. flutter doctor - Show information about the installed tooling.

Folder Structure

Do

lib
--core
----services
------api_service.dart
----shared_widgets
------custom_textfield_widget.dart
----utils
------utils.dart
--features
----authentication
------screens
--------login_screen.dart
--------register_screen.dart
----home
------screens
--------home_screen.dart
------widgets
--------product_widget.dart
--main.dart


Don't

lib
--api_service.dart
--custom_textfield_widget.dart
--home_screen.dart
--login_screen.dart
--main.dart
--product_widget.dart
--register_screen.dart
--utils.dart


Conclusion: Making it easier to locate and organize files.

Note: If you use state management you can add it in every feature. Example: features/home/bloc.

Having trouble displaying splashes using an InkWell

Use an Ink widget ! The Ink widget draws on the same widget that InkWell does, so the splash appears.


class InkWellCard extends StatelessWidget(
  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 3.0,
      child: Ink(
        child: InkWell (
          onTap:() => print("Ordering..."),
          child: Text("Order Bageis'),
        )
      )
    );
  }
}

How to build signed apk from Android Studio ?

  1. Go Tools > Flutter > Open for Editing in Android Studio and select New Window option.
  2. Wait for while until project synchronization.
  3. Go to Build > Generate Signed Bundle/APK.
  4. Select Android App Bundle or APK option and click Next.
  5. Select Create new.. option to generate new Signed Key if you release your app first time.
  6. Fill all Options.
  7. Click OK then click Next.
  8. Build Variants.
  9. Wait for a while until Gradle Build Running process complete.


Options

Key store Path - Path where your key store file .jks file stored.
Key store password - Enter password. e.g. 123456
Key alias - Enter Key alias e.g. key
Key Password - Enter Key password (Choose different password than Key store password) e.g. 123456
Validity(years) - Keep it as it is or change as per your requirements.
Certificate - Fill certificate information (Not all fields are mandatory)


Variants

Android App Bundle

  1. Select release and click Finish.


APK -

  1. Select profile and checked V1 and V2.
  2. Click Finish.
  3. Repeat the step by select release after the profile apk generated.