Flutter Android IOS 三端共用同一份配置文件
Posted freeCodeSunny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter Android IOS 三端共用同一份配置文件相关的知识,希望对你有一定的参考价值。
前言
Flutter 是 Google 使用 Dart 语言开发的一套移动应用开发框架,介绍Flutter开发的文章已经汗牛充栋, 所以这里我们主要不是来讨论怎么去开发一个Flutter应用,而是来解决在开发过程中遇到的问题。
现状
环境配置
在应用开发过程中, 我们往往是有很多配置的,比如开发环境,一般我们分为线上和测试,在不同的环境中链接不同的服务器,也可能根据不同的环境本地加载不同的代码,以前我们做android或者ios 在本地创建一个配置文件,比如我们在Android下面创建一个config.properties
# env, switch
ENV=ONLINE
#ENV=TEST
应用在打包的时候读取配置,注入BuildConfig自动调整环境:
def configProperties = new Properties()
def versionPropertiesFile = rootProject.file('../config.properties')
if (versionPropertiesFile.exists())
versionPropertiesFile.withReader('UTF-8')
reader -> configProperties.load(reader)
def evn = configProperties.getProperty("ENV")
if (evn == null)
evn = 'TEST'
// 在应用的build.grade的defaultConfig节点根据环境注入我们的需要的配置,也可以同时注入BuildConfig
defaultConfig
applicationId "xxxxxx"
minSdkVersion 21
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk
abiFilters 'armeabi-v7a', 'arm64-v8a'
manifestPlaceholders = [COM_NETEASE_NIM_APP_KEY: evn == 'ONLINE' ? onlineKey : testKey]
上述方式就需要Android一份配置,IOS一份配置,每次有变更,两边都需要配置和修改。
版本配置
我们知道在Android中我们配置版本号,在应用的build.gradle的defaultConfig节点配置versionCode和versionName:
android
compileSdkVersion 28
sourceSets
main.java.srcDirs += 'src/main/kotlin'
lintOptions
disable 'InvalidPackage'
defaultConfig
applicationId "xxxxx"
minSdkVersion 21
targetSdkVersion 28
versionCode 5
versionName 1.0.0
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk
abiFilters 'armeabi-v7a', 'arm64-v8a'
而在IOS中我们需要在Info.plist中进行配置CFBundleShortVersionString与CFBundleVersion,一般我们在xcode的runner-General手动配置或者脚读取:
上面只是Android端和IOS端,目前我们已经采用Flutter来进行开发,在Flutter中很多时候我们也有需要读取当前的版本号,这时我们怎么办? 我们一般都采用读取平台的版本来实现,这里我们可以采用在pubspec中添加dependencies:
dependencies:
flutter:
sdk: flutter
package_info: ^0.4.0+13
然后在代码中进行读取,我们新建一个package_info.dart文件:
class PackageInfoUtil
static PackageInfoUtil _singleton;
static PackageInfo _packageInfo;
factory PackageInfoUtil() => _singleton ?? (_singleton = PackageInfoUtil._internal());
PackageInfoUtil._internal()
_preLoad();
Future<void> _preLoad() async
if (_packageInfo == null)
_packageInfo = await PackageInfo.fromPlatform();
String get versionCode
return _packageInfo?.buildNumber;
String get versionName
return _packageInfo?.version;
解决方案
有没有一种方法可以三端只采用一份配置,就可以自动配置各种环境与版本号?
flutter端
这里我们知道flutter中我们可以配置asset文件,这里我们可以自定义一个配置文件到asset里面,我们在flutter工程中创建一个asset目录,预置一份配置文件,这里文件我们可以采用json格式,也可以采用properties格式,json格式便于flutter解析,但是proterties便于Android的gradle解析,这里我们采用properties格式来配置,只不过需要flutter内部需要我们来手动解析:
- 我们首先在flutter工程中新建一个assets目录,创建一个config.properties 文件,这里time表示编译时间,还可以注入git号等信息。
# version
versionName=0.3.1
versionCode=5
# env, switch
ENV=ONLINE
#ENV=TEST
# time
time=2020-04-07 15:19:29
- 我们在工程的pubspec.yaml中配置asset信息:
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# other module assets must declare here
fonts:
- family: iconfont
fonts:
- asset: uikit/assets/fonts/iconfont.ttf
# To add assets to your application, add an assets section, like this:
assets:
- assets/config.properties
根据上面文件我们配置信息已经ok,之后我们就是需要在flutter中解析对应的信息,我们这里创建一个dart文件,在应用加载前预先执行解析:
class AppConfig
factory AppConfig() => _instance ?? (_instance = AppConfig._internal());
static AppConfig _instance;
AppConfig._internal();
static const String online = 'ONLINE';
static const String test = 'TEST';
String evn;
String versionName;
String versionCode;
/// build time
String time;
bool get isOnline
return evn == online;
static bool get isInDebugMode
bool inDebugMode = false;
assert(inDebugMode = true);
return inDebugMode;
Future init() async
Map<String, String> properties = Map();
String value = await rootBundle.loadString("assets/config.properties");
List<String> list = value?.split("\\n");
list?.forEach((element)
if (element != null && element.contains("="))
String key = element.substring(0, element.indexOf("="));
String value = element.substring(element.indexOf("=") + 1);
properties[key] = value;
);
parserProperties(properties);
return Future.value();
void parserProperties(Map<String, String> properties)
evn = properties['EVN'] ?? online;
versionName = properties['versionName'] ?? "1.0.0";
versionCode = properties['versionCode'] ?? "0";
time = properties['time'] ?? TimeUtil.getTimeFormatMillisecond();
这里很多字段被删除了, 大家只需要关注整个流程就ok了, 同时这里的time字段配置文件中可以不预先赋值,这样在debug阶段中,每次编译都是当前生成的时间,但是在上线前打包时,我们可以采用脚本注入打包的时间,后面我们会给出样例。
Android端
上述我们已经创建了对应的配置文件,现在就需要在Android端同样解析对应的信息, 我们在应用对应的build.gradle中解析对应的信息,注入对应的信息:
def configProperties = new Properties()
def versionPropertiesFile = rootProject.file('../assets/config.properties')
if (versionPropertiesFile.exists())
versionPropertiesFile.withReader('UTF-8')
reader -> configProperties.load(reader)
def flutterVersionCode = configProperties.getProperty('versionCode')
if (flutterVersionCode == null)
flutterVersionCode = '3'
def flutterVersionName = configProperties.getProperty('versionName')
if (flutterVersionName == null)
flutterVersionName = '2.0.0'
def evn = configProperties.getProperty("ENV")
if (evn == null)
evn = 'TEST'
android
compileSdkVersion 28
sourceSets
main.java.srcDirs += 'src/main/kotlin'
lintOptions
disable 'InvalidPackage'
defaultConfig
applicationId "com.netease.yunxin.meeting"
minSdkVersion 21
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk
abiFilters 'armeabi-v7a', 'arm64-v8a'
manifestPlaceholders = [COM_NETEASE_NIM_APP_KEY: evn == 'ONLINE' ? onlineKey : testKey]
IOS端
上面flutter,android已经公用了同一份信息,那ios怎么处理,这里我们知道ios在打包时候会执行build phases中的run script脚本,那我们可以在脚本的前面预先解析对应的信息,这里我们解析版本信息, 将信息写回Info.plist:
VERSION_NAME=$(cat ../assets/config.properties | grep versionName | head -1 | cut -d '=' -f 2)
VERSION_CODE=$(cat ../assets/config.properties | grep versionCode | head -1 | cut -d '=' -f 2)
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION_NAME" "$PROJECT_DIR/$INFOPLIST_FILE"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION_CODE" "$PROJECT_DIR/$INFOPLIST_FILE"
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
这样我们就在三端中公用了同一份信息,也可以根据不同的端配置不同的信息,各端解析对应的文件,这样就避免了改丢或者改错的问题。
上面我们提到了脚本注入编译时间的问题,这里我们在上线打包时我们可以在脚本中注入打包时间, 我们创建一个build.sh脚本:
set -e
set +x
echo "build start"
project_path=$(dirname $(pwd))
echo $project_path
cd $project_path
rm -rf "$project_path/outputs"
mkdir -p "$project_path/outputs"
current_time=$(date "+%Y-%m-%d %H:%M:%S")
echo $current_time
sed -i "" '$d' $project_path/assets/config.properties
echo "time=$current_time" >> $project_path/assets/config.properties
sh $project_path/deploy/build_android.sh
cd $project_path
sh $project_path/deploy/build_ios.sh
cd $project_path
echo "build done"
set +e
上面我们注入了时间,首先删除了最后一行,同时追加了当时的编译时间
后记
Flutter开发中还有很多东西可以提升,后续有机会也会逐步写出来
以上是关于Flutter Android IOS 三端共用同一份配置文件的主要内容,如果未能解决你的问题,请参考以下文章