Với một tính năng nhất định, có thể có nhiều package cho bạn lựa chọn. Làm sao để tìm đúng thư viện triển khai nhanh chóng và ít lỗi. Mình sẽ phân loại chúng dựa trên kinh nghiệm làm việc.
1. Trình xem PDF Flutter (Flutter PDF Viewer)
- Package: flutter_pdfview
Ưu điểm:
Xử lý được hyperlink
Nhược điểm:
Dung lượng APK quá lớn.
- Tham khảo: endigo/flutter_pdfview/issues/183
Thiết lập:
PDFView(
pageFling: false,
pageSnap: false,
filePath: _remotePDFpath,
onRender: (_) {
// Stop loading
},
// onError, onPageError (Chỉ Android)
// https://github.com/endigo/flutter_pdfview/blob/780a3d30e27c6a0610f9ad74630d6155fe4ee355/CHANGELOG.md#1005
onError: (error) {
debugPrint("onError ${error.toString()}");
_handleError();
},
onPageError: (page, error) {
debugPrint("onPageError ${error.toString()}");
_handleError();
},
preventLinkNavigation: true,
onLinkHandler: (uri) {
debugPrint("onLinkHandler $uri");
if (uri == null || uri.isEmpty) return;
launchUrl(Uri.parse(uri), mode: LaunchMode.platformDefault);
},
onViewCreated: (PDFViewController controller) {
if (Platform.isIOS) {
// Sửa lỗi: cuộn lên đầu lúc khởi tạo
Future.delayed(const Duration(milliseconds: 50), () {
controller.setPage(0);
});
}
},
autoSpacing: Platform.isIOS,
),Tải xuống tệp:
Future<File?> _createFileOfPdfUrl(String url) async {
try {
var res = await http.get(Uri.parse(url));
if (res.statusCode != 200 || res.body.startsWith("<?xml version=") || res.body.startsWith("<!DOCTYPE html")) {
throw Exception('statusCode ${res.statusCode}_${res.reasonPhrase}');
}
final filePath = await _getPdfFilePath;
File file = File(filePath);
await file.writeAsBytes(res.bodyBytes, flush: true);
return file;
} catch (e) {
debugPrint(e.toString());
return null;
}
}2. Flutter Webview
- Package: webview_flutter
Ưu điểm:
Thư viện webview chính thức của Flutter
Nhược điểm:
- Ít tính năng đặc thù cho từng nền tảng
- Không có chế độ singleton trong webview_flutter iOS
-
Tham khảo: flutter/issues/94591
-
Bản vá: guide-flutter/plugins/tree/webview_flutter_wkwebview
- Android setTextZoom, setMinimumFontSize
Thêm mã bên dưới vào pubspec.yaml để áp dụng bản vá:
dependency_overrides:
webview_flutter_android:
git:
url: https://github.com/guide-flutter/plugins.git
path: packages/webview_flutter/webview_flutter_android
ref: webview_flutter_android
webview_flutter_wkwebview:
git:
url: https://github.com/guide-flutter/plugins.git
path: packages/webview_flutter/webview_flutter_wkwebview
ref: webview_flutter_wkwebviewPhân tích cookie trong header phản hồi HTTP
- Tham khảo: how-to-handle-multiple-set-cookie-with-dart
String _getSetCookie(final Map<String, dynamic> headers) {
for (final key in headers.keys) {
if (key.toLowerCase() == 'set-cookie') {
return headers[key] as String;
}
}
return '';
}final _regexSplitSetCookies = RegExp(
r"""(?<!expires=\w{3}|"|')\s*,\s*(?!"|')""",
caseSensitive: false,
);
List<Cookie> fromCookiesString(String? cookiesString) {
final cookieList = cookiesString?.split(_regexSplitSetCookies) ?? [];
final List<Cookie> cookies = [];
for (var e in cookieList) {
try {
final cookie = Cookie.fromSetCookieValue(e);
cookie.domain ??= Constants.DomainUrl;
cookies.add(cookie);
debugPrint("__cookie ${cookie.name}:${cookie.secure}");
} catch (e) {
debugPrint(e.toString());
}
}
return cookies;
}Thiết lập cookie cho Webview
Cần sử dụng package bên thứ ba: webview_cookie_manager
Future<void> _syncCookies(List<Cookie> cookies) async {
final cookieManager = WebviewCookieManager();
if (Platform.isAndroid) {
await cookieManager.clearCookies();
final gCookieDomain = groupBy(cookies, (c) => c.domain);
for (var domain in gCookieDomain.keys) {
final cks = gCookieDomain[domain] ?? [];
final gCookieSecure = groupBy(cks, (c) => c.secure);
for (var isSecure in gCookieSecure.keys) {
final ckks = gCookieSecure[isSecure]?.toList() ?? [];
if (ckks.isNotEmpty) {
debugPrint("_______Cookie: ${ckks.toString()}");
await cookieManager.setCookies(ckks, origin: isSecure ? 'https://$domain' : null);
}
}
}
} else {
await cookieManager.setCookies(cookies);
}
}3. Phát hiện Jailbreak hoặc Root trong Flutter
- Package: flutter_jailbreak_detection
Bản vá đường dẫn:
flutter_jailbreak_detection:
git:
url: https://github.com/guide-flutter/flutter_jailbreak_detection.git4. Tự động tạo Icon cho ứng dụng Flutter
- Package: flutter_launcher_icons
Cấu hình yaml
# gen app icon
flutter_icons:
android: true
image_path_ios: "assets/icon/icon_ios.png"
image_path_android: "assets/icon/icon_android.png"
min_sdk_android: 23
adaptive_icon_background: "#ffffff"
adaptive_icon_foreground: "assets/icon/icon_adaptive_foreground.png"
ios: true
remove_alpha_ios: true5. Giao diện Flutter hiển thị hợp lý trên nhiều kích thước màn hình
- Package: flutter_screenutil
Cảnh báo: Không sử dụng ScreenUtilInit cho từng trang riêng lẻ, việc này sẽ gây lỗi nếu trang đó có ô nhập liệu text
import 'dart:ui' as ui;
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(375, 812 + MediaQueryData.fromWindow(ui.window).padding.bottom),
minTextAdapt: true,
builder: (BuildContext context, Widget? child) {
return MaterialApp.router(
builder: (context, child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0, boldText: false),
child: child ?? const SizedBox.shrink(),
);
},
);
},
);