Android

Sử dụng Flutter để lập trình xuyên nền tảng cho Android và iOS

Tại Google I/O 2017, Google chính thức giới thiệu Flutter, một framework chính chủ từ chính Google, giúp các lập trình viên chuyên về di động có thể phát triển đồng thời cả hai phiên bản ứng dụng di động cho Android và iOS chỉ với một project duy nhất, nói cách khác là lập trình xuyên nền tảng. Thực tế Flutter không phải là framework đầu tiên hỗ trợ bạn làm việc này. Cái tên “sừng sỏ” nhất có thể nhắc tới là React Native, một framework của Facebook, ngoài ra chúng ta còn có những cái tên khác như Ionic hay PhoneGap, nhưng nhìn chung, bạn chỉ nên tiếp cận với React Native và giờ là Flutter nữa vì hiệu năng của chúng là rất cao, bởi chúng sử dụng native engine chứ không phải là nhồi nhét và render các HTML elements trong WebView.

Flutter

Tại Google I/O 2018, Google ra sức nâng tầm Flutter với những cải tiến vô cùng đáng giá nhằm đưa Flutter trở thành một thế lực cạnh tranh sòng phẳng với React Native. Và quả thật, những cải tiến này làm thay đổi quan điểm của tôi đến mức từ chỗ cho rằng “Đã có React Native, sao lại cần Flutter làm gì” mà thành “Đúng là Flutter cũng hay thật”. Sau một thời gian tìm hiểu, EITGUIDE trân trọng giới thiệu loạt bài hướng dẫn lập trình với Flutter. Nhưng trước hết, chúng ta cần điểm qua những thế mạnh cũng như những điểm chưa tốt của framework chính thức của Google này.

1. Google đã có Android SDK, sao lại ra mắt thêm Flutter?

Đây có lẽ là câu hỏi đầu tiên xuất hiện trong suy nghĩ của bạn. Đúng vậy. Từ thuở ban sơ của Android tới giờ, bạn học lập trình Android là bạn sẽ sử dụng Android SDK để viết ứng dụng, trước nhất là phải có bộ “ếch đi cày” này trước cái đã, rồi dùng trực tiếp nó qua Android Studio hay Eclipse, hay gián tiếp nó qua React Native, và giờ có thêm Flutter nữa. Vậy, Google đã sinh ra Android SDK, sao lại còn sinh ra thêm Flutter để làm gì? Flutter có giẫm lên chân của Android SDK hay không? Và tương lai của Android SDK sẽ đi về đâu? Liệu rằng Flutter có hoàn toàn thay thế Android SDK không? “Em mới có hứng thú với việc phát triển ứng dụng cho Android, vậy em có nên vào Flutter ngay hay phải học Android SDK trước?”. Rất nhiều câu hỏi sẽ “mọc ra” trong bạn khi nghe tới tên F*beep* này. Tôi sẽ giải đáp ngay sau đây.

  • Google đã sinh ra Android SDK, sao lại còn sinh ra thêm Flutter để làm gì? Thực tế, cách tiếp cận của Flutter hoàn toàn khác biệt so với Android (và iOS) SDK. Nhìn chung, tương tự như React Native, Flutter chỉ nằm ở “bề mặt” của tảng băng. Tức là bạn chỉ có thể dùng Flutter để viết ứng dụng ít sử dụng các tác vụ của hệ thống, mà chủ yếu là chỉ nặng về phần giao diện, tương tác với “sẹc vơ” gồm gửi request và nhận response. Chẳng hạn, ứng dụng về mạng xã hội, về bán hàng, v.v… Còn đối với những ứng dụng đào sâu vào hệ thống như quản lí tin nhắn, cuộc gọi, chỉnh sửa ảnh trực tiếp bằng ứng dụng, thì đó vẫn là đất diễn độc quyền của Android SDK. Do đó, câu trả lời cho Flutter có giẫm lên chân của Android SDK hay không? là một chữ KHÔNG to đùng. Mặt khác, bạn có thẻ truy cập vào APIs của hệ thống Android và iOS từ Flutter thông qua Android SDK và iOS SDK, và bạn thường phải code nó trong phần code riêng cho nền tảng đích – phần này tôi sẽ nói sau – nên Android SDK sẽ vẫn mãi còn đó, vẫn được phát triển đều đặn như thường, và nó không ảnh hưởng đến Flutter cũng như Flutter cũng không ảnh hưởng gì tới nó.
  • “Em mới có hứng thú với việc phát triển ứng dụng cho Android, vậy em có nên vào Flutter ngay hay phải học Android SDK trước?” Tốt nhất, bạn vẫn nên học về Android SDK với Java hay Kotlin, cũng như iOS với Swift trước, vì sau này, lỡ như bạn phải gọi APIs của hệ thống thì còn biết đường mà lần. Bởi như tôi đã nói ở bên trên, Flutter chỉ chuyên về phần giao diện tương tác là nhiều. Thực tế, dù bạn viết ứng dụng thuần về giao tiếp mạng, như app bán hàng hay mạng xã hội, nhưng đôi lúc sẽ phát sinh những vấn đề cần platform APIs, chẳng hạn như thông báo. Dẫu React Native hay Flutter có hỗ trợ bạn gửi thông báo ra trung tâm thông báo của hệ thống, song, chúng chỉ hỗ trợ những cái chung, đơn giản nhất, nhằm mục đích đảm bảo tính tương thích với hệ thống đích. Để có thể tối ưu thông báo trên nền tảng đích, mà cụ thể hơn là Android vốn hỗ trợ nhiều tính năng hơn so với iOS như Quick actions, Bundled notification thì bạn sẽ cần tới Android APIs.

Tóm lại, Flutter chỉ là một giải pháp để bạn viết một ứng dụng, trước tiên luôn có tính chất “mì ăn liền”, chạy ngay trên Android và iOS chỉ với một project duy nhất mà không cần động chạm tới native platform APIs. Bản chất nó hiện không, và chính Google cũng không muốn, nó hoàn toàn thay thế cho Android và iOS SDK. Flutter và Android SDK trên đà phát triển, dẫu có va chạm nhau một phần dư lào – dù Flutter giao với Android SDK nhiều hơn – song chúng vẫn là những “thế lực” có đường hướng phát triển riêng biệt.

2. Những điểm mạnh của Flutter.

Bạn có thể thấy ngay mà không cần tôi lặp lại, là Flutter kết xuất được ứng dụng cho đồng thời Android và iOS chỉ với một project duy nhất. Do đó, bạn chỉ code một “phát” một mà thôi, không cần phải build riêng phiên bản cho Android và phiên bản riêng cho iOS, để khi cập nhật thì phải thay đổi cả hai, cũng như tốn kém thời gian duy trì cả hai và có thể dẫn tới việc không đồng đều, nghĩa là phiên bản trên iOS có những tính năng mới sớm hơn, và ổn định hơn trên Android, hay phiên bản trên Android làm được nhiều việc hơn phiên bản trên iOS.

Một điểm mạnh khác là hiệu năng. Thực tế, ứng dụng Flutter được render với bộ engine được build trực tiếp vào ứng dụng của bạn dưới dạng mã máy nên cho hiệu năng khá cao. Bộ engine này được tối ưu hóa sẵn, nên bạn chỉ đơn giản là làm những gì bạn cần, còn những thứ mang tính nền, “background” đã được lo sẵn. Với những hiệu ứng được Flutter cung cấp sẵn, việc chúng được render dưới tốc độ 60fps là điều không có gì bất ngờ – một điều mà các coder sử dụng Android và iOS SDKs có thể phải tự tối ưu hóa “bằng tay” với trình độ và kinh nghiệm cao cường võ nghệ mới có thể đạt được, đặc biệt là trên Android vốn có sự đa dạng về GPUs và kernel không được tối ưu sẵn như iPhone và iPad.

Nhưng không thể không kể tới việc các concepts về Services hầu như là không cần thiết với Flutter. Bạn chỉ cần đặt (các) methods là async thì chúng sẽ được thực hiện dưới nền, và do đó bạn không cần viết ứng dụng theo hướng “dùng Service để cập nhật giao diện trên Activity” trên Android, vì code trên Flutter nặng về phần giao diện. Và cũng lại là Android, khi bạn không cần thiết phải xử lí các thao tác với Bundle savedInstanceState bằng tay khi xảy ra các tình huống như người dùng đột ngột xoay màn hình. Với Flutter, mọi thứ sẽ tự được giữ “y chang” như trước và bạn không cần làm gì. Do đó, có thể nói Flutter giải quyết được khá nhiều vấn đề với Android phát sinh với Android SDKs gây nên những hoang mang nhất định cho bạn.

Thực tế, Dart không phải là một ngôn ngữ dễ tiếp cận như Java hay Swift, nhưng nó cũng có một số điểm mạnh riêng và nhờ vào đó, Flutter cũng tận dụng được những điểm mạnh đó. Chẳng hạn, việc tạo lập constructor trong các Dart class dễ dàng hơn so với Java nhiều, dù vẫn có những phiền phức lớn hơn Java. Song, nếu quen thuộc với Dart rồi thì bạn vẫn chấp nhận “hi sinh” những thói quen cố hữu với Java mà chấp nhận làm việc với Dart.

3. Những điểm yếu và gây ức chế của Flutter.

Phàm là Flutter tốt đấy, ngon đấy, nhưng những ức chế mà nó mang lại sẽ gây khó dễ cho bạn và đối với những bạn đã quá quen thuộc với hướng tư duy với Java/Android hay Swift/iOS thì bạn có xu hướng bỏ ngay và luôn, dù họ vẫn code React Native như chẻ tre dẫu cho Flutter có hơi hướng tương đồng cao với bộ framework của Facebook. Dưới đây, tôi xin liệt kê một số ức chế mà bản thân tôi đã gặp phải, nếu bạn muốn “add thêm một item nào”, xin để lại còm mèn bên dưới.

Đầu tiên, có thể nói là bạn phải học một ngôn ngữ mới là Dart. Và thực tế, bạn hầu như chỉ dùng Dart để viết Flutter mà thôi, trong khi bạn học JavaScript và JSX cho React Native và cả làm Web nữa. Tất nhiên, bạn vẫn có thể dùng Dart để làm Web và build ứng dụng cho máy tính, nhưng cá nhân tôi nhận thấy việc dùng Dart để làm Web chỉ phổ biến ở nội bộ Google LLC mà thôi, còn đối với các công ty ngoài họ ra, cũng như các bạn, thì hầu như chưa thấy ai viết Web bằng Dart cả. Bản thân Dart có những điểm hay nhất định, song nó không dễ tiếp cận như Java hay Swift và có thể làm bạn cảm thấy “kì cục”, khó nuốt.

Kế tiếp là việc dựng giao diện, và điểm này khiến tôi ức chế nhất. Đối với Android và iOS, mọi thành phần giao diện đều được extends từ Android View hay iOS UIView và bản thân Android View hay UIView có rất nhiều những properties và methods quan trọng, và quan trọng nhất là margin, padding cũng như các constraints và gravity. Do vậy, việc bạn căng lề, cân chỉnh vị trí của các Android Views hay iOS UIViews, hay ReactNative Views là điều dễ như trở bàn tay. Còn với Flutter widgets, mọi thứ không như vậy, và thực chất là khá khó để làm quen. Bạn muốn tạo margin và padding cho một Flutter Widget, bạn phải đặt nó trong một Padding widget. Chẳng hạn, dưới đây tôi sẽ đưa ra một ví dụ cực kì đơn giản như sau trên Android và bên dưới là Flutter:

Rõ ràng là bạn thấy được một phần ức chế, khi tại sao ta không đánh thẳng tham số margin và padding trên Text widget kia mà phải “thuê” tên Padding kia vào làm gì cho… chật đất. Hơn nữa, phần padding như bạn thấy lại là một instance của một class tên là EdgeInsects chứ không trực tiếp bằng số được. Ngoài ra, các tham số như textColor, fontSize hay fontWeight lại phải được cho vào một instance của một tên TextStyle thay vì trực tiếp dùng trên Text widget kia cho rồi? Đơn giản là vì Google thích thế đấy. Chúng ta không còn thấy một Google thân thiện nữa, mà The Big G hiện tại có sở thích đánh đố chúng ta cho xoắn não như vậy. Đấy, may là như vậy thôi mà còn phiền, tới khi bạn phải bọc một Widget trong nhiều Widget như Center, Expanded, v.v…, để định vị trí cho nó nữa là sẽ có cảm giác “dẹp ngay và dẹp luôn”, tôi chắc là như vậy.

Nhưng đó cũng chưa phải là hết. Đối với Android và iOS, bạn sẽ thao tác trực tiếp trên View hay UIView. Chẳng hạn, khi bạn cho click một (UI)Button để thay đổi phần được hiển thị trên (UI)TextView thì bạn chỉ cần “nắm lấy tên (UI)TextView này ra” để gán text mới cho nó mà thôi, thông qua hành động click của (UI)Button. Còn đối với Flutter thì, èo… Bạn không tài nào lấy cái Text(“Hello world”) ra được đâu, mà dẫu có lấy ra được thì nó cũng không có method nào để setText hay prop data của nó, tức là phần text kia, là immutable, tức readOnly mà thôi. What the Flutter? Vậy làm sao thay text cho nó được?

Nếu bạn đã quen thuộc với React và React Native thì có thể bạn sẽ bật lên câu “setState chứ cây lúa gì” và với Flutter thì bạn cũng có một method setState. Bạn chỉ cần đặt data, tức phần text của Flutter Text(data) là một biến, và khi button nhận click thì sẽ setState và thay giá trị của tên data kia mà thôi. Khoan đã, setState giống React và React Native à? Vâng, chuẩn thằng Chính con ông Xác rồi. Hóa ra Flutter “đạo” của React và React Native à? E hèm, Google không có chối đâu bạn à. Thực chất, họ còn chưa chi đã “khai thiệt” với chúng ta như sau:

Does Flutter come with a framework?
Yes! Flutter ships with a modern framework, inspired by React (https://reactjs.org/). Flutter’s framework is designed to be layered and customizable (and optional). Developers can choose to use only parts of the framework, or a different framework.

Nhưng cũng không phải việc sử dụng State như vậy là không có lí đâu. Có những điểm mà bạn sẽ thấy dùng state hay hơn việc thao tác trực tiếp trên widget. Chẳng hạn như trên Android, bạn có một ListView chứa các items. Để hiển thị items đó ra trên ListView, bạn sẽ cần một <Adapter extends AdapterView> – và bạn sẽ thao tác với tên Adapter này chứ không phải ListView đâu! Khi bạn thêm một item vào Adapter, bạn sẽ phải gọi Adapter#notifyDataSetChanged và ngoài ra bạn còn phải đảm bảo mớ items sẽ được bảo toàn với Bundle savedInstanceState nữa. Khá nhiêu khê đúng không? Nhưng với Flutter, bạn chỉ cần thêm item mới vào items trong nội dung của setState, sau khi đã liên kết items vào Flutter ListView Widget – trực tiếp luôn chứ không qua Adapter nào cả bạn ơi – thì ListView nó tự cập nhật cho bạn. Phần nào, chứ phần này thì code của Flutter vừa dễ dàng lại vừa nhẹ nhàng hơn so với Android SDK.

Như vậy, có thể nói bạn sẽ thay đổi hoàn toàn các tư duy khi viết ứng dụng bằng Flutter. Nếu bạn đã “có gốc” React hay React Native thì bạn chỉ phải lo về phần dựng Widgets mà thôi. Nhưng nếu bạn chưa từng “làm queng” với bộ frameworks tới từ F*c****k thì sẽ gặp những ức chế nhất định, dù sẽ không mất quá nhiều thời gian để làm quen với State.

Tạm thời, chúng ta kết thúc bài tìm hiểu sơ lược ở đây. Để “bay vào” Flutter, bạn sẽ cần tìm hiểu về Dart trước. Thực tế Dart cũng không quá khó khăn, bởi nó cũng như bao ngôn ngữ khác, có những basic concepts và syntax khá quen thuộc như for và while loops, if – else, constructor, v.v… Và do vậy, tôi sẽ chỉ trình bày những điểm khác biệt về cú pháp của Dart trong các bài viết hướng dẫn về nó. Hẹn gặp lại các bạn sau, và trong khi chờ đợi, nếu bạn muốn tự tìm hiểu về Dart, hãy ghé thăm https://www.dartlang.org/guides/language/language-tour.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.