Cách chạy Flutter trên Android/iOS/Web
Giới thiệu
Flutter là một framework phát triển ứng dụng đa nền tảng của Google, cho phép bạn xây dựng ứng dụng cho Android, iOS và Web từ một codebase duy nhất. Bài viết này sẽ hướng dẫn bạn cách cài đặt và chạy ứng dụng Flutter trên các nền tảng khác nhau.
Yêu cầu hệ thống
Windows
- Windows 7 SP1 trở lên (64-bit)
- Git for Windows
- Android Studio
- Visual Studio Code (khuyến nghị)
macOS
- macOS 10.14 trở lên
- Xcode (cho iOS)
- Android Studio
- Visual Studio Code (khuyến nghị)
Linux
- Ubuntu 18.04 trở lên
- Android Studio
- Visual Studio Code (khuyến nghị)
Cài đặt Flutter SDK
-
Tải Flutter SDK từ trang chủ Flutter: https://flutter.dev/docs/get-started/install
-
Giải nén file tải về vào thư mục mong muốn (ví dụ:
C:\src\flutter
trên Windows) -
Thêm đường dẫn Flutter vào biến môi trường PATH:
- Windows: Thêm
C:\src\flutter\bin
vào PATH - macOS/Linux: Thêm
export PATH="$PATH:
pwd/flutter/bin"
vào~/.bashrc
hoặc~/.zshrc
- Windows: Thêm
-
Kiểm tra cài đặt bằng lệnh:
flutter doctor
Cài đặt cho Android
-
Cài đặt Android Studio từ: https://developer.android.com/studio
-
Cài đặt Android SDK:
- Mở Android Studio
- Vào Tools > SDK Manager
- Chọn "SDK Platforms" và cài đặt Android SDK
- Chọn "SDK Tools" và cài đặt:
- Android SDK Build-Tools
- Android SDK Command-line Tools
- Android Emulator
- Android SDK Platform-Tools
-
Tạo máy ảo Android (AVD):
- Mở Android Studio
- Vào Tools > AVD Manager
- Click "Create Virtual Device"
- Chọn thiết bị và phiên bản Android
- Hoàn tất quá trình tạo AVD
-
Kiểm tra cài đặt:
flutter doctor --android-licenses
flutter doctor
Cài đặt cho iOS (chỉ macOS)
-
Cài đặt Xcode từ Mac App Store
-
Cài đặt các công cụ dòng lệnh:
xcode-select --install
- Chấp nhận giấy phép Xcode:
sudo xcodebuild -license accept
- Cài đặt CocoaPods:
sudo gem install cocoapods
- Kiểm tra cài đặt:
flutter doctor
Cài đặt cho Web
- Bật hỗ trợ web trong Flutter:
flutter config --enable-web
- Kiểm tra cài đặt:
flutter doctor
Tạo và chạy ứng dụng Flutter
Tạo ứng dụng mới
flutter create my_app
cd my_app
Chạy trên Android
-
Kết nối thiết bị Android:
- Bật chế độ Developer Options trên điện thoại
- Bật USB Debugging
- Kết nối điện thoại với máy tính qua USB
- Chấp nhận yêu cầu debug trên điện thoại
-
Kiểm tra thiết bị đã kết nối:
flutter devices
- Chạy ứng dụng:
flutter run
Khi chạy lệnh flutter run
, bạn sẽ thấy:
- Terminal hiển thị quá trình build và chạy ứng dụng
- Ứng dụng được cài đặt và chạy trên thiết bị Android
- Giao diện ứng dụng hiển thị với AppBar, nội dung và nút Floating Action Button
- Có thể sử dụng các phím tắt để tương tác với ứng dụng
Chạy trên iOS (chỉ macOS)
-
Mở Xcode và chấp nhận giấy phép
-
Kết nối thiết bị iOS hoặc khởi động máy ảo iOS
-
Chạy ứng dụng:
flutter run
Chạy trên Web
- Chạy ứng dụng:
flutter run -d chrome
Các lệnh hữu ích
Kiểm tra thiết bị đang kết nối
flutter devices
Chạy trên thiết bị cụ thể
flutter run -d <device-id>
Build ứng dụng
Android:
flutter build apk
iOS:
flutter build ios
Web:
flutter build web
Xử lý lỗi thường gặp
Lỗi Android SDK
- Kiểm tra biến môi trường ANDROID_HOME
- Cập nhật Android SDK Tools
- Chấp nhận giấy phép Android SDK
Lỗi iOS
- Cập nhật Xcode
- Chạy
pod install
trong thư mục ios - Kiểm tra quyền truy cập
Lỗi Web
- Xóa thư mục build:
flutter clean
- Cập nhật Flutter:
flutter upgrade
- Kiểm tra phiên bản Chrome
Kết luận
Flutter cung cấp một cách tiếp cận thống nhất để phát triển ứng dụng đa nền tảng. Với các hướng dẫn trên, bạn có thể bắt đầu phát triển ứng dụng Flutter cho Android, iOS và Web. Hãy nhớ luôn cập nhật Flutter SDK và các công cụ phát triển để có trải nghiệm tốt nhất.
Tài liệu tham khảo
Cấu hình IDE
Visual Studio Code
-
Cài đặt Flutter và Dart extensions:
- Mở VS Code
- Vào Extensions (Ctrl+Shift+X)
- Tìm và cài đặt:
- Flutter
- Dart
- Flutter Widget Snippets
- Awesome Flutter Snippets
-
Cấu hình VS Code:
- Format on Save: Bật tính năng tự động format code
- Flutter Hot Reload: Cấu hình phím tắt
- Flutter DevTools: Cài đặt công cụ debug
Android Studio
-
Cài đặt Flutter và Dart plugins:
- Mở Android Studio
- Vào File > Settings > Plugins
- Tìm và cài đặt:
- Flutter
- Dart
-
Cấu hình Android Studio:
- Flutter SDK Path: Chỉ định đường dẫn Flutter SDK
- Dart SDK Path: Tự động phát hiện
- Flutter Hot Reload: Cấu hình phím tắt
Cấu trúc dự án Flutter
my_app/
├── android/ # Mã nguồn Android
├── ios/ # Mã nguồn iOS
├── lib/ # Mã nguồn Dart chính
│ ├── main.dart # Điểm khởi đầu ứng dụng
│ ├── screens/ # Các màn hình
│ ├── widgets/ # Các widget tái sử dụng
│ ├── models/ # Các model dữ liệu
│ ├── services/ # Các service
│ └── utils/ # Các tiện ích
├── test/ # Unit tests và widget tests
├── web/ # Mã nguồn Web
└── pubspec.yaml # File cấu hình dự án
Quản lý dependencies
Thêm package mới
- Tìm package trên pub.dev
- Thêm vào
pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
http: ^1.1.0
provider: ^6.0.5
- Cài đặt dependencies:
flutter pub get
Cập nhật dependencies
flutter pub upgrade
Hot Reload và Hot Restart
Hot Reload
- Giữ nguyên state của ứng dụng
- Cập nhật UI và logic
- Phím tắt:
r
trong terminal hoặcCtrl+S
trong VS Code
Hot Restart
- Reset toàn bộ ứng dụng
- Mất state hiện tại
- Phím tắt:
R
trong terminal hoặcCtrl+Shift+S
trong VS Code
Debug và Testing
Debug
- Sử dụng
print
:
print('Debug message');
- Sử dụng
debugPrint
:
debugPrint('Debug message with timestamp');
- Sử dụng breakpoints trong IDE
Unit Testing
void main() {
test('Counter increments', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
Widget Testing
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});
}
Tối ưu hóa hiệu suất
Build Release
# Android
flutter build apk --release
# iOS
flutter build ios --release
# Web
flutter build web --release
Tối ưu hóa hình ảnh
- Sử dụng
Image.asset
vớicacheWidth
vàcacheHeight
- Nén hình ảnh trước khi sử dụng
- Sử dụng
const
cho các widget tĩnh
Tối ưu hóa memory
- Sử dụng
const
constructor - Tránh tạo widget không cần thiết
- Sử dụng
ListView.builder
thay vìListView
Triển khai ứng dụng
Android
- Tạo keystore:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
- Cấu hình
android/app/build.gradle
:
android {
signingConfigs {
release {
storeFile file("upload-keystore.jks")
storePassword "******"
keyAlias "upload"
keyPassword "******"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
- Build APK:
flutter build apk --release
iOS
-
Cấu hình Xcode:
- Chọn team development
- Cấu hình Bundle Identifier
- Cấu hình version và build number
-
Archive và upload:
- Product > Archive
- Distribute App
Web
- Build cho production:
flutter build web --release
- Triển khai lên hosting:
- Firebase Hosting
- GitHub Pages
- Netlify
- Vercel
Các công cụ hữu ích
Flutter DevTools
- Khởi động DevTools:
flutter run --debug
- Tính năng chính:
- Performance profiling
- Memory analysis
- Network inspection
- Widget inspector
Flutter Inspector
- Mở trong IDE
- Kiểm tra widget tree
- Debug layout issues
Flutter Performance
- Timeline view
- Frame rendering
- Memory usage
Best Practices
Code Style
- Tuân thủ Dart Style Guide
- Sử dụng
flutter format
để format code - Sử dụng
flutter analyze
để kiểm tra lỗi
Architecture
- Sử dụng BLoC hoặc Provider cho state management
- Tách biệt business logic và UI
- Sử dụng repository pattern
Performance
- Tránh rebuild không cần thiết
- Sử dụng
const
constructor - Tối ưu hóa hình ảnh và assets
Tài nguyên học tập
Documentation
Courses
Communities
Chạy và hiển thị kết quả trên Android
Tạo ứng dụng mẫu
- Tạo project mới:
flutter create my_first_app
cd my_first_app
- Mở file
lib/main.dart
và thay thế nội dung:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Bạn đã nhấn nút này nhiều lần:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Tăng',
child: const Icon(Icons.add),
),
);
}
}
### Chạy ứng dụng trên Android
1. Kết nối thiết bị Android:
- Bật chế độ Developer Options trên điện thoại
- Bật USB Debugging
- Kết nối điện thoại với máy tính qua USB
- Chấp nhận yêu cầu debug trên điện thoại
2. Kiểm tra thiết bị đã kết nối:
```bash
flutter devices
- Chạy ứng dụng:
flutter run
Các phím tắt khi chạy ứng dụng
r
: Hot reload (cập nhật UI mà không mất state)R
: Hot restart (khởi động lại ứng dụng)q
: Thoát ứng dụngp
: Hiển thị widget treeo
: Chuyển đổi giữa Android và iOSw
: Chuyển sang chế độ web
Debug trên thiết bị Android
- Sử dụng Flutter DevTools:
flutter run --debug
- Mở DevTools trong trình duyệt:
- Performance tab: Kiểm tra hiệu suất
- Memory tab: Kiểm tra bộ nhớ
- Network tab: Kiểm tra kết nối mạng
- Widget Inspector: Kiểm tra cấu trúc widget
Xử lý lỗi thường gặp trên Android
- Lỗi "Waiting for another flutter command to release the startup lock":
rm ~/flutter/bin/cache/lockfile
- Lỗi "Failed to install the following Android SDK packages":
flutter doctor --android-licenses
- Lỗi "Unable to find git in your PATH":
- Cài đặt Git
- Thêm Git vào PATH
Tối ưu hóa hiển thị trên Android
- Cấu hình AndroidManifest.xml:
<manifest ...>
<application
android:label="My First App"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
- Cấu hình styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
Tạo APK để cài đặt
- Build APK:
flutter build apk
- Cài đặt APK:
flutter install
hoặc tìm file APK tại:
build/app/outputs/flutter-apk/app-release.apk
Kiểm tra hiệu suất
- Sử dụng Flutter Performance:
flutter run --profile
- Kiểm tra các chỉ số:
- FPS (Frames per second)
- Memory usage
- CPU usage
- GPU usage
Tùy chỉnh giao diện Android
- Thay đổi theme:
MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
useMaterial3: true,
),
darkTheme: ThemeData(
brightness: Brightness.dark,
useMaterial3: true,
),
themeMode: ThemeMode.system,
// ...
)
- Tùy chỉnh status bar:
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
),
);
- Tùy chỉnh navigation bar:
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
),
);