Flutter && gradlew 命令 && shell打包脚本

无论是持续性编译还是平时开发,都离不开命令。Android有gradlew命令,flutter也有对应的命令,对于shell脚本命令,我们也经常用到。这篇博文只是简单整理,方便以后查阅。

对于部分
Shell(Bash)多命令顺序执行方法详解

gradlew命令

我们知道 Android打包使用的是gradlew命令,先来看一下gradlew命令

gradlew命令都可以使用简写,例如:

./gradlew assembleRelease 简写为:./gradlew aR

gradlew前面加./表示当前目录,具体查看以下博文:路径中的'.'和'..'还有'./'和'../'都是什么意思,所以这里需要切换到flutter的Android根目录之下,才能找到gradlew命令

image.png
# 查看所有任务

./gradlew tasks --all

# 对某个module [moduleName] 的某个任务[TaskName] 运行.

/gradlew:moduleName:taskName

# 查看项目的依赖都依赖了哪些库。

gradlew :app:dependencies 

#只编译清单文件,并查看具体日志,快速定位清单文件报错

gradlew :app:processDebugManifest --stacktrace:

# 查看构建版本

./gradlew -v

# 清除build文件夹

./gradlew clean

# 检查依赖并编译打包

./gradlew build

# 编译并安装debug包

./gradlew installDebug

# 编译并打印日志

./gradlew build --info

# 调试模式构建并打印日志

./gradlew build --info --debug --stacktrace

# 强制更新最新依赖,清除构建并构建

./gradlew clean --refresh-dependencies build

注意build命令把 debug、release环境的包都打出来的

如果需要指定构建使用如下命令

指定构建目标命令

# 编译并打Debug包

./gradlew assembleDebug./gradlew aD

# 编译并打Release的包

./gradlew assembleRelease./gradlew aR

构建并安装调试命令

# 编译并打Debug包

./gradlew assembleDebug

# 编译app module 并打Debug包

./gradlew install app:assembleDebug

# 编译并打Release的包(生成的aar包就在`.android/Flutter/build/outputs/aar/`目录下)

./gradlew assembleRelease

#  Release模式打包并安装

./gradlew installRelease

# 卸载Release模式包

./gradlew uninstallRelease

多渠道打包

assemble还可以和productFlavors结合使用,如果出现类似 Task'install'isambiguousinroot project 这种错误,请查看配置的多个渠道然后修改命令为./gradlew install[productFlavorsName] app:assembleDebug来用命令构建调试

# Release模式打包并安装

./gradlew installRelease

# 卸载Release模式包

./gradlew uninstallRelease

# Release模式全部渠道打包

./gradlew assembleRelease

# Release模式 test 渠道打包

./gradlew assembleTestRelease

# debug release模式全部渠道打包

./gradlew assemble

#查看包依赖

./gradlew dependencies

# 编译时的依赖库

./gradlew app:dependencies --configuration compile

# 运行时的依赖库

./gradlew app:dependencies --configuration runtime

依赖管理
传递依赖特性

dependencies {
    transitive true
}

手动配置transitive属性为false,阻止依赖的下载

强制

configurations.all{
// transitive false// 强制指定版本
  resolutionStrategy{
      force'org.hamcrest:hamcrest-core:1.3'// 强制不编译
      all*.excludegroup:'org.hamcrest',
      module:'hamcrest-core'
  }
}

动态依赖特性

dependencies {
  // 任意一个版本
  compile group:'b',name:'b',version:'1.+'
  // 最新的版本
  compile group:'a',name:'a',version:'latest.integration'
}

查看详细依赖信息

#使用离线模式

./gradlew aDR --offline

#守护进程

./gradle build --daemon

#并行编译模式

./gradle build --parallel --parallel-threads=N

#按需编译模式

./gradle build --configure-on-demand

#不使用snapshot依赖仓库 前提是离线可以使用时

./gradlew clean aDR

通过增加--dwarf_stack_traces,--print-snapshot-sizes,--obfuscate命令压缩体积

./gradlew clean assembleRelease -Pextra-gen-snapshot-options="--dwarf_stack_traces,--print-snapshot-sizes,--obfuscate"

flutter 命令

前面说完gradlew命令,我们回过头来研究flutter。

flutter create

在指定的目录中,创建新的flutter项目,如果没有指定目录,则在当前目录下创建项目

flutter create ~/flutter #在家目录下的flutter目录项目
flutter create . #在当前目录下创建

flutter -v

查看APP所有日志的输出,对于调试是非常有用处,在调试时需要配合run命令使用

flutter -v run

flutter -d

切换在不同设备上运行app,如果没有指定设备,默认将会使用设备列表的第一个设备,这对于计算机连接多个设备时非常有用,可以使用设备名称或者设备id作为参数

flutter run -d NX569J #设备名称
flutter run -d devices_id #设备id

flutter analyze

编辑Flutter代码时,使用分析器检查代码是非常重要,默认是分析整个项目的代码,你也可以通过使用analysis_options.yaml文件来排除不需要的代码分析

analyzer:
  exclude:
    - flutter/**

analysis_options.yaml

有时候你可能需要代码分析一直在运行,可以使用--watch选项

flutter analyze --watch

当运行分析命令flutter都执行一次pub get命令,如果不需要运行,可以执行以下命令

flutter analyze --no-pub 

flutter attach

相当于命令flutter run命令,不同之处在很多执行都是自己手动,比如热重载,

flutter bash-completion

在执行该命令时会输出一的配置脚本,脚本可以实现命令行提示的自动完成,可用于zsh,bash的配置,将脚本添加到~/.bashrc或者~/.zshrc

if type complete &>/dev/null; then
  __flutter_completion() {
    local si="$IFS"
    IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
                           COMP_LINE="$COMP_LINE" \
                           COMP_POINT="$COMP_POINT" \
                           flutter completion -- "${COMP_WORDS[@]}" \
                           2>/dev/null)) || return $?
    IFS="$si"
  }
  complete -F __flutter_completion flutter
elif type compdef &>/dev/null; then
  __flutter_completion() {
    si=$IFS
    compadd -- $(COMP_CWORD=$((CURRENT-1)) \
                 COMP_LINE=$BUFFER \
                 COMP_POINT=0 \
                 flutter completion -- "${words[@]}" \
                 2>/dev/null)
    IFS=$si
  }
  compdef __flutter_completion flutter
elif type compctl &>/dev/null; then
  __flutter_completion() {
    local cword line point words si
    read -Ac words
    read -cn cword
    let cword-=1
    read -l line
    read -ln point
    si="$IFS"
    IFS=$'\n' reply=($(COMP_CWORD="$cword" \
                       COMP_LINE="$line" \
                       COMP_POINT="$point" \
                       flutter completion -- "${words[@]}" \
                       2>/dev/null)) || return $?
    IFS="$si"
  }
  compctl -K __flutter_completion flutter
fi

flutter build

构建应用程序的apk,appbundle,aot,ios,IOS应用需要在Mac osx上构建

flutter build apk

flutter channel

切换flutter不同的版本,在执行flutter channel会输出不同分支信息,默认使用stable分支

flutter channel # 输出channel
flutter channel dev # 切换到dev channel

flutter clean

删除build/.dart_tool/目录,清除缓存信息,避免之前不同版本代码的影响

flutter config

可以用于指定gradle,android sdk,android studio的目录或者开启,禁用analytics选项,analytics选项用于flutter工具的报告

flutter config --gradle-dir /gradle/

flutter devices

列出已经连接到计算机的设备

flutter devices
NX569J                    • 192.168.43.1:5555 • android-arm64 • Android 7.1.2 (API 25)
Android SDK built for x86 • emulator-5554     • android-x86   • Android 9 (API 28) (emulator)

flutter doctor

检查开发工具链是否完整安装,对于安装环境非常有用处,检查andorid licenses需要连接外网,请科学上网

flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.2.1, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Android Studio (version 3.3)
[✓] VS Code (version 1.33.1)
[✓] Connected device (2 available)

• No issues found!

flutter pub outdated

查询展示依赖包可更新的版本信息

Showing outdated packages.
[*] indicates versions that are not the latest available.

Package Name     Current     Upgradable  Resolvable  Latest   

direct dependencies:
cupertino_icons  *0.1.3      *0.1.3      1.0.3       1.0.3    
fixnum           *0.10.11    *0.10.11    1.0.0       1.0.0    
package_info     *0.3.2+1    *0.3.2+1    2.0.2       2.0.2    
protobuf         *0.13.16+1  *0.13.16+1  2.0.0       2.0.0    

transitive dependencies:
meta             *1.3.0      *1.3.0      *1.3.0      1.7.0    

transitive dev_dependencies:
async            *2.6.1      *2.6.1      *2.6.1      2.8.2    
charcode         *1.2.0      *1.2.0      *1.2.0      1.3.1    
matcher          *0.12.10    *0.12.10    *0.12.10    0.12.11  
test_api         *0.3.0      *0.3.0      *0.3.0      0.4.3    

4  dependencies are constrained to versions that are older than a resolvable version.

flutter pub upgrade --major-versions

快速自动更新app依赖

Resolving dependencies...
  async 2.6.1 (2.8.2 available)
  boolean_selector 2.1.0
  characters 1.1.0
  charcode 1.2.0 (1.3.1 available)
  clock 1.1.0
  collection 1.15.0
> cupertino_icons 1.0.3 (was 0.1.3)
  fake_async 1.2.0
> fixnum 1.0.0 (was 0.10.11)
  flutter 0.0.0 from sdk flutter
  flutter_test 0.0.0 from sdk flutter
  matcher 0.12.10 (0.12.11 available)
  meta 1.3.0 (1.7.0 available)
> package_info 2.0.2 (was 0.3.2+1)
  path 1.8.0
> protobuf 2.0.0 (was 0.13.16+1)
  sky_engine 0.0.99 from sdk flutter
  source_span 1.8.1
  stack_trace 1.10.0
  stream_channel 2.1.0
  string_scanner 1.1.0
  term_glyph 1.2.0
  test_api 0.3.0 (0.4.3 available)
  typed_data 1.3.0
  vector_math 2.1.0
Downloading protobuf 2.0.0...
Changed 4 dependencies!
5 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

Changed 4 constraints in pubspec.yaml:
  package_info: ^0.3.2+1 -> ^2.0.2
  fixnum: ^0.10.9 -> ^1.0.0
  protobuf: ^0.13.4 -> ^2.0.0
  cupertino_icons: ^0.1.2 -> ^1.0.3

flutter drive

执行flutter ui测试,该工具类似与web端的Selenium,WebDriver,Protractor.你可以指定不同模式进行测试,可以是debug,profile,release,flavor模式,flavor模式可以指定平台规范,你还可以指定在不同的平台测试,甚至可以指定页面路由

flutter drive --debug --target-platform android-x86

flutter emulators

列出,创建,启动模拟器,默认是列出模拟器

flutter emulators --launch flutter_emulator #启动
flutter emulators # 列出
flutter emulators --create Pixel_API_28 # 创建

flutter format

按照dart代码规范格式项目代码文件,flutter format .是当前项目所有文件,也可以指定目录或者文件

flutter format dartfile

flutter verion

列出或者切换flutter版本,默认是列出所有版本

flutter version
flutter version v1.5.8

flutter upgrade

更新flutter代码,实质就是git代码更新拉取,下载flutter sdk是git仓库的打包

flutter test

运行flutter单元测试,可以使用--start-paused模式等待调试器的连接,--concurrency可以指定并发任务数默认值是6

flutter test --concurrency=8

flutter install

安装app到一个已经连接的设备

flutter install

flutter screenshot

截取当前屏幕,默认是将图片输出到家目录下,使用-o指定输出目录

flutter screenshot -o /home/work

flutter packages

获取,测试,更新依赖包,flutter pub 将会传递剩余参数到dart工具的pub

flutter packages get

首先打开flutter的安装目录,进入flutter_tools-》gradle打开flutter.gradle


image.png

shell打包脚本

Android打包

多渠道

多渠道打包常规方式有两种,Flavor 和 --dart-define,后者是 Flutter1.17新增的命令行可选参数,比Flavor配置更简单,非常适合用于环境配置

channel_dev.dart

class EnvironmentConfig{
  static const APP_CHANNEL = String.fromEnvironment('APP_CHANNEL',defaultValue:"default");
  static const APP_STORE_NAME = String.fromEnvironment('APP_STORE_NAME');
}

将渠道传给第三方埋点统计平台,比如友盟和bugly

FlutterUmengPlus.init(androidAppKey:"XXXXXXX", iOSAppKey:"XXXXXX", channel:"${EnvironmentConfig.APP_CHANNEL}",logEnable: false,);

android =》app=〉build.gradle添加以下信息

/// 获取渠道参数使用,这里设置一下默认值
def dartEnvironmentVariables = [
        APP_CHANNEL: 'default',
        APP_STORE_NAM: 'yatsar',
        APP_STORE_URL:''
]
///拦截dart-defines 获取外部输入值,添加到dartEnvironmentVariables
if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                def pair = URLDecoder.decode(entry, "utf-8").split('=')
                [(pair.first()): pair.last()]
            }
}

android{}下更改apk名字

 // 重命名 apk
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            if(variant.buildType.name == "release"){
                // 获取版本
                def versionName = variant.versionName
                def versionCode = variant.versionName
                // 设置新名称
                def newApkName ="app_v${defaultConfig.versionName}_${defaultConfig.versionCode}_channel_${dartEnvironmentVariables.APP_CHANNEL}.apk"
                outputFileName = new File(newApkName)
            }
        }
    }
单个市场打包脚本fapk_channel.sh
echo "正在打包$1市场渠道,请耐心等待。。。"
cd C:/Users/Administrator/StudioProjects/flutter_beauty/
flutter clean
echo "flutter clean end: $?"
if [$? -ne 0];then
    echo "clean faild"
else
    echo "clean success"
fi

flutter build apk  --dart-define=APP_CHANNEL=$1  --dart-define=APP_STORE_NAME=$2
cd build/app/outputs/flutter-apk/

date_time=$(date "+%Y%m%d")

build_dir=C:/myApp/output/$date_time/$1

if [ ! -d "$build_dir" ];then
     mkdir -p $build_dir
fi

time=$(date "+%Y%m%d%H%M%S")

cp -R *release.apk  $build_dir/$1_$time.apk

进行打包某个渠道的时候只要输入命令即可

fapk_channel.sh HUAWEI  华为
全部市场打包脚本fapk_all_channel.sh
echo "打包全部市场渠道市场渠道,请耐心等待。。。"

fapk_channel.sh MyApp 腾讯应用宝;
fapk_channel.sh 360  360手机助手;
fapk_channel.sh Baidu 百度手机助手;
fapk_channel.sh Yatsar Yatsar
fapk_channel.sh HUAWEI  华为;
fapk_channel.sh OPPO OPPO;
fapk_channel.sh VIVO VIVO;
fapk_channel.sh Mi 小米;
fapk_channel.sh SamSung 三星应用市场

iOS打包

iOS打包比较复杂一些,需要用到一个打包的脚本,这个脚本在Flutter SDK里,路径为packages/flutter_tools/bin,有一个叫xcode_backend.sh的脚本,首先分析这个脚本:

if [[ $# == 0 ]]; then
  # Backwards-compatibility: if no args are provided, build.
  BuildApp
else
  case $1 in
    "build")
      BuildApp ;;
    "thin")
      ThinAppFrameworks ;;
    "embed")
      EmbedFlutterFrameworks ;;
  esac
fi

可以看到这个脚本有三个功能,分别是:

  1. build
  2. thin
  3. embed

把这个脚本拷贝到工程的目录,运行

  1. 第一步
$/bin/sh xcode_backend.sh build

然后你会发现有报错,如下:

ERROR: Unknown FLUTTER_BUILD_MODE: .
Valid values are 'Debug', 'Profile', or 'Release' (case insensitive).
This is controlled by the FLUTTER_BUILD_MODE environment varaible.
If that is not set, the CONFIGURATION environment variable is used.

这是因为少了一些环境变量,要把这些变量加上:

export FLUTTER_BUILD_MODE="" //有三个值:Debug  Profile   Release
export FLUTTER_ROOT="" //Flutter SDK的目录
export FLUTTER_APPLICATION_PATH=""  //工程目录
export SOURCE_ROOT="${FLUTTER_APPLICATION_PATH}/.ios/Flutter"  //Flutter iOS代码的目录
export FLUTTER_TARGET="lib/main.dart"  //dart代码
export FLUTTER_BUILD_DIR="build" //build生成的路径
export ARCHS="armv7 arm64" //Flutter打包的Framework要支持的平台
  1. 第二步
$/bin/sh xcode_backend.sh thin

同样也要加上环境变量:

export SOURCE_ROOT=".../.ios/Flutter" //Flutter iOS代码的目录
export ARCHS="armv7 arm64" //Flutter打包的Framework要支持的平台
export TARGET_BUILD_DIR="${SOURCE_ROOT}" //build生成的路径
export app_path="${TARGET_BUILD_DIR}/Flutter" //Flutter打包的Framework所在的路径
export frameworks_dir="${app_path}"  //Flutter打包的Framework所在的路径

综上,要加的环境变量如下:

export FLUTTER_BUILD_MODE="" //有三个值:Debug  Profile   Release
export FLUTTER_ROOT="" //Flutter SDK的目录
export FLUTTER_APPLICATION_PATH=""  //工程目录
export SOURCE_ROOT="${FLUTTER_APPLICATION_PATH}/.ios/Flutter"  //Flutter iOS代码的目录
export FLUTTER_TARGET="lib/main.dart"  //dart代码
export FLUTTER_BUILD_DIR="build" //build生成的路径
export ARCHS="armv7 arm64" //Flutter打包的Framework要支持的平台
export TARGET_BUILD_DIR="${SOURCE_ROOT}" //build生成的路径
export app_path="${TARGET_BUILD_DIR}/Flutter" //Flutter打包的Framework所在的路径
export frameworks_dir="${app_path}"  //Flutter打包的Framework所在的路径

运行的命令如下:

$/bin/sh xcode_backend.sh build
$/bin/sh xcode_backend.sh thin

生成产物在.../.iOS/Flutter中查看,如果想修改生成产物的路径,修改脚本里derived_dir的值,如下:

  local derived_dir="${SOURCE_ROOT}/Flutter/Flutter"
  if [[ -e "${project_path}/.ios" ]]; then
    derived_dir="${project_path}/.ios/Flutter/Flutter"
  fi
flutter --suppress-analytics build aot --output-dir=build/aot --target-platform=ios --target=lib/main.dart --release --ios-arch=arm64 --extra-gen-snapshot-options="--dwarf_stack_traces,--print-snapshot-sizes,--print_instructions_sizes_to=build/aot.json"
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容