Flavors Organization at Flutter

What are Flavors for?


Imagine the situation: there is an application with analytics. There is a development team, testers and end users. Both those and those use one version of the application. Suppose we want to analyze how interesting feature A is to users. What do we do in this case? We go to analytics and see how many uses of this feature were (for example, transitions to the screen). But what do we see: a prohibitive number of transitions, which is by no means impossible with the current audience, and all these transitions were in a certain period of time. We go further and understand that at this time tests of this feature were carried out. And a little earlier its development. At the same time, analytics was also sent. Bottom line: analytics is dirty and substandard.


Here you can replace the word analytics with any other: push notifications, crash reporting, etc.


And in this situation, we are saved by dividing the application into two versions that differ minimally, for example, Bundle ID (package-name). Developers and testers use only a special dev version, and users use a sales one.


This is just one of the tasks of flavores. Here flavor will be used, since this is the name used by Flutter. People who are familiar with Android development, I think immediately recognized this mechanism.



Flavoring Flutter?


Well, we figured out the task. But how to implement it? Is everything as simple as they say?
Let's immediately decide: the organization of flavors is a purely native task. Information about them will not be available from the dart code. Therefore, for the ways of organization, we will go to the native mobile development.


Android


. android. : « buildType?», .


, , :


flavorDimensions "release-type"

    productFlavors {
        dev {
            dimension "release-type"
            applicationIdSuffix  ".dev"
            versionNameSuffix "-dev"
        }

        prod {
            dimension "release-type"
        }
    }

, :


flutter run --flavor dev

android .


: « buildType?» : Flutter buildType . , .


.
, builtTypes. IOS.
:


AndroidIOS
build typesbuild configurations
flavorstargets

— , ( ). flavor’ target’ — .


, , «»...


Runner — .


, target flavors iOS . , Flutter . , . . .


IOS


: (dev, prod, ).


:


  1. .
  2. .
  3. !

.



: dev, prod. :


    #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"
    #include "Generated.xcconfig"
    #include "common.xcconfig"

    bundle_suffix=.dev
    IDENTIFIER=$(identifier)$(bundle_suffix)

, bundle_suffix.


, Flutter Release Debug. bundle_suffix. , IDE.


IDENTIFIER — .


, :


ios/Flutter/dev.xcconfig
ios/Flutter/prod.xcconfig

XCode ( , ). Runner → New File → Configuration Settings File → .


Build Configurations. .


. Runner.xcworkspace Xcode Project.


«+» Configurations : Release Debug, .


:



, , IOS .


Scheme


, .



. : — Runner.
Edit Scheme .


Info.plist


(: ) — Bundle Identifier Info.plist


$(PRODUCT_BUNDLE_IDENTIFIER)$(bundle_suffix)

...


, , Android , fastlane gym iOS — . , IOS - … .


No Provisioning Profile


— . , .


, Info.plist , gym PRODUCT_BUNDLE_IDENTIFIER, .
common.xcconfig IDENTIFIER? .


, , , PRODUCT_BUNDLE_IDENTIFIER.


:


identifier=your.bundle.identifier

include User Defined
IDENTIFIER:


#include "common.xcconfig"

IDENTIFIER=$(identifier)$(bundle_suffix)

Xcode. Build Settings:



Product Bundle Identifier ( Packaging):



:


$(IDENTIFIER)


Info.plist bundle suffix, :


$(PRODUCT_BUNFLE_IDENTIFIER)

. .


bundle id


. Firebase, ( ).


— google-services.json(Google-Services.Info.plist). Android : flavor’ .


IOS - .



, . :



: XCode. . XCode — IDE, Add to target.
.



, . - , .


Run Script (setup firebase ):



, !


, :


# 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}/Firebase/dev/${GOOGLESERVICE_INFO_PLIST}
GOOGLESERVICE_INFO_PROD=${PROJECT_DIR}/${TARGET_NAME}/Firebase/prod/${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 # 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 # 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}" == *-prod ]]
then
echo "Using ${GOOGLESERVICE_INFO_PROD}"
cp "${GOOGLESERVICE_INFO_PROD}" "${PLIST_DESTINATION}"
else
echo "Using ${GOOGLESERVICE_INFO_DEV}"
cp "${GOOGLESERVICE_INFO_DEV}" "${PLIST_DESTINATION}"
fi


. , , Flutter ( ). , . .


All Articles