Flutter Flavor ile Uygulama Geliştirme

Flutter flavor ile ilgili bir çok makale okudum. Genelde flavor kullanımlarında Dev-Prod ayrımı yapılıyor. Farz edelim bir uygulama geliştirdik ve bu uygulama ile birden fazla firma için çıktı almamız gerekiyor. İçerikte sadece renkler , api url , google service json , image gibi değişiklikler söz konusu olsun.

Flavor ile aynı uygulamayı bahsettiğimiz değişiklikler ile birden fazla firmaya çıktı alabilir ve her uygulamayı farklı imzalayabiliriz.

Öncelikle klasör ayarlarımızı gerçekleştirelim.

Lib klasörü içerisinde settings adında bir klasör oluşturalım ve içerisine flavor_config.dart isimli bir dosya oluşturalım

import 'package:flutter/material.dart';

enum Flavor {
  // ignore: constant_identifier_names
  ACOMPANY,
  // ignore: constant_identifier_names
  BCOMPANY,
}

class FlavorValues {
  FlavorValues({required this.baseUrl});
  final String baseUrl;
  //Add other flavor specific values, e.g database name
}

class FlavorConfig {
  final Flavor flavor;
  static FlavorConfig? _instance;
  final String companyName;
  final String logo;
  Color bprimaryColor;

  factory FlavorConfig({
    required Flavor flavor,
    required String companyName,
    required String logo,
    required Color bprimaryColor,
  }) {
    _instance ??=
        FlavorConfig._internal(flavor, companyName, bprimaryColor, logo);
    return _instance!;
  }

  // ignore: unused_element
  FlavorConfig._internal(
      this.flavor, this.companyName, this.bprimaryColor, this.logo);
  static FlavorConfig get instance {
    return _instance!;
  }

  static bool isProduction() => _instance!.flavor == Flavor.ACOMPANY;
  static bool isProduction2() => _instance!.flavor == Flavor.BCOMPANY;
}

Bu dosyada belirttiğimiz enum Flavor kısmında firmalarımız bulunmakta. Ayrıca class içerisinde required olan kullanmak ve değiştirmek istediğiniz companyName, logo, bprimaryColor adında değişkenlerimiz bulunuyor.

Config dosyamızı ayarladığıma göre artık tüm sayfada kullanmamız gereken değişkenlerimizi farklı bir sayfa üzerinde toplayalım. Settings klasörü içerisine flavor_variable.dart isimli bir dosya oluşturalım.

import 'package:flutter/material.dart';

import 'flavor_config.dart';

const String apiUrl = "https---------/";
final String companyName = FlavorConfig.instance.companyName;
final String logo = FlavorConfig.instance.logo;
Color bprimaryColor = FlavorConfig.instance.bprimaryColor;

Burada oluşturduğumuz değişkenleri FlavorConfig class içerisindeki instance olarak aldığımız değişkenlerimize eşitliyoruz. Projemizde çağırdığımız bu değişkenler başlattığımız flavor main e göre bizlere yardımcı olacaktır.

Projemizin kök dizinine assets/img şeklinde klasör oluşturalım ve img klasörünün içerisine acompany ve bcompany şeklinde klasör yapımızı oluşturalım. Burada firmalarımıza ait resimleri tutacağız. Bu kısmı özelleştirebilir isterseniz fontlar veya diğer media lar için ayırabilirsiniz.

pubspec.yaml içerisine logolarımızı ekleyelim assets/img/acompany/logo.png — assets/img/bcompany/logo.png

Şimdi gelelim olayın can alıcı noktasına. Lib klasörü içerisinde main_acompany.dart ve main_bcompany.dart adında 2 adet dosya oluşturalım. Bu dosyalarımızın içeriği şu şekilde olacak.

import 'package:flavor_app/settings/flavor_config.dart';
import 'package:flutter/material.dart';
import 'main.dart';

void main() async {
  FlavorConfig(
      bprimaryColor: Colors.blue,
      companyName: "A COMPANY",
      flavor: Flavor.ACOMPANY,
      logo: "assets/img/acompany/logo.png");
  runApp(const MyApp());
}
import 'package:flavor_app/settings/flavor_config.dart';
import 'package:flutter/material.dart';
import 'main.dart';

void main() async {
  FlavorConfig(
      bprimaryColor: Colors.red,
      companyName: "B COMPANY",
      flavor: Flavor.ACOMPANY,
      logo: "assets/img/bcompany/logo.png");
  runApp(const MyApp());
}

Burada yaptığımız işlem tam olarak şöyle ifade edebilirim. Projemizi build ederken flavor ile başlatacağımız bu main ler FlavorConfig ayarları ile runApp içerisinde bulunan ve main.dart dosyamızdaki MyApp classını tetikletecek. Projemiz main.dart üzerinden değil aşağıda paylaşacağım şekilde başlatmak istediğiniz main_acompany veya bcompany üzerinden build olacaktır.

main.dart dosyamız

import 'package:flavor_app/page/home_page.dart';
import 'package:flavor_app/settings/flavor_variable.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: companyName,
      home: const HomePage(),
    );
  }
}

Ben başlattığımız main için companyName , bprimaryColor , logo gösterilen bir HomePage sayfası oluşturdum.

import 'package:flavor_app/settings/flavor_variable.dart';
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: bprimaryColor,
      appBar: AppBar(
        title: Text(companyName),
      ),
      body: Center(
        child: Image.asset(logo),
      ),
    );
  }
}

Şuan için tüm sayfalarımız hazır. İnce bir dokunuş ile android/app/build.grandle dosyamızı düzenleyelim.

signingConfigs
    {
        acompany
        {
                    def keystoreProperties = new Properties()
                    def keystorePropertiesFile = rootProject.file('app/src/acompany/key.properties')
                    if (keystorePropertiesFile.exists()) {
                        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
                    }

                    keyAlias keystoreProperties['keyAlias']
                    keyPassword keystoreProperties['keyPassword']
                    storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
                    storePassword keystoreProperties['storePassword']
        }
        bcompany
        {
                    def keystoreProperties = new Properties()
                    def keystorePropertiesFile = rootProject.file('app/src/bcompany/key.properties')
                    if (keystorePropertiesFile.exists()) {
                        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
                    }

                    keyAlias keystoreProperties['keyAlias']
                    keyPassword keystoreProperties['keyPassword']
                    storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
                    storePassword keystoreProperties['storePassword']
        }
    }

    buildTypes {
        release {
           signingConfig signingConfigs.acompany
           signingConfig signingConfigs.bcompany
        }
    }
    flavorDimensions "flavors"
    productFlavors
    {
        acompany
        {
            dimension "flavors"
            resValue "string", "app_name", "ACompany"
            applicationId "com.flavor.acompany"
            signingConfig signingConfigs.acompany
        }
        bcompany
        {
            dimension "flavors"
            resValue "string", "app_name", "BCompany"
            applicationId "com.flavor.bcompany"
            signingConfig signingConfigs.bcompany
        }
    }

Burada android{} içerisinde oluşturduğumuz productFlavors içerisinde firmalarımızı belirttik ve herbirinin app_name , applicationId ve config kısmını ayarlamış olduk. signingConfigs içerisinde projelerimizin çıktı almadan önce oluşturduğumuz imzalama işlemleri için gerekli olan properties kısımlarını ayarladık. rootProject.file(‘app/src’) diye başlayan kısımlarda belirtilen yol üzerinde sizinde dosya yapısı oluşturmanız gerekiyor. Örnek olarak aşağıda bu dosyayı paylaşıyorum. İçerisinde res klasörü , styles.xml , google-service.json , key.properties gibi dosyalarım mevcut.

Res klasöründe android iconlarınızı (mipmap) oluşturabilirsiniz. Firebase için google-service.json yine burada bulunmaktadır.

Artık tüm ayarlarımız yapıldığına ve Android Studio üzerinden imzalama işlemlerinizi yaptığınızı farz ederek build olayına geçebiliriz.

Terminal içerisinden aşağıdaki komut ile A Firması için build başlatıyoruz.

flutter run -t lib/main_acompany.dart -flavor=acompany

Aynı kodlar ile 2 farklı firma için tüm herşeyimiz tamamlanmış oldu.

Ekranlardan görebildiğiniz gibi A Company için title alanı ve B company için title alanları aynı zamanda background rengi ve logo lar başlattığımız firmaya göre değişiklik göstermiş oldu. Daha fazla firma ekleyerek aynı proje üzerinden birden fazla firmaya çıktı alabilirsiniz. Appbundle için

flutter build appbundle -t lib/main_acompany.dart -flavor=acompany

Githup : https://github.com/huseyinbedir/flavor_app

Umarım faydalı olur.

Hatalar Affola

Kalın sağlıcakla…