Flutter 2.0 now officially support Web, below is some common situations when developing Flutter web and solutions:
Routing
- Use getx with named route
- Define route like this:
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(
name: '/',
page: () => MyHomePage(),
),
GetPage(
name: '/profile/',
page: () => Profiles(),
),
GetPage(
name: '/profile/user',
page: () => UserProfile.newInstance(),
)
],
)
- Then navigate like this:
Get.toNamed("/profile/user?name=quan&age=18");
- Then navigate like this:
Get.parameters['name']
- To safe to get param: create extension on Object like below:
extension CastTypeObjectExtension on Object {
int get castToInt {
if (this is int) {
return this;
}
return null;
}
double get castToDouble {
if (this is double) {
return this;
}
return null;
}
String get castToString {
if (this is String) {
return this;
}
return null;
}
bool get castToBool {
if (this is bool) {
return this;
}
return null;
}
}
- Usage
String name = Get.parameters['name'].castToString
Provider and Param when navigate
- Create a factory for widget to get param as well as pass provider
class UserProfile extends StatefulWidget {
static Widget newInstance() {
//pass provider here
//get param from path here
return BlocProvider(
create: (context) {
return UserBloc();
},
child: UserProfile._(
name: Get.parameters['name'].castToString,
age: Get.parameters['age'].castToString,
));
}
final String name;
final String age;
UserProfile._({this.name, this.age});
@override
_UserProfileState createState() => _UserProfileState();
}
Cache libs: get_storage, or hive
- init
void main() async { await GetStorage.init(); ... }
- get
currentCounter = GetStorage().read<int>('counter') ?? 0;
- set
GetStorage().write('counter', currentCounter);
HTML renderer and CanvasKit renderer
- More info
- HTML renderer: smaller download size, suitable for mobile
flutter build web --web-renderer html
- CanvasKit renderer: larger download size (+2MB), but faster performance, suitable for desktop
flutter build web --web-renderer canvaskit
- Suggest to choose the auto option (default) if you are optimizing for download size on mobile browsers and optimizing for performance on desktop browsers.
flutter build web --web-renderer auto
Cookie, session
- Local storage is enough to save data
- Cookie will be automatically managed by browser
- Use Dio package with option withCredential = true to send cookie in the request
Responsive
- Awesome package: responsive_builder
- Some useful features:
// return appropriate widgets base on screen type
ScreenTypeLayout.builder(
mobile: (BuildContext context) => Container(color:Colors.blue),
tablet: (BuildContext context) => Container(color:Colors.yellow),
desktop: (BuildContext context) => Container(color:Colors.red),
watch: (BuildContext context) => Container(color:Colors.purple),
);// return appropriate value base on screen type
getValueForScreenType<double>(
context: context,
mobile: 10,
tablet: 30,
desktop: 60,
)// Return a widget function per orientation
OrientationLayoutBuilder(
portrait: (context) => Container(color: Colors.green),
landscape: (context) => Container(color: Colors.pink),
),
Permission
- Use html.window.navigator.permissions.query
final perm = await html.window.navigator.permissions.query({"name": "camera"});
if (perm.state == "denied") {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Oops! Camera access denied!"),
backgroundColor: Colors.orangeAccent,
));
return;
}
final stream = await html.window.navigator.getUserMedia(video: true);
Select, drag file to upload
- Select file: file_picker
var picked = await FilePicker.platform.pickFiles();if (picked != null) {
print(picked.files.first.name);
}
- Drop file to upload: flutter_dropzone
Widget buildZone1(BuildContext context) => Builder(
builder: (context) => DropzoneView(
operation: DragOperation.copy,
cursor: CursorType.grab,
onHover: () {
setState(() => highlighted1 = true);
print('Zone 1 hovered');
},
onLeave: () {
setState(() => highlighted1 = false);
print('Zone 1 left');
},
onDrop: (file) {
setState(() {
message1 = '${file.name} dropped';
highlighted1 = false;
});
},
),
);
Embed JS code, communicate between dart and js
- Create a file app.js under web folder with this content
function alertMessage(text) {
alert(text)
return 'from js with love';
}
- Modify the index.html file under web folder
<head>
<script src="app.js" defer></script>
...
- In dart side
import 'dart:js' as js;final value = js.context.callMethod('alertMessage', ['From flutter with love']);
print("result is $value"); //will print 'result is from js with love'
SEO
- As Flutter render on the canvas instead of using html tags, so currently Flutter is not SEO-friendly