FLutter build with Flavor (part-3) - Google service config

Phần này chúng ta sẽ config với Google service nhé mọi người. Phần này khá là phức tạp đối với bên iOS. Còn Android thì khá là dễ. Ngoài ra cái này sẽ có 2 phần là cấu hình với file google services và 1 cái là với Google Api key.

Android

Đầu tiên thì là liên quan đến Google Api key. Cái này thì ta dùng thuộc tính "manifestPlaceholders" để có thể tạo một khoá ánh xạ đến AndroidManiest.xml. Ở ví dụ này mình sẽ dùng Google Maps API nhé.

    flavorDimensions "flavor"
    productFlavors {
        dev {
            dimension "flavor"
            applicationIdSuffix = ".dev"
            resValue "string", "app_name", "Build-[DEV]"
            manifestPlaceholders.google_maps_key = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag"
        }
        stg {
            dimension "flavor"
            applicationIdSuffix = ".stg"
            resValue "string", "app_name", "Build-[STG]"
            manifestPlaceholders.google_maps_key = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag"
        }
    }

Như ở trê thì khi build sẽ có 1 cái google maps key được ánh xạ đến manifest: manifestPlaceholders.google_maps_key = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag". Tại manifest để xử dụng chúng ta sẽ khai báo để key "google_maps_key" để có thấy được giá trị ra set vào.

<meta-data android:name="com.google.android.geo.API_KEY"
           android:value="${google_maps_key}"/>

Như trên thì nó sẽ lấy đúng khoá để gán vào. Vậy là xong phần API. Nói chung là khá dễ. Tiếp theo sẽ đến phần "google-services.json". Cái này thì chúng ta cũng chỉ cần tạo thư mục theo như flavor đã khai báo rồi copy file services vào đúng thư mục là được.

Tạo thư mục và copy vào nhé

Tại thư mục root của Android mình tạo 2 thư mục mà dev và stg như cây thư mục bên trên và cop vào. Với prod thì chúng ta sẽ cop vào main. Mặc định nếu ko có thư mục riêng theo flavor thì nó sẽ lấy ở main nhé. Như vậy là cũng xong rồi. Nói chung là Android thì cứ gọi là ez. Sang phần iOS sẽ phức tạp hơn khá nhiều.

iOS

Đối với Google API key thì chúng ta cần thêm và chỉnh sửa trong AppDelegate nhé. Mỗi 1 key cho một môi trường thì khai báo ra để gán vào. sau đó chúng ta phải gán key custom vào.

import Flutter
import GoogleMaps

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Using active compilation conditions to provide the right API key for the right flavor.
        var keyMap = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag"
        #if DEV
            keyMap = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag"
        #elseif STG
            keyMap = "xxxxxxxxxxxx-kVOsrtUevW6pMAyXkTQYPFZ7ag"
        #endif
        GMSServices.provideAPIKey(keyMap)
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

Đây là AppDelegate sau khi chỉnh sửa. key custom sẽ được thêm vào theo môi trường. Sau đó chung ta phải gán nó vào GG service qua lệnh "GMSServices.provideAPIKey(keyMap)".

Tiếp theo đến với file GoogleService-Info.plist. Cái này thì khá là phức tạp. Chúng ta phải viết 1 cái script cho nó để khi chạy nó sẽ add file theo đúng thư mục. Đầu tiên mở thư mục Runner trong root của iOS ra. Tạo các thư mục liên theo tên môi trường và copy file vào nhé. Chú ý là copy bằng Finder chứ ko cop hay kéo thả bằng xcode nhé

Copy file và thư mục như trên

Giờ thì mở xCode lên nhé.

Nhìn nè

Đầu tiên chọn Runner chọn targets Runner -> Build Phase -> '+' -> New Run Script Phase. Làm theo các bước này để tạo 1 Script khi build Project.

Tạo script

Đặt tên cho nó nhé. và nhớ là nó có sắp xếp vị trí đấy. Nhờ đặt nó trên cái Copy Bundle Resources mặc định nhé. Để dưới là không chạy đâu nhé.

Mở rộng nó ra

Mở rộng nó ra và chọn như dưới. Sau đó copy đoạn script sau để có thể thực thi.

# Name of the resource we're selectively copying
GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist

# Get references to dev and prod versions of the GoogleService-Info.plist
# NOTE: These should only live on the file system and should NOT be part of the target (since we'll be adding them to the target manually)
GOOGLESERVICE_INFO_DEV=${PROJECT_DIR}/${TARGET_NAME}/dev/${GOOGLESERVICE_INFO_PLIST}
GOOGLESERVICE_INFO_PROD=${PROJECT_DIR}/${TARGET_NAME}/prod/${GOOGLESERVICE_INFO_PLIST}
GOOGLESERVICE_INFO_STG=${PROJECT_DIR}/${TARGET_NAME}/stg/${GOOGLESERVICE_INFO_PLIST}

# Make sure the dev version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_DEV}"
if [ ! -f $GOOGLESERVICE_INFO_DEV ]
then
    echo "No Development GoogleService-Info.plist found. Please ensure it's in the proper directory."
    exit 1
fi

# Make sure the prod version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_PROD}"
if [ ! -f $GOOGLESERVICE_INFO_PROD ]
then
    echo "No Production GoogleService-Info.plist found. Please ensure it's in the proper directory."
    exit 1
fi

# Get a reference to the destination location for the GoogleService-Info.plist
PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${PLIST_DESTINATION}"

# Copy over the prod GoogleService-Info.plist for Release builds
if [ "${CONFIGURATION}" == "Debug-dev" ] || [ "${CONFIGURATION}" == "Profile-dev" ] || [ "${CONFIGURATION}" == "Release-dev" ]
then
    echo "Using ${GOOGLESERVICE_INFO_DEV}"
    cp "${GOOGLESERVICE_INFO_DEV}" "${PLIST_DESTINATION}"
elif [ "${CONFIGURATION}" == "Debug-stg" ] || [ "${CONFIGURATION}" == "Profile-stg" ] || [ "${CONFIGURATION}" == "Release-stg" ]
then
    echo "Using ${GOOGLESERVICE_INFO_STG}"
    cp "${GOOGLESERVICE_INFO_STG}" "${PLIST_DESTINATION}"
else 
    echo "Using ${GOOGLESERVICE_INFO_PROD}"
    cp "${GOOGLESERVICE_INFO_PROD}" "${PLIST_DESTINATION}"
fi

Với đoạn script này thì nó sẽ lấy file GoogleService-Info.plist từ thư mục config để copy vào đúng vị trí của nó. Một số chỗ cần chú ý như "GOOGLESERVICE_INFO_DEV=${PROJECT_DIR}/${TARGET_NAME}/dev/${GOOGLESERVICE_INFO_PLIST}" thì chỗ này TARGET_NAME thì nó sẽ lấy mặc định theo config Target. 'dev' thì là thư mục chưa file mà bạn đặt tên phía trên.

Đoạn check flavor "if [ "${CONFIGURATION}" == "Debug-dev" ] || [ "${CONFIGURATION}" == "Profile-dev" ] || [ "${CONFIGURATION}" == "Release-dev" ]". Phần này dùng để check muốn config nào dùng file nào. của mình ở đây là dev thì trỏ vào dev. Cái này mọi người tuỳ chỉnh theo cấu hình build của mình nhé.

Vậy là 3 phần về build mình đang làm ở dự án của mình đã kết thúc. Cảm ơn mọi người đã theo dõi.

Part 1
Part 2
Part 3