Android开发日常之gradle

学无止境,有一技旁身,至少不至于孤陋寡闻。
随着我们工作阅历的提升,除了基本的业务开发,也需要提升我们自身在开发效能方面的一些储备与笔记。

Android开发日常之gradle
Android开发日常之adb
Android开发日常之git
Android开发日常之shell alias

在Android开发中在项目根目录、app或者其他module中我们都能看到build.gradle 这个文件,我们也知道Android项目的编译和运行都是通过gradle来实现,需要引入第三方库时就找到对应项目的build.gradle 中按照集成文档修修改改引入即可,有可能也不会过多的去关注,这里简单介绍下关于在Android开发中gradle的使用。

  1. 调整gradle的编译参数(gradle.properties文件中配置)
    内存配置:

    org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

    • 堆的内存分配用-Xms和-Xmx
      1. Xms分配堆最小内存,默认为物理内存的1/64;
      2. Xmx分配最大内存,默认为物理内存的1/4。
    • 非堆内存分配用-XX:PermSize和-XX:MaxPermSize
      1. XX:PermSize分配非堆最小内存,默认为物理内存的1/64;
      2. XX:MaxPermSize分配最大内存,默认为物理内存的1/4。

    守护进程
    org.gradle.daemon=true
    并行编译
    org.gradle.parallel=true
    开启缓存
    android.enableBuildCache=true
    开启孵化模式
    org.gradle.configureondemand=true
    更多配置信息,移步Gradle官方文档

  2. 推荐引用固定版本依赖库

     dependencies { 
       compile 'com.google.code.gson:gson:2.2.1' //推荐写法
     // compile 'com.google.code.gson:gson:2.+' // 不推荐写法
    }
    

    虽然带+号的引用可以保证库是最新的,但更新的新库有没有更改库逻辑而带来的bug是未知的。

  3. module、jar及aar的依赖方式

     implementation project(':commonlibrary')
     implementation files('libs/alipaysdk.jar')
     implementation(name: 'xpay-1.0.1', ext: 'aar')
    
    • module生成jar
      def ccLibName = 'cc-1.0.1.jar'
      task makeJar(type: Copy) {
          //删除存在的
          delete 'build/libs/'+ccLibName
          //设置拷贝的文件
          from('build/intermediates/packaged-classes/release/')
          //打进jar包后的文件目录
          into('build/libs/')
          //将classes.jar放入build/libs/目录下
          //include ,exclude参数来设置过滤
          include('classes.jar')
          rename ('classes.jar',ccLibName)
      }
      makeJar.dependsOn(build)
      
    • module生成aar(默认编译会生成aar,此处更改aar生成名称)
      buildTypes {
       release {
           ...
           ...
           android.libraryVariants.all { variant ->
               if(variant.name.equalsIgnoreCase("release")) {
                   variant.outputs.all { output ->
                       def f = output.outputFileName
                       if (f != null && f.endsWith('.aar')) {
                           def fileName = "cc-v${defaultConfig.versionName}.aar"
                           output.outputFileName = fileName
                       }
                   }
               }
           }
       }
      }
      
  4. 用exclude关键字解决依赖库冲突问题
    如我们在Android项目中集成某个第三方库时,可能第三方库也会引入某个本地已经引入的库,所以就会存在引入多版本的依赖库。

    • 移除整个组织的库
      compile ('com.facebook.fresco:animated-webp:0.13.0') { 
             exclude group: 'com.android.support' // 仅仅写组织名称
      }
      
    • 精确移除某个指定库
      compile('com.android.support:appcompat-v7:23.2.0') {
            exclude group: 'com.android.support', module: 'support-annotations' // 写全称
            exclude group: 'com.android.support', module: 'support-compat'
            exclude group: 'com.android.support', module: 'support-v4'
            exclude group: 'com.android.support', module: 'support-vector-drawable'
      }
      

    如何产看项目中的第三方库的依赖关系?
    执行以下命令行:(如何你想查看某个module的依赖关系,此处的app使用你的module名来替换即可

    • Windows:
      gradlew :app:dependencies > dependencis.txt
    • MAC:
      ./gradlew :app:dependencies > dependencis.txt
  5. 设置java版本

    • 如果是在某个module中设置,那么就在对应module的build.gradle文件中配置:
      android {
         compileOptions {
             sourceCompatibility JavaVersion.VERSION_1_8
             targetCompatibility JavaVersion.VERSION_1_8
         }
      }
      
    • 如果想要做全局配置,那么就在根目录的build.gradle中配置:
      allprojects {
         repositories {
            jcenter()
         }
        tasks.withType(JavaCompile) {
           sourceCompatibility = JavaVersion.VERSION_1_8
           targetCompatibility = JavaVersion.VERSION_1_8
        }
      }
      
  6. 在build.gradle中设置productFlavors

    android {  
          productFlavors {
              baidu {
                  manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
              }  
              xiaomi {
                  manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
              }
          }  
      }
    
  7. assemble是Gradle中的编译打包命令

    • 打包baidu渠道的release版本
      gradlew assembleBaiduRelease
    • 打包baidu渠道的debug版本
      gradlew assembleBaiduDebug
    • 生成baidu渠道的Release和Debug版本
      gradlew assembleBaidu
    • 打包全部渠道Release版本
      gradlew assembleRelease
  8. 为各渠道设置各自的配置信息

    android {  
           productFlavors {
               baidu {
                   applicationId "com.liujc.demo.baidu"
                   manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu",
                                          APP_NAME :  "app应用01",  //app名称
                                          ]
                   buildConfigField "String", "API_APP_ID", "\"10001\""
               }  
               xiaomi {
                   applicationId "com.liujc.demo.xiaomi"
                   manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi",
                                          APP_NAME :  "app应用02",  //app名称
                                          ]
                   buildConfigField "String", "API_APP_ID", "\"10002\""
               }
           }  
       }
    

    如何使用?
    如上的applicationIdmanifestPlaceholders 中信息在AndroidManifest中使用如下:

      android:label="${APP_NAME}"
      <uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" />
    

    buildConfigField 中的参数在代码中使用BuildConfig.API_APP_ID

  9. Android Studio 为多渠道执行自定义名称打包命令:

    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                applicationVariants.all { variant ->
                    variant.outputs.each { output ->
                        def outputFile = output.outputFile
                        if (outputFile != null && outputFile.name.endsWith('.apk')) {
                            // 计划输出apk名称为App_V1.0.0_baidu.apk
                            def fileName = "App_V${variant.productFlavors.versionName}_${variant.productFlavors.name}.apk"
                            output.outputFile = new File(outputFile.parent, fileName)
                        }
                    }
                }
    

    下面是多渠道配置:

    android {  
        productFlavors {
            baidu {
                applicationId "com.liujc.demo.baidu"
                versionCode 1
                versionName "1.0.0"
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu",
                                       APP_NAME :  "app应用01",  //app名称
                                       ]
                buildConfigField "String", "API_APP_ID", "\"10001\""
            }  
            xiaomi {
                versionCode 2
                versionName "1.0.1"
                applicationId "com.liujc.demo.xiaomi"
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi",
                                       APP_NAME :  "app应用02",  //app名称
                                       ]
                buildConfigField "String", "API_APP_ID", "\"10002\""
            }
        }  
    }
    

    打包成功后你会发现包名为:App_V[1.0.0]_[baidu].apk ,这不是我想要的啊,怎么都多了个中括号呢,修改打包代码:

     proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                 applicationVariants.all { variant ->
                     variant.outputs.each { output ->
                         def outputFile = output.outputFile
                         if (outputFile != null && outputFile.name.endsWith('.apk')) {
                             // 计划输出apk名称为App_V1.0.0_baidu.apk
                             def fileName = "App_V${variant.productFlavors[0].versionName}_${variant.productFlavors[0].name}.apk"
                             output.outputFile = new File(outputFile.parent, fileName)
                         }
                     }
                 }
    

    再重新打包,成功后发现包名为:App_V1.0.0_baidu.apk OK了。

  10. 打包时相关属性介绍

    name:build type的名字
    applicationIdSuffix:应用id后缀
    versionNameSuffix:版本名称后缀
    debuggable:是否生成一个debug的apk
    minifyEnabled:是否混淆
    proguardFiles:混淆文件
    signingConfig:签名配置
    manifestPlaceholders:清单占位符
    shrinkResources:是否去除未利用的资源,默认false,表示不去除。
    zipAlignEnable:是否使用zipalign工具压缩。
    multiDexEnabled:是否拆成多个Dex
    multiDexKeepFile:指定文本文件编译进主Dex文件中
    multiDexKeepProguard:指定混淆文件编译进主Dex文件中


以下开发中开发中常用的gradle命令

  1. 生成Android项目的依赖文件并导出
    gradlew :app:dependencies > dependencis.txt

  2. 查看编译日志详细信息
    gradlew compileDebugSource --stacktrace -info

  3. 输出项目debug编译日志
    gradlew assembleDebug --info>log2.txt

  4. 获取构建报告,以HTML的形式展示。
    gradle build -profile
    gradle build -x lint 在Task Execution(任务执行)中去掉lint任务,节省Gradle构建时间。
    Tips:使用Android Studio任务栏直接点击运行按钮是不能去掉lint任务的,所以为了方便构建后安装应用,可以使用 gradle installDebug -x lint 命令。

  5. Clean命令

    mac:
    ./gradlew clean build --info > cleanlog.log
    
    windows:
    gradlew.bat clean build --info > cleanlog.log
    
  6. 使用help
    ./gradlew --help

  7. build 某个指定 module
    AS 推荐的结构是 multiple project 结构,即一个 project 下,管理多个 module,如果每次都要 build 全部的 project 的话,有点浪费时间,则可以使用 -p module 参数,其中 module 是你要 build 的 module:

    $ ./gradlew -p app clean build
    $ ./gradlew -p app/app_module assembledebug
    
  8. 明确指定不执行某个 task
    Gradle 的命令存在依赖,例如 build task,是依赖于一系列的其他的 task,如果想要指定不执行某个 task,则可以使用 -x task 参数,其中 task 是要忽略的那个,这个参数可以传递多次。

    $ ./gradlew build -x test -x lint
    
  9. 执行多模块任务
    当你在工程根目录下通过命令行窗口运行任务时,Gradle会找出所有模块中的同名任务,并运行它们。比如,你有一个app模块和一个Android Wear模块,运行./gradlew assembleDebug将会为app模块和Android Wear模块都构建一个debug版本。如果你切换到模块的目录下,Gradle将只会运行该模块的任务,即使你在工程根目录中运行Gradle Wrapper。比如,在Android Wear模块的目录运行./gradlew assembleDebug,只会构建Android Wear模块。

    切换目录的方式来运行模块的任务是比较繁琐的。另一个方式是可以使用模块名称来预处理任务名称,使运行任务只在那个模块上运行。比如只想构建Android Wear模块,可以使用如下命令:

    ./gradlew :wear:assembleDebug
    ./gradlew -p app/app_module assembledebug
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容