Tạo cầu (Bridge) giữa Javascript và Flutter cho một trải nghiệm liền mạch
Luận bàn về sử dụng WebView trong Mobile App
Nhờ có sự phát triển của các framework giúp xây dựng Web App như (React, Angular, Vue,…), kết hợp với sức mạnh ngày càng khủng của các thiết bị di động mà các lập trình viên ngày càng ưa thích việc sử dụng WebView (nhúng trang web lên app điện thoại).
Một ví dụ điển hình là ứng dụng Shopee, các bác có bao giờ thắc mắc tại sao các bác không cập nhật App mà ứng dụng lại có thể “biến hình” mỗi đợt khuyến mãi? Nhưng thật kì lạ rằng các bác vẫn sử dụng ứng dụng một cách liền mạch mà không hề có cảm giác đang vào trang Web đúng không?
Vì các ứng dụng này đã tạo rất nhiều cầu nối (Bridge) giữa Javascript và Native cực kì “điêu luyện”. Hôm nay cháu sẽ hướng dẫn cách tạo Bridge để điều hướng màn hình trên Flutter và tạo một trải nghiệm liền mạch giữa WebView và Native App
B1: Tạo Router
Bình thường nếu mới học Flutter, các bác sẽ hay viết kiểu:
Navigator.push(context, gì gì đó)
Tuy nhiên, về lâu dài cháu thấy cách viết này gây ra rất nhiều vấn đề về kiểm soát luồng sử dụng App và quan trọng là không tạo được Bridge để push màn hình.
Vì vậy, cháu khuyến khích mọi người tạo Router và sử dụng Navigator.pushNamed
để quản lý như thế này
router.dart
class YourAppRouter {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case YourAppRoutes.route1:
return MaterialPageRoute(builder: (_) => Route1Widget());
case YourAppRoutes.route2:
var routeParams = settings.arguments as String;
return MaterialPageRoute(
builder: (_) => Route2Widget(routeParams: routeParams));
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
appBar: AppBar(),
body: Center(
child: Text('Fallback')),
));
}
}
}
class YourAppRoutes {
static const String route1 = '/route1';
static const String route2 = '/route2';
}
và trong main.dart các bác config như sau:
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
onGenerateRoute: YourAppRouter.generateRoute,
initialRoute: YourAppRouter.route`,
....
);
}
}
B2: Tạo Bridge trong WebView
Giả sử các bác có một đoạn code của WebView
return WebView(
key: _key,
initialUrl: this.widget.url,
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
onPageStarted: (String url) {
setState(() {
isLoading = true;
});
},
);
giờ hãy thêm JavascriptChannel
javascriptChannels: Set.from([
JavascriptChannel(
name: 'PushScreen',
onMessageReceived: (JavascriptMessage message) {
print(message.message);
var pushScreenNotification =
PushScreenNotification.fromJson(
jsonDecode(message.message));
Navigator.pushNamed(
context, pushScreenNotification.screen,
arguments: pushScreenNotification.params);
}),
]),
WebView này sẽ lắng nghe liên tục tại kênh PushScreen
, để lấy message ta gọi message.message
trong Flutter
Tại phía Web, cháu sẽ tạo một object có dạng như sau
const screenNeedToPush = {
screen: '/route2',
params: '<PARAMS_HERE>`
}
và tại button nào đó cháu sẽ gọi
PushScreen.(screenNeedToPush);
mục đích là cháu muốn truyền 2 thứ: Màn hình cần push + Tham số cho màn hình này
B3: Kiểm nghiệm
Nhờ việc xây dựng Bridge như này, cháu có thể tạo một tính năng là Push màn hình tương ứng từ trang thông báo (có nhiều loại thông báo khác nhau)