Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Flutter Notes - Revised

Download as pdf or txt
Download as pdf or txt
You are on page 1of 53

1

Mobile Applications with Flutter (in Place of Advanced Java)


2

Table of Content
Chapter 1: Introduction ............................................................................................................... 4
Installation ................................................................................................................................... 4
Review of Dart Language ........................................................................................................... 4
Assert ....................................................................................................................................... 4
Final and const ......................................................................................................................... 5
Strings ...................................................................................................................................... 5
Lists ......................................................................................................................................... 6
Maps ........................................................................................................................................ 6
Functions ..................................................................................................................................... 7
Chapter 2: Control flow statements ............................................................................................ 9
If and else................................................................................................................................. 9
For loops .................................................................................................................................. 9
While and do-while ............................................................................................................... 10
Break and continue ................................................................................................................ 10
Switch and case ..................................................................................................................... 10
Asynchrony support .................................................................................................................. 12
Handling Futures ....................................................................................................................... 12
Test Drive .................................................................................................................................. 13
Use an external package ............................................................................................................ 13
Stateless and Stateful Widget .................................................................................................... 14
Example: Create an infinite scrolling ListView using ListViewBuilder .................................. 14
Navigation in Flutter ................................................................................................................. 15
Chapter 3: Widget Components ................................................................................................ 17
AppBar ...................................................................................................................................... 17
Drawer ....................................................................................................................................... 19
Images ....................................................................................................................................... 20
Specifying assets ....................................................................................................................... 20
Tabs ........................................................................................................................................... 21
BottomNavigationBar ............................................................................................................... 21
Column ...................................................................................................................................... 22
3

Row ........................................................................................................................................... 23
Container ................................................................................................................................... 23
RaisedButton ............................................................................................................................. 24
Card ........................................................................................................................................... 26
Alert Dialog ............................................................................................................................... 27
Bottom Sheets ........................................................................................................................... 27
ListView .................................................................................................................................... 28
Using Listview Builder .......................................................................................................... 28
Chapter 4: SQLite Database Connection ................................................................................. 30
SQLite ....................................................................................................................................... 30
Chapter 5: Accessing REST API ............................................................................................... 39
Basic Concepts .......................................................................................................................... 39
Accessing Product service API ................................................................................................. 40
Chapter 6: Deployment .............................................................................................................. 51
Android Application .................................................................................................................. 51
iOS Application ......................................................................................................................... 51
Assignment Project ..................................................................................................................... 53
4

Chapter 1: Introduction

Installation
1. Install Android Studio
2. Install flutter
 Extract the zip file and place the contained flutter in the desired installation location for the
Flutter SDK (for example, C:\src\flutter).
 Under User variables check if there is an entry called Path:
 If the entry exists, append the full path to flutter\bin using ; as a separator from
existing values.

 Run C:\src\flutter>flutter doctor

3. Install Visual Studio Code as your IDE


 Start VS Code.
 Invoke View > Command Palette….
 Type “install”, and select Extensions: Install Extensions.
 Type “flutter” in the extensions search field, select Flutter in the list, and click Install. This also
installs the required Dart plugin.
4. First Program

C:\Users\user>flutter create myapp

For Java C:\Users\user>flutter create -a java myapp

To check Licenses

flutter doctor –-android-licenses

Incase Flutter does not get SDK use

Flutter config --android-sdk <path>


C:\Users\USER>C:\Users\USER\AppData\Local\Android\Sdk\tools\bin\sdkmanager --install "cmdline-tools;latest"
Review of Dart Language
Variables

Examples

var name = 'Bob';


String name = 'Bob';

assert(lineCount == null);

Assert
5

During development, use an assert statement — assert(condition, optionalMessage); — to


disrupt normal execution if a boolean condition is false. You can find examples of assert statements
throughout this tour. Here are some more:

// Make sure the variable has a non-null value.


assert(text != null);

// Make sure the value is less than 100.


assert(number < 100);

// Make sure this is an https URL.


assert(urlString.startsWith('https'));

Final and const

If you never intend to change a variable, use final or const, either instead of var or in addition to a
type. A final variable can be set only once; a const variable is a compile-time constant. (Const
variables are implicitly final.) A final top-level or class variable is initialized the first time it’s used.

Note: Instance variables can be final but not const. Final instance variables must be initialized before
the constructor body starts — at the variable declaration, by a constructor parameter, or in the
constructor’s initializer list.
Here’s an example of creating and setting a final variable:

final name = 'Bob'; // Without a type annotation


final String nickname = 'Bobby';
You can’t change the value of a final variable:

name = 'Alice'; // Error: a final variable can only be set once.

Use const for variables that you want to be compile-time constants. If the const variable is at the
class level, mark it static const. Where you declare the variable, set the value to a compile-time
constant such as a number or string literal, a const variable, or the result of an arithmetic operation
on constant numbers:

const bar = 1000000; // Unit of pressure (dynes/cm2)


const double atm = 1.01325 * bar; // Standard atmosphere

Strings

A Dart string is a sequence of UTF-16 code units. You can use either single or double quotes to
create a string:

var s1 = 'Single quotes work well for string literals.';


var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";
6

You can put the value of an expression inside a string by using ${expression}. If the expression is
an identifier, you can skip the {}. To get the string corresponding to an object, Dart calls the
object’s toString() method.

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==


'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');

Lists

Perhaps the most common collection in nearly every programming language is the array, or ordered
group of objects. In Dart, arrays are List objects, so most people just call them lists.

Dart list literals look like JavaScript array literals. Here’s a simple Dart list:

var list = [1, 2, 3];


Note: Dart infers that list has type List<int>. If you try to add non-integer objects to this list,
the analyzer or runtime raises an error. For more information, read about type inference.
Lists use zero-based indexing, where 0 is the index of the first value and list.length - 1 is the
index of the last value. You can get a list’s length and refer to list values just as you would in
JavaScript:

var list = [1, 2, 3];


assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

Maps

In general, a map is an object that associates keys and values. Both keys and values can be any
type of object. Each key occurs only once, but you can use the same value multiple times. Dart
support for maps is provided by map literals and the Map type.

Here are a couple of simple Dart maps, created using map literals:

var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
7

var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};

var gifts = Map();


gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();


nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

Functions
Dart is a true object-oriented language, so even functions are objects and have a
type, Function. This means that functions can be assigned to variables or passed as arguments to
other functions. You can also call an instance of a Dart class as if it were a function. For details,
see Callable classes.

Here’s an example of implementing a function:

bool isNoble(int atomicNumber) {


return _nobleGases[atomicNumber] != null;
}
Although Effective Dart recommends type annotations for public APIs, the function still works if you
omit the types:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
For functions that contain just one expression, you can use a shorthand syntax:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

String say(String from, String msg, [String device]) {


var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
8
9

Chapter 2: Control flow statements


You can control the flow of your Dart code using any of the following:

 if and else
 for loops
 while and do-while loops
 break and continue
 switch and case
 assert

You can also affect the control flow using try-catch and throw, as explained in Exceptions.

If and else

Dart supports if statements with optional else statements, as the next sample shows. Also
see conditional expressions.

if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
Unlike JavaScript, conditions must use boolean values, nothing else. See Booleans for more
information.

For loops

You can iterate with the standard for loop. For example:

var message = StringBuffer('Dart is fun');


for (var i = 0; i < 5; i++) {
message.write('!');
}
Closures inside of Dart’s for loops capture the value of the index, avoiding a common pitfall found in
JavaScript. For example, consider:

var callbacks = [];


for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
The output is 0 and then 1, as expected. In contrast, the example would print 2 and then 2 in
JavaScript.

If the object that you are iterating over is an Iterable, you can use the forEach() method.
Using forEach() is a good option if you don’t need to know the current iteration counter:
10

candidates.forEach((candidate) => candidate.interview());


Iterable classes such as List and Set also support the for-in form of iteration:

var collection = [1, 2, 3];


for (var x in collection) {
print(x); // 1 2 3
}

While and do-while

A while loop evaluates the condition before the loop:

while (!isDone()) {
doSomething();
}
A do-while loop evaluates the condition after the loop:

do {
printLine();
} while (!atEndOfPage());

Break and continue

Use break to stop looping:

while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
Use continue to skip to the next loop iteration:

for (int i = 0; i < candidates.length; i++) {


var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
You might write that example differently if you’re using an Iterable such as a list or set:

candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());

Switch and case

Switch statements in Dart compare integer, string, or compile-time constants using ==. The
compared objects must all be instances of the same class (and not of any of its subtypes), and the
class must not override ==. Enumerated types work well in switch statements.
11

Note: Switch statements in Dart are intended for limited circumstances, such as in interpreters
or scanners.
Each non-empty case clause ends with a break statement, as a rule. Other valid ways to end a non-
empty case clause are a continue, throw, or return statement.

Use a default clause to execute code when no case clause matches:

var command = 'OPEN';


switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
The following example omits the break statement in a case clause, thus generating an error:

var command = 'OPEN';


switch (command) {
case 'OPEN':
executeOpen();
// ERROR: Missing break

case 'CLOSED':
executeClosed();
break;
}
However, Dart does support empty case clauses, allowing a form of fall-through:

var command = 'CLOSED';


switch (command) {
case 'CLOSED': // Empty case falls through.
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
If you really want fall-through, you can use a continue statement and a label:

var command = 'CLOSED';


switch (command) {
12

case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.

nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}

Asynchrony support
Dart libraries are full of functions that return Future or Stream objects. These functions
are asynchronous: they return after setting up a possibly time-consuming operation (such as I/O),
without waiting for that operation to complete.

The async and await keywords support asynchronous programming, letting you write asynchronous
code that looks similar to synchronous code.

Handling Futures
When you need the result of a completed Future, you have two options:

 Use async and await.


 Use the Future API, as described in the library tour.

Code that uses async and await is asynchronous, but it looks a lot like synchronous code. For
example, here’s some code that uses await to wait for the result of an asynchronous function:

await lookUpVersion();
To use await, code must be in an async function—a function marked as async:

Future checkVersion() async {


var version = await lookUpVersion();
// Do something with version
}
13

Test Drive
Replace the contents of lib/main.dart.
Delete all of the code from lib/main.dart. Replace with the following code, which displays “Hello
World” in the center of the screen.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}

Use an external package


2. The pubspec.yaml file manages the assets and dependencies for a Flutter app.

3. While viewing the pubspec.yaml file in Android Studio’s editor view, click Pub get.
This pulls the package into your project. You should see the following in the
console:

$ flutter pub get


Running "flutter pub get" in startup_namer...
Process finished with exit code 0
Performing Pub get also auto-generates the pubspec.lock file with a list of all
packages pulled into the project and their version numbers.
14

Stateless and Stateful Widget


Stateful widgets maintain state that might change during the lifetime of the widget.
Implementing a stateful widget requires at least two classes: 1) a StatefulWidget class that
creates an instance of 2) a State class. The StatefulWidget class is, itself, immutable and
can be thrown away and regenerated, but the State class persists over the lifetime of the
widget.

class RandomWords extends StatefulWidget {


@override
_RandomWordsState createState() => _RandomWordsState();
}

class _RandomWordsState extends State<RandomWords> {


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

Example: Create an infinite scrolling ListView using ListViewBuilder

Stateless Widget

A widget that does not require mutable state.

A stateless widget is a widget that describes part of the user interface by building a
constellation of other widgets that describe the user interface more concretely.
15

class Frog extends StatelessWidget {


const Frog({
Key key,
this.color = const Color(0xFF2DBD3A),
this.child,
}) : super(key: key);

final Color color;


final Widget child;

@override
Widget build(BuildContext context) {
return Container(color: color, child: child);
}
}

Navigation in Flutter
Navigate to a new screen and back

First, create two routes to work with. Since this is a basic example, each route contains
only a single button. Tapping the button on the first route navigates to the second route.
Tapping the button on the second route returns to the first route.

First, set up the visual structure:


16

Navigator.push() is used to go to the next page

onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}

To return back, Navigator.pop(context);

use onPressed: () {
Navigator.pop(context);
}
17

Chapter 3: Widget Components

AppBar
An app bar consists of a toolbar and potentially other widgets, such as a TabBar and a FlexibleSpaceBar.
App bars typically expose one or more common actions with IconButtons which are optionally followed
by a PopupMenuButton for less common operations (sometimes called the "overflow menu").
18
19

Drawer
In Flutter, use the Drawer widget in combination with a Scaffold to create a layout with a
Material Design drawer. This recipe uses the following steps:

1. Create a Scaffold.
2. Add a drawer.
3. Populate the drawer with items.
4. Close the drawer programmatically.

Scaffold(
drawer: Drawer(
child: ListView(
children: [
DrawerHeader(child: Text("Header"),decoration: BoxDecoration(color:
Colors.blue,),),
ListTile(
title: Text("Results"),
)
],
),
),
)
20

Images
Flutter apps can include both code and assets (sometimes called resources). An asset
is a file that is bundled and deployed with your app, and is accessible at runtime.
Common types of assets include static data (for example, JSON files), configuration
files, icons, and images (JPEG, WebP, GIF, animated WebP/GIF, PNG, BMP, and
WBMP).

Specifying assets
Flutter uses the pubspec.yaml file, located at the root of your project, to identify assets
required by an app.

Here is an example:

flutter:
assets:
- assets/images/

As a widget, use

Image.asset('assets/images/banner2.png'),

To use an image as an Asset, use

Var imgurl = AssetImage('assets/images/person.png');


Var imgurl = NetworkImage(‘http://person.png’);

To create an avatar use

CircleAvatar(
radius: 60,
backgroundColor: Colors.white,
child: CircleAvatar(
radius: 57.0,
backgroundImage: imgurl,
),
),

Or

CircleAvatar(
radius: 18,
child: ClipOval(
child: Image.network(
'image-url',
21

),
),
),

Tabs
The tabs are mainly used for mobile navigation. The styling of tabs is different for
different operating systems.

To add tabs to the app, we need to create a TabBar and TabBarView and attach them
with the TabController. The controller will sync both so that we can have the behavior
which we need.

Widget build(BuildContext context) {


return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
title: Text('University of Bosaso'),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
);
}

BottomNavigationBar
This is bottom navigation bar which returns a list of items at the bottom bar.

class _HomeState extends State<Home> {


int _currentIndex = 0;
22

final List<Widget> _children = [


Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.yellow)
];
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("UOB"),
),
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// this will be set when a new tab is tapped
onTap: onTabTapped, // new
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: new Icon(Icons.notifications),
label: 'Notifications',
),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile')
],
),
);
}
}

Column
A widget that displays its children in a vertical array.

To cause a child to expand to fill the available vertical space, wrap the child in an Expanded widget.

The Column widget does not scroll (and in general it is considered an error to have more children in a
Column than will fit in the available room). If you have a line of widgets and want them to be able to
scroll if there is insufficient room, consider using a ListView.
23

Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('We move under cover and we move as one'),
Text('Through the night, we have one shot to live another day'),
Text('We cannot let a stray gunshot give us away'),
Text('We will fight up close, seize the moment and stay in it'),
Text('It’s either that or meet the business end of a bayonet'),
Text('The code word is ‘Rochambeau,’ dig me?'),
Text('Rochambeau!', style:
DefaultTextStyle.of(context).style.apply(fontSizeFactor: 2.0)),
],
)

Row
A widget that displays its children in a horizontal array.

To cause a child to expand to fill the available horizontal space, wrap the child in an Expanded widget.

The Row widget does not scroll (and in general it is considered an error to have more children in a Row
than will fit in the available room). If you have a line of widgets and want them to be able to scroll if
there is insufficient room, consider using a ListView.

Row(
children: <Widget>[
Expanded(
child: Text('Deliver features faster', textAlign: TextAlign.center),
),
Expanded(
child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
),
Expanded(
child: FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: const FlutterLogo(),
),
),
],
)

Container
A convenience widget that combines common
painting, positioning, and sizing widgets.

Center(
child: Container(
margin: const EdgeInsets.all(10.0),
color: Colors.amber[600],
width: 48.0,
height: 48.0,
),
24

Example2

Container(
constraints: BoxConstraints.expand(
height: Theme.of(context).textTheme.headline4.fontSize * 1.1 + 200.0,
),
padding: const
EdgeInsets.all(8.0),
color: Colors.blue[600],
alignment: Alignment.center,
child: Text('Hello World',
style: Theme.of(context)
.textTheme
.headline4
.copyWith(color:
Colors.white)),
transform:
Matrix4.rotationZ(0.1),
)

RaisedButton
A material design "raised button".

A raised button is based on a Material widget whose


Material.elevation increases when the button is pressed.

Use raised buttons to add dimension to otherwise mostly flat


layouts, e.g. in long busy lists of content, or in wide spaces.
Avoid using raised buttons on already-raised content such as
dialogs or cards.

Widget build(BuildContext context) {


return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const RaisedButton(
onPressed: null,
child: Text(
'Disabled Button',
style: TextStyle(fontSize: 20)
25

),
),
const SizedBox(height: 30),
RaisedButton(
onPressed: () {},
child: const Text(
'Enabled Button',
style: TextStyle(fontSize: 20)
),
),
const SizedBox(height: 30),
RaisedButton(
onPressed: () {},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
padding: const EdgeInsets.all(10.0),
child: const Text(
'Gradient Button',
style: TextStyle(fontSize: 20)
),
),
),
],
),
);
}
26

Card
A card is a sheet used to represent the information related to each other, such as an
album, a geographical location, contact details, etc. A card in Flutter is in rounded
corner shape and has a shadow. We mainly used it to store the content and action
of a single object.

Card(
elevation: 2,
margin: EdgeInsets.all(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Beauty of Somalia'),
subtitle: Text('Somali kids were playing in a beautiful river..') ),
Image.network('http://i1.trekearth.com/photos/20045/somalia_somali_somalia.jpg'),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextButton(
child: const Text('Like'),
onPressed: () {/* ... */},),
const SizedBox(width: 8),
TextButton(
child: const Text('Visit'),
onPressed: () {/* ... */},),
const SizedBox(width: 8),
],
),
],
),
),
27

Alert Dialog
An alert dialog informs the user about situations that require
acknowledgement.

showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('AlertDialog’),
content: Text('This is a demo alert dialog.'),
),
},
);

Bottom Sheets
A modal bottom sheet is an alternative to a menu or a dialog and prevents the user from interacting
with the rest of the app.

Center(
child: ElevatedButton(
child: Text('Comment'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children:[
Text("Comment"),
TextField(
decoration: InputDecoration(
prefixIcon:Icon(Icons.photo_camera),
suffixIcon:Icon(Icons.send),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.teal)
)),
) ]
) );
},
);
},
), );
28

ListView
ListView is the most commonly used scrolling widget. It displays its children one after another in the
scroll direction. In the cross axis, the children are required to fill the ListView.

ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Container(
height: 50,
color: Colors.amber[600],
child: Center(child: Text('Entry A')),
),
Container(
height: 50,
color: Colors.amber[500],
child: Center(child: Text('Entry B')),
),
Container(
height: 50,
color: Colors.amber[100],
child: Center(child: Text('Entry C')),
),
],
)

Using Listview Builder

Example 1: Long List

ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
);
},
),

Example 2: List with Separator

final List<String> entries = <String>['A', 'B', 'C'];


final List<int> colorCodes = <int>[600, 500, 100];
ListView.separated(
padding: const EdgeInsets.all(8),
29

itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
);
30

Chapter 4: SQLite Database Connection

Flutter provides many advanced packages to work with databases. The most important
packages are −
 sqflite − Used to access and manipulate SQLite database, and

SQLite
SQLite database is the de-facto and standard SQL based embedded database engine.
It is small and time-tested database engine. sqflite package provides a lot of
functionality to work efficiently with SQLite database. It provides standard methods to
manipulate SQLite database engine. The core functionality provided by sqflite package
is as follows −
 Create / Open (openDatabase method) a SQLite database.
 Execute SQL statement (execute method) against SQLite database.
 Advanced query methods (query method) to reduce to code required to query
and get information from SQLite database.
Let us create a product application to store and fetch product information from a
standard SQLite database engine using sqflite package and understand the concept
behind the SQLite database and sqflite package.
 Create a new Flutter application in Android studio, product_sqlite_app.
 Replace the default startup code (main.dart) with our product_rest_app code.
 Copy the assets folder from product_nav_app to product_rest_app and add
assets inside the *pubspec.yaml` file.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
 Configure sqflite package in the pubspec.yaml file as shown below −
dependencies: sqflite: any
Use the latest version number of sqflite in place of any
 Configure path_provider package in the pubspec.yaml file as shown below −
dependencies: path_provider: any
31

 Here, path_provider package is used to get temporary folder path of the system
and path of the application. Use the latest version number of sqflite in place
of any.
 Android studio will alert that the pubspec.yaml is updated.
 Click Get dependencies option. Android studio will get the package from Internet
and properly configure it for the application.
 In database, we need primary key, id as additional field along with Product
properties like name, price, etc., So, add id property in the Product class. Also,
add a new method, toMap to convert product object into Map object. fromMap
and toMap are used to serialize and de- serialize the Product object and it is
used in database manipulation methods.
class Product {
final int id;
final String name;
final String description;
final int price;
final String image;
static final columns = ["id", "name", "description", "price",
"image"];
Product(this.id, this.name, this.description, this.price,
this.image);
factory Product.fromMap(Map<String, dynamic> data) {
return Product(
data['id'],
data['name'],
data['description'],
data['price'],
data['image'],
);
}
Map<String, dynamic> toMap() => {
"id": id,
"name": name,
"description": description,
"price": price,
"image": image
};
}
 Create a new file, Database.dart in the lib folder to write SQLite related
functionality.
 Import necessary import statement in Database.dart.
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
32

import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'Product.dart';
 Note the following points here −
o async is used to write asynchronous methods.
o io is used to access files and directories.
o path is used to access dart core utility function related to file paths.
o path_provider is used to get temporary and application path.
o sqflite is used to manipulate SQLite database.
 Create a new class SQLiteDbProvider
 Declare a singleton based, static SQLiteDbProvider object as specified below −
class SQLiteDbProvider {
SQLiteDbProvider._();
static final SQLiteDbProvider db = SQLiteDbProvider._();
static Database _database;
}
 SQLiteDBProvoider object and its method can be accessed through the static db
variable.
SQLiteDBProvoider.db.<emthod>
 Create a method to get database (Future option) of type Future<Database>.
Create product table and load initial data during the creation of the database
itself.
Future<Database> get database async {
if (_database != null)
return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await
getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ProductDB.db");
return await openDatabase(
path,
version: 1,
onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Product ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
33

"description TEXT,"
"price INTEGER,"
"image TEXT" ")"
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone is the stylist phone ever", 1000,
"iphone.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel is the most feature phone ever",
800, "pixel.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop is most productive development
tool", 2000, "laptop.png"]\
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop is most productive development
tool", 1500, "tablet.png"]
);
await db.execute(
"INSERT INTO Product
('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive is useful storage medium",
100, "pendrive.png"]
);
await db.execute(
"INSERT INTO Product
('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "Floppy drive is useful rescue
storage medium", 20, "floppy.png"]
);
}
);
}
34

 Here, we have used the following methods −


o getApplicationDocumentsDirectory − Returns application directory
path
o join − Used to create system specific path. We have used it to create
database path.
o openDatabase − Used to open a SQLite database
o onOpen − Used to write code while opening a database
o onCreate − Used to write code while a database is created for the first
time
o db.execute − Used to execute SQL queries. It accepts a query. If the
query has placeholder (?), then it accepts values as list in the second
argument.
 Write a method to get all products in the database −
Future<List<Product>> getAllProducts() async {
final db = await database;
List<Map>
results = await db.query("Product", columns: Product.columns,
orderBy: "id ASC");

List<Product> products = new List();


results.forEach((result) {
Product product = Product.fromMap(result);
products.add(product);
});
return products;
}
 Here, we have done the following −
o Used query method to fetch all the product information. query provides
shortcut to query a table information without writing the entire query.
query method will generate the proper query itself by using our input like
columns, orderBy, etc.,
o Used Product’s fromMap method to get product details by looping the
results object, which holds all the rows in the table.
 Write a method to get product specific to id
Future<Product> getProductById(int id) async {
final db = await database;
var result = await db.query("Product", where: "id = ",
whereArgs: [id]);
return result.isNotEmpty ? Product.fromMap(result.first) : Null;
}
35

 Here, we have used where and whereArgs to apply filters.


 Create three methods - insert, update and delete method to insert, update and
delete product from the database.
insert(Product product) async {
final db = await database;
var maxIdResult = await db.rawQuery(
"SELECT MAX(id)+1 as last_inserted_id FROM Product");

var id = maxIdResult.first["last_inserted_id"];
var result = await db.rawInsert(
"INSERT Into Product (id, name, description, price, image)"
" VALUES (?, ?, ?, ?, ?)",
[id, product.name, product.description, product.price,
product.image]
);
return result;
}
update(Product product) async {
final db = await database;
var result = await db.update("Product", product.toMap(),
where: "id = ?", whereArgs: [product.id]); return result;
}
delete(int id) async {
final db = await database;
db.delete("Product", where: "id = ?", whereArgs: [id]);
}
 The final code of the Database.dart is as follows −
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'Product.dart';

class SQLiteDbProvider {
SQLiteDbProvider._();
static final SQLiteDbProvider db = SQLiteDbProvider._();
static Database _database;

Future<Database> get database async {


if (_database != null)
return _database;
_database = await initDB();
return _database;
}
initDB() async {
36

Directory documentsDirectory = await


getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ProductDB.db");
return await openDatabase(
path, version: 1,
onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Product ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"description TEXT,"
"price INTEGER,"
"image TEXT"")"
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone is the stylist phone ever",
1000, "iphone.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel is the most feature phone ever",
800, "pixel.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop is most productive development
tool", 2000, "laptop.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop is most productive development
tool", 1500, "tablet.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive is useful storage medium",
100, "pendrive.png"]
37

);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description',
'price', 'image')
values (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "Floppy drive is useful rescue
storage medium", 20, "floppy.png"]
);
}
);
}
Future<List<Product>> getAllProducts() async {
final db = await database;
List<Map> results = await db.query(
"Product", columns: Product.columns, orderBy: "id ASC"
);
List<Product> products = new List();
results.forEach((result) {
Product product = Product.fromMap(result);
products.add(product);
});
return products;
}
Future<Product> getProductById(int id) async {
final db = await database;
var result = await db.query("Product", where: "id = ",
whereArgs: [id]);
return result.isNotEmpty ? Product.fromMap(result.first) :
Null;
}
insert(Product product) async {
final db = await database;
var maxIdResult = await db.rawQuery("SELECT MAX(id)+1 as
last_inserted_id FROM Product");
var id = maxIdResult.first["last_inserted_id"];
var result = await db.rawInsert(
"INSERT Into Product (id, name, description, price,
image)"
" VALUES (?, ?, ?, ?, ?)",
[id, product.name, product.description, product.price,
product.image]
);
return result;
}
update(Product product) async {
final db = await database;
var result = await db.update(
"Product", product.toMap(), where: "id = ?", whereArgs:
[product.id]
38

);
return result;
}
delete(int id) async {
final db = await database;
db.delete("Product", where: "id = ?", whereArgs: [id]);
}
}
 Change the main method to get the product information.
void main() {
runApp(MyApp(products: SQLiteDbProvider.db.getAllProducts()));
}
 Here, we have used the getAllProducts method to fetch all products from the
database.
 Run the application and see the results. It will be similar to previous
example, Accessing Product service API, except the product information is
stored and fetched from the local SQLite database.

Summary
Class _HomeState extends State<Home>{
initState(){
databaseinit() ;
super.initState();
}
databaseinit() async {
var directory = await getApplicationDocumentsDirectory();
String path = directory.path + "armo.db";
Database db = await openDatabase(path, version: 1,
onCreate: (Database mydb, int version) async {
await mydb.execute(
"CREATE TABLE IF NOT EXISTS students(id INTEGER PRIMARY KEY,name TEXT,marks INTEGER)");
});
await db.rawInsert("INSERT INTO students (name,marks) VALUES ('yusuf',40)");
print("Everything is OK");
var results = await db.rawQuery("select * from students");
print(results);
}
Widget build(){}
39

Chapter 5: Accessing REST API


Flutter provides http package to consume HTTP resources. http is a Future-based
library and uses await and async features. It provides many high level methods and
simplifies the development of REST based mobile applications.

Basic Concepts
http package provides a high level class and http to do web requests.
 http class provides functionality to perform all types of HTTP requests.
 http methods accept a url, and additional information through Dart Map (post
data, additional headers, etc.,). It requests the server and collects the response
back in async/await pattern. For example, the below code reads the data from
the specified url and print it in the console.
print(await http.read('https://flutter.dev/'));
Some of the core methods are as follows −
 read − Request the specified url through GET method and return back the
response as Future<String>
 get − Request the specified url through GET method and return back the
response as Future<Response>. Response is a class holding the response
information.
 post − Request the specified url through POST method by posting the supplied
data and return back the response as Future<Response>
 put − Request the specified url through PUT method and return back the
response as Future <Response>
 head − Request the specified url through HEAD method and return back the
response as Future<Response>
 delete − Request the specified url through DELETE method and return back the
response as Future<Response>
http also provides a more standard HTTP client class, client. client supports persistent
connection. It will be useful when a lot of request to be made to a particular server. It
needs to be closed properly using close method. Otherwise, it is similar to http class.
The sample code is as follows −
var client = new http.Client();
try {
print(await client.get('https://flutter.dev/'));
}
finally { Future createAlbum(String title) { return
client.close(); http.post( Uri.parse
} ('https://jsonplaceholder.typicode.com/album
s'), headers: String>{ 'Content-Type':
'application/json; charset=UTF-8', },
body: jsonEncode( String>{ 'title': title,
}), );}
40

Accessing Product service API


Let us create a simple application to get product data from a web server and then show
the products using ListView.
 Create a new Flutter application in Android studio, product_rest_app.
 Replace the default startup code (main.dart) with our product_nav_app code.
 Copy the assets folder from product_nav_app to product_rest_app and add
assets inside the pubspec.yaml file.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
 Configure http package in the pubspec.yaml file as shown below −
dependencies:
http: ^0.12.0+2
 Here, we will use the latest version of the http package. Android studio will send
a package alert that the pubspec.yaml is updated.
 Click Get dependencies option. Android studio will get the package from Internet
and properly configure it for the application.
 Import http package in the main.dart file −
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
 Create a new JSON file, products.json with product information as shown below

[
{
"name": "iPhone",
"description": "iPhone is the stylist phone ever",
"price": 1000,
"image": "iphone.png"
},
{
"name": "Pixel",
"description": "Pixel is the most feature phone ever",
"price": 800,
"image": "pixel.png"
41

},
{
"name": "Laptop",
"description": "Laptop is most productive development tool",
"price": 2000,
"image": "laptop.png"
},
{
"name": "Tablet",
"description": "Tablet is the most useful device ever for
meeting",
"price": 1500,
"image": "tablet.png"
},
{
"name": "Pendrive",
"description": "Pendrive is useful storage medium",
"price": 100,
"image": "pendrive.png"
},
{
"name": "Floppy Drive",
"description": "Floppy drive is useful rescue storage
medium",
"price": 20,
"image": "floppy.png"
}
]
 Create a new folder, JSONWebServer and place the JSON file, products.json.
 Run any web server with JSONWebServer as its root directory and get its web
path. For example, http://192.168.184.1:8000/products.json. We can use any
web server like apache, nginx etc.,
 The easiest way is to install node based http-server application. Follow the steps
given below to install and run http- server application
o Install Nodejs application (nodejs.org)
o Go to JSONWebServer folder.
cd /path/to/JSONWebServer
 Install http-server package using npm.
npm install -g http-server
 Now, run the server.
http-server . -p 8000

Starting up http-server, serving .


42

Available on:
http://192.168.99.1:8000
http://127.0.0.1:8000
Hit CTRL-C to stop the server
 Create a new file, Product.dart in the lib folder and move the Product class into
it.
 Write a factory constructor in the Product class, Product.fromMap to convert
mapped data Map into the Product object. Normally, JSON file will be converted
into Dart Map object and then, converted into relevant object (Product).
factory Product.fromJson(Map<String, dynamic> data) {
return Product(
data['name'],
data['description'],
data['price'],
data['image'],
);
}
 The complete code of the Product.dart is as follows −
class Product {
final String name;
final String description;
final int price;
final String image;

Product(this.name, this.description, this.price, this.image);


factory Product.fromMap(Map<String, dynamic> json) {
return Product(
json['name'],
json['description'],
json['price'],
json['image'],
);
}
}
 Write two methods − parseProducts and fetchProducts - in the main class to
fetch and load the product information from web server into the List<Product>
object.
List<Product> parseProducts(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String,
dynamic>>();
return parsed.map<Product>((json)
=>Product.fromJson(json)).toList();
}
Future<List<Product>> fetchProducts() async {
43

final response = await


http.get('http://192.168.1.2:8000/products.json');
if (response.statusCode == 200) {
return parseProducts(response.body);
} else {
throw Exception('Unable to fetch products from the REST
API');
}
}
 Note the following points here −
o Future is used to lazy load the product information. Lazy loading is a
concept to defer the execution of the code until it is necessary.
o http.get is used to fetch the data from the Internet.
o json.decode is used to decode the JSON data into the Dart Map object.
Once JSON data is decoded, it will be converted into List<Product> using
fromMap of the Product class.
o In MyApp class, add new member variable, products of type
Future<Product> and include it in constructor.
class MyApp extends StatelessWidget {
final Future<List<Product>> products;
MyApp({Key key, this.products}) : super(key: key);
...
 In MyHomePage class, add new member variable products of type
Future<Product> and include it in constructor. Also, remove items variable and
its relevant method, getProducts method call. Placing the products variable in
constructor. It will allow to fetch the products from Internet only once when the
application is first started.
class MyHomePage extends StatelessWidget {
final String title;
final Future<ListList<Product>> products;
MyHomePage({Key key, this.title, this.products}) : super(key:
key);
...
 Change the home option (MyHomePage) in the build method of MyApp widget to
accommodate above changes −
home: MyHomePage(title: 'Product Navigation demo home page',
products: products),
 Change the main function to include Future<Product> arguments −
void main() => runApp(MyApp(fetchProduct()));
 Create a new widget, ProductBoxList to build the product list in the home page.
44

class ProductBoxList extends StatelessWidget {


final List<Product> items;
ProductBoxList({Key key, this.items});

@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) =gt; ProductPage(item:
items[index]),
),
);
},
);
},
);
}
}
Note that we used the same concept used in Navigation application to list the product
except it is designed as a separate widget by passing products (object) of type
List<Product>.
 Finally, modify the MyHomePage widget’s build method to get the product
information using Future option instead of normal method call.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: Center(
child: FutureBuilder<List<Product>>(
future: products, builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData ? ProductBoxList(items:
snapshot.data)

// return the ListView widget :


Center(child: CircularProgressIndicator());
},
),
)
);
}
45

 Here note that we used FutureBuilder widget to render the widget. FutureBuilder
will try to fetch the data from it’s future property (of type Future<List<Product>>).
If future property returns data, it will render the widget using ProductBoxList,
otherwise throws an error.
 The complete code of the main.dart is as follows −
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'Product.dart';

void main() => runApp(MyApp(products: fetchProducts()));

List<Product> parseProducts(String responseBody) {


final parsed = json.decode(responseBody).cast<Map<String,
dynamic>>();
return parsed.map<Product>((json) =>
Product.fromMap(json)).toList();
}
Future<List<Product>> fetchProducts() async {
final response = await
http.get('http://192.168.1.2:8000/products.json');
if (response.statusCode == 200) {
return parseProducts(response.body);
} else {
throw Exception('Unable to fetch products from the REST
API');
}
}
class MyApp extends StatelessWidget {
final Future<List<Product>> products;
MyApp({Key key, this.products}) : super(key: key);

// This widget is the root of your application.


@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Product Navigation demo home
page', products: products),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
46

final Future<List<Product>> products;


MyHomePage({Key key, this.title, this.products}) : super(key:
key);

// final items = Product.getProducts();


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: Center(
child: FutureBuilder<List<Product>>(
future: products, builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData ? ProductBoxList(items:
snapshot.data)

// return the ListView widget :


Center(child: CircularProgressIndicator());
},
),
)
);
}
}
class ProductBoxList extends StatelessWidget {
final List<Product> items;
ProductBoxList({Key key, this.items});

@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return GestureDetector(
child: ProductBox(item: items[index]),
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => ProductPage(item:
items[index]),
),
);
},
);
},
);
}
}
class ProductPage extends StatelessWidget {
47

ProductPage({Key key, this.item}) : super(key: key);


final Product item;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(this.item.name),),
body: Center(
child: Container(
padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset("assets/appimages/" +
this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name, style:
TextStyle(fontWeight:
FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
),
),
);
}
}
class RatingBox extends StatefulWidget {
@override
_RatingBoxState createState() =>_RatingBoxState();
}
class _RatingBoxState extends State<RatingBox> {
int _rating = 0;
void _setRatingAsOne() {
setState(() {
_rating = 1;
48

});
}
void _setRatingAsTwo() {
setState(() {
_rating = 2;
});
}
void _setRatingAsThree() {
setState(() {
_rating = 3;
});
}
Widget build(BuildContext context) {
double _size = 20;
print(_rating);
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,

children: <Widget>[
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 1
? Icon(Icons.star, ize: _size,)
: Icon(Icons.star_border, size: _size,)
),
color: Colors.red[500], onPressed:
_setRatingAsOne, iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (
_rating >= 2
? Icon(Icons.star, size: _size,)
: Icon(Icons.star_border, size: _size, )
),
color: Colors.red[500],
onPressed: _setRatingAsTwo,
iconSize: _size,
),
),
Container(
padding: EdgeInsets.all(0),
child: IconButton(
49

icon: (
_rating >= 3 ?
Icon(Icons.star, size: _size,)
: Icon(Icons.star_border, size: _size,)
),
color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size,
),
),
],
);
}
}
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.item}) : super(key: key);
final Product item;

Widget build(BuildContext context) {


return Container(
padding: EdgeInsets.all(2), height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" +
this.item.image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.item.name,
style:TextStyle(fontWeight: FontWeight.bold)),
Text(this.item.description),
Text("Price: " +
this.item.price.toString()),
RatingBox(),
],
)
)
)
]
),
)
);
}
50

}
Finally run the application to see the result. It will be same as our Navigation example
except the data is from Internet instead of local, static data entered while coding the
application.
51

Chapter 6: Deployment

Android Application
 Change the application name using android:label entry in android manifest file.
Android app manifest file, AndroidManifest.xml is located in <app
dir>/android/app/src/main. It contains entire details about an android application.
We can set the application name using android:label entry.
 Change launcher icon using android:icon entry in manifest file.
 Sign the app using standard option as necessary.
 Enable Proguard and Obfuscation using standard option, if necessary.
 Create a release APK file by running below command −
cd /path/to/my/application
flutter build apk
 You can see an output as shown below −
Initializing gradle...
8.6s
Resolving dependencies...
19.9s
Calling mockable JAR artifact transform to create file:
/Users/.gradle/caches/transforms-1/files-1.1/android.jar/
c30932f130afbf3fd90c131ef9069a0b/android.jar with input
/Users/Library/Android/sdk/platforms/android-28/android.jar
Running Gradle task 'assembleRelease'...
Running Gradle task 'assembleRelease'...
Done
85.7s
Built build/app/outputs/apk/release/app-release.apk (4.8MB).
 Install the APK on a device using the following command −
flutter install
 Publish the application into Google Playstore by creating an appbundle and push
it into playstore using standard methods.
flutter build appbundle

iOS Application
 Register the iOS application in App Store Connect using standard method. Save
the =Bundle ID used while registering the application.
 Update Display name in the XCode project setting to set the application name.
 Update Bundle Identifier in the XCode project setting to set the bundle id, which
we used in step 1.
52

 Code sign as necessary using standard method.


 Add a new app icon as necessary using standard method.
 Generate IPA file using the following command −
flutter build ios
 Now, you can see the following output −
Building com.example.MyApp for device (ios-release)...
Automatically signing iOS for device deployment
using specified development team in Xcode project:
Running Xcode build... 23.5s
......................
 Test the application by pushing the application, IPA file into TestFlight using
standard method.
 Finally, push the application into App Store using standard method.
53

Assignment Project
Create a project with a backend server that is an ecommerce based restaurant platform and its data is
saved in an online database. It should have the capability of working even when the user is offline (This
means it should save all its transactions in SQLITE database before synchronizing). Use shimmer in
the splash screen

The interfaces should be like the ones below.

You might also like