Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Dart Defines
Written by Hồng Vân Lê on June 14, 2022

Dart Defines trong Flutter và sức mạnh của nó

Flutter & Dart . Tutorials

Contents

  • Chuẩn bị
  • Dart Defines
  • Cú pháp
  • Ứng dụng vào Flutter Flavor
    • Cấu hình cho Android
    • Cấu hình cho iOS
  • Mở rộng thêm tính năng Customize Debug and Run của Visual Studio Code
  • Tạm kết

Chào mừng bạn đến với Fx Studio. Chúng ta đã cùng nhau phiêu lưu trong thế giới Flutter với Flavor. Tuy nhiên, bạn sẽ phải tốn kha khá các thao tác để đạt được mục đích.  Do đó, chủ đề bài viết này sẽ hướng dẫn cho các bạn 1 cách khác để config, nó sẽ giúp mình giảm được vô số bước. Đó là Dart Defines.

Tác giả bài viết là bạn Hồng Vân. Mọi người có thể theo dõi thêm các bài viết từ GitHub chính chủ của bạn nhóe!

Còn nếu mọi việc đã ổn rồi, thì …

Bắt đầu thôi!

Chuẩn bị

Về mặt kiến thức, bạn cần thông thạo Flutter cơ bản trước nhóe. Còn về mặt tools & versions, mình sẽ sử dụng các công cụ như sau:

  • IDE:

    • Visual Studio Code version 1.67.0

    • Android Studio Chipmunk 2021.2.1

    • XCode version 13.3.1

  • Flutter SDK version 2.10.5

Ngoài ra, đây cũng là phần tiếp theo của 3 bài viết liên quan tới Flavor trong Flutter. Nên nếu bạn chưa đọc qua nó, thì có thể tham khảo ở link sau:

  • Guide to flavoring a Flutter app

  • Guild to customize Run and Debug in flutter using VSCode

  • Write code for specific platform by MethodChannel.

Dart Defines

Dart defines là các biến được tạo ra trong khoảng thời gian biên dịch chương trình (compile-time variables). Nếu bạn đang tìm kiếm những biến tương tự biến môi trường (environtment variables), thì Dart defines là những gì bạn cần! Và chúng được tạo ra bởi --dart-define.

Vậy --dart-define là gì?

Nó là một tham số để truyền vào (pass) vào câu lệnh flutter build hoặc flutter run. Nó sẽ giúp chúng ta chuyển tiếp các biến môi trường. Điều đó có nghĩa là bạn có thể custom code của mình với bất kỳ giá trị nào bạn truyền qua tham số này.

Quá là hay phải không nào? Điều này khiến mình ngay lập tức nghĩ đến việc define các biến khác nhau cho flavor thay vì config khùng điên như ở bài trước của mình.

Ahihi!

Cú pháp

Trước khi đi vào ứng dụng cho flavor, mình sẽ demo nhỏ nhỏ để các bạn nắm được cách làm việc với --dart-define nha!

  • Bước 1: Chúng ta sẽ xây dựng 1 ứng dụng có UI đơn giản như sau:

 

  • Bước 2: Các bạn define lớp EnvironmentConfig:
class EnvironmentConfig {
  static const APP_NAME =
      String.fromEnvironment('APP_NAME', defaultValue: 'awesomeApp');
  static const APP_SUFFIX = String.fromEnvironment('APP_SUFFIX');
}

Giải thích 1 chút:

  • Chúng ta có thể truy cập các biến dart define thông qua hàm fromEnvirontment(name, defaultValue). name sẽ là tên biến được define sau câu lệnh --dart-define= , nếu như fromEnvirontment không thể tìm thấy biến nào như vậy thì nó sẽ trả về defaultValue.

  • Bạn sẽ bắt buộc phải khai báo biến là const, bởi vì hàm fromEnvironment chỉ đảm bảo hoạt động khi các biến đó là hằng số.

Còn vì sao có thêm static phía trước? Bạn chỉ cần gõ const không thôi là hiểu rõ! Ahihi!

  • Bước 3: Sử dụng lớp EnviromentConfig:

Tới đây, mình sẽ gán 2 biến APP_NAME và APP_SUFIX vào trên UI:

Text(
   'APP_NAME: ${EnvironmentConfig.APP_NAME}',
    style: Theme.of(context).textTheme.subtitle1,
),
Text(
   'APP_SUFFIX: ${EnvironmentConfig.APP_SUFFIX}',
    style: Theme.of(context).textTheme.subtitle1,
),

 

  • Bước 4: Run và xem kết quả thôi nào!

Câu lệnh run như sau:

flutter run --dart-define=APP_NAME=demo --dart-define=APP_SUFFIX=.dev

dart defines

(Kết quả thực thi nhóe!)

Ứng dụng vào Flutter Flavor

Nếu chưa biết Flutter Flavor là gì, bạn có thể tham khảo qua bài viết này của mình.

Còn đã biết rồi, thì bắt tay vào công việc thôi nào! Ý tưởng ở đây là mình sẽ config app có name và suffix khác nhau cho mỗi flavor nhé!

Cấu hình cho Android

  • Bước 1: Định nghĩa và đọc các biến dart define:

Bạn vào file android/app/build.gradle và thêm đoạn code này vào:

// 1
def dartEnvironmentVariables = [
    APP_NAME: 'awesomeApp',
    APP_SUFFIX: null
];
// 2
if (project.hasProperty('dart-defines')) {
    // 3    
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                // 4
                def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
                [(pair.first()): pair.last()]
            }
}

Giải thích code:

  1. Chúng ta define các biến dart define theo dạng key-value. Key này sẽ giống nhau ở cả iOS, Android và Flutter. Còn value định nghĩa các giá trị default.

  2. Flutter sẽ pass các biến dart define trong các thuộc tính của project với key là dart-defines

  3. Chuyển đổi string từ dart-defines thành Map.

  4. Flutter Tool sẽ pass tất cả các Dart Defines như 1 string với dấu phẩy, ví dụ:

    • Ở Flutter 1.17: APP_NAME=awesomeApp1,APP_SUFFIX=.dev

    • Ở Flutter 1.20: APP_NAME%3Dawesome1,APP_SUFFIX%3D.dev

    • Ở Flutter 2.2: REVGSU5FRVhBTVBMRV9BUFBfTkFNRT1hd2Vzb21lMg==,REVGSU5FRVhBTVBMRV9BUFBfU1VGRklYPS5kZXY=

    Ở mỗi version, có cách mã hoá khác nhau, ở đây vì mình sử dụng Flutter 2.16 mã hoá base64 như ở Flutter 2.2, nên mình sẽ phải giải mã base64 ngược lại.

 

  • Bước 2: Thay đổi app name và application id suffix
    • Bạn tiếp tục vào file android/app/build.gradle và sửa ở phần defaultConfig như sau:
defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.demo_dart_define"
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        // NOTE: ADD THESE LINES
        applicationIdSuffix dartEnvironmentVariables.APP_SUFFIX
        resValue "string", "app_name", dartEnvironmentVariables.APP_NAME
}
    • Bạn vào android/app/src/main/AndroidManifest.xml để gán app_name vào application label
<application
        android:label="@string/app_name"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">

Bây giờ run và xem kết quả thôi. Câu lệnh như trên nhé!

flutter run --dart-define=APP_NAME=demo --dart-define=APP_SUFFIX=.dev

Dart Defines

App name đã được thay đổi!

Cấu hình cho iOS

Bạn vẫn phải thực hiện trên XCode nha!

  • Bước 1: Bạn tạo file Define-defaults.xcconfig để define các cặp key-value tương tự như ở bước 1 của Android.

    • Click chuột phải vào Runner/Flutter chọn New File, nhập “con“” vào ô filter chọn Next và đặt tên tương ứng.

    • Bạn định nghĩa vào đó như sau:
APP_NAME=awesomeApp
APP_SUFFIX=

 

  • Bước 2: import file đó vào Debug.xcconfig và Release.xcconfig

#include "Generated.xcconfig"
#include "Define-defaults.xcconfig"
#include "Define.xcconfig"

Giải thích: Define-defaults.xcconfig là file bạn đã tạo ở bước 1 còn Define.xcconfig để ghi các biến dart define sẽ là file được tạo ra trong quá trình biên dịch.

 

  • Bước 3: Thay đổi app name và app bundle identifier trong file Info.plist

 

  • Bước 4: Chỉnh sửa scheme để đọc các biến dart define và ghi vào file Define.xcconfig
    • Click vào Scheme Runner -> Edit Scheme. Sau đó dưới tab Build chọn Pre-actions -> click dấu + chọn New Run Script Action

    • Tiếp theo, chúng ta sẽ viết đoạn code thực hiện việc đọc các biến dart define và ghi vào file Define.xcconfig. Đoạn code này sẽ được biên dịch trước khi XCode build app. Tương tự như Android là vẫn phải giải mã base64 nha:
function entry_decode() { echo "${*}" | base64 --decode; }

IFS=',' read -r -a define_items <<< "$DART_DEFINES"

for index in "${!define_items[@]}"
do
    define_items[$index]=$(entry_decode "${define_items[$index]}");
done

printf "%s\n" "${define_items[@]}"|grep '^APP_' > ${SRCROOT}/Flutter/Define.xcconfig
    • Nhớ chọn Provide build settings from là Runner nhoé! Nếu không thì các bạn sẽ gặp lỗi đấy.
Dart Defines
Run và xem kết quả thôi. Vẫn dùng câu lệnh trên kia nhé!
flutter run --dart-define=APP_NAME=demo --dart-define=APP_SUFFIX=.dev

Dart Defines

Lưu ý: Đoạn code trên sẽ giúp bạn tự generate ra file Define.xcconfig khi bạn chạy câu lệnh có flutter run --dart-define=APP_... nhưng điều gì sẽ xảy ra nếu bạn chỉ chạy lệnh flutter run hoặc các biến dart define không chứa chữ “APP“? Bạn nghĩ nó sẽ lấy giá trị trong Define-defaults.xcconfig phải không? Không đâu! Bạn sẽ gặp lỗi như vậy:

Dart Defines

Theo mình thấy thì điều này khá khó chịu. Vậy nên, mình đề xuất các bạn hãy tạo luôn file Define.xcconfig để nếu có không pass các biến dart define, thì chương trình vẫn chạy trơn tru.

Mở rộng thêm tính năng Customize Debug and Run của Visual Studio Code

Có lẽ sẽ có bạn thắc mắc rằng: “Không lẽ mỗi lần build bắt buộc phải build bằng command sao?” Hoặc rằng: “Nếu các biến dart define đó dài hay cần nhiều biến thì chẳng phải quá tốn công sao?”

Bây giờ, sẽ là lúc mình giúp bạn trả lời câu hỏi đó!

Nếu các bạn chưa biết về Customize Debug & Run của Visual Studio Code, thì tham khảo qua bài viết ở link này của mình. Còn nếu biết rồi, thì chúng ta bắt đầu thôi!

  • Bạn vào tab Run and Debug và click vào create a launch.json file -> chọn Debbuger là Dart&Flutter nhé!.

Dart Defines

  • Vào file .vscode/launch.json, tạo 3 configurations tương ứng với 3 flavor là dev, staging và product.
{
     "name": "dev",
     "request": "launch",
     "type": "dart",
     "args": ["--dart-define", "APP_NAME=[dev]demo", "--dart-define", "APP_SUFFIX=.dev"]
},
{
     "name": "staging",
     "request": "launch",
     "type": "dart",
     "args": ["--dart-define", "APP_NAME=[stg]demo", "--dart-define", "APP_SUFFIX=.stg"]
},
{
     "name": "prod",
     "request": "launch",
     "type": "dart",
     "args": ["--dart-define", "APP_NAME=demo"]
},
  • Run lên và xem kết quả thôi! Bạn có thể chọn flavor nào để build tuỳ thích nhé!

Dart Defines

Kết quả nhận được như sau nhóe!

  • dev

  • staging

  • product

Xem lại tên của 3 app để thấy sự khác nhau của mỗi config nhóe!

Tạm kết

Qua bài này bạn đã biết:

  • Khái niệm và cách làm việc với --dart-define trong Flutter

  • Ứng dụng --dart-define vào Flutter flavor

  • Mở rộng tính năng của Customize Run and Debug

Nếu các bạn đã từng theo dõi các bài viết trước của mình, thì sẽ nhận ra có 1 cái liên quan đến Flutter flavor mà mình chưa nói đến. Đó là cái api url khác nhau cho từng flavor.

Câu trả lời đấy mình để dành cho các bạn trả lời đấy! Nếu muốn biết đáp án thì các bạn có thể liên hệ mình.

Okay! Tới đây, mình xin kết thúc bài viết về Dart Defines trong Flutter . Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.

  • Bạn có thể checkout source code tại đây.
  • Nguồn tham khảo:
    • Flutter 1.17 — no more Flavors, no more iOS Schemas. Command argument that changes everything | Denis Beketsky

    • Using –dart-define in Flutter – Dart Code – Dart & Flutter support for Visual Studio Code

    • How to setup dart define for keys and screts on android | Gildásio Filho

  • Follow me more:

    • Facebook: https://www.facebook.com/van.may.750/
    • Email : lehongvan.develop@gmail.com
    • LinkedIn: https://www.linkedin.com/in/le-van-935231150/

Cảm ơn bạn đã đọc bài viết này!

FacebookTweetPinYummlyLinkedInPrintEmailShares10

Related Posts:

  • Flavor & Câu chuyện config trong Flutter
    Flavor & Câu chuyện config trong Flutter
  • Bản chất của Layout - SwiftUI Notes #30
    Bản chất của Layout - SwiftUI Notes #30
  • Platform-specific code with MethodChannel - Flutter
    Platform-specific code with MethodChannel - Flutter
  • Đạo đức nghề nghiệp và lương tâm của coder
    Đạo đức nghề nghiệp và lương tâm của coder
Tags: flavor, flutter
Written by Hồng Vân Lê

Leave a Reply Cancel reply

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

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift api AppDistribution Asynchronous autolayout basic ios tutorial blog callback ci/cd closure collectionview combine concurrency CoreData Core Location crashlytics darkmode dart dart basic dart tour Declarative decoding delegate deploy fabric fastlane firebase flavor flutter GCD iOS mapview MVVM optional protocol rxswift Swift Swift 5.5 SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Raw String trong 10 phút
  • Dispatch Semaphore trong 10 phút
  • Tổng kết năm 2022
  • KeyPath trong 10 phút – Swift
  • Make color App Flutter
  • Ứng dụng Flutter đầu tiên
  • Cài đặt Flutter SDK & Hello world
  • Coding Conventions – người hùng hay kẻ tội đồ?
  • Giới thiệu về Flutter
  • Tìm hiểu về ngôn ngữ lập trình Dart

You may also like:

  • Make color App Flutter
    Make color App Flutter
  • Variables & Constant - Dart Tour
    Variables & Constant - Dart Tour
  • Mình đã tự học Flutter như thế nào?
    Mình đã tự học Flutter như thế nào?
  • Expressions - Dart Tour
    Expressions - Dart Tour
  • Bản chất của Layout - SwiftUI Notes #30
    Bản chất của Layout - SwiftUI Notes #30

Archives

  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (22)
  • Code (4)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (86)
  • RxSwift (37)
  • SwiftUI (76)
  • Tutorials (70)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2023 Fx Studio - All rights reserved.

    Share this ArticleLike this article? Email it to a friend!

    Email sent!