android-gradle记录

android-gradle记录


前篇


自定义任务 Task

gradle 中定义

1
2
3
4
task mylog() {
group = 'a_mytask' // 指定任务分组, 在 gradle 窗口中可以看到, 不指定默认在 other 分组中
println String.format("--- hello world") // 格式化字符串
}


构建指定任务

以构建 testapp 模块的 Release 版本为例, 也就是 :testapp:assembleRelease 任务.


命令行方式

1
2
3
4
5
6
7
8
9
E:\its_rummy\Rummy_AndroidStudio>gradlew :testapp:assembleRelease

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.1.1/userguide/command_line_interface.html#sec:command_line_wa
rnings

BUILD SUCCESSFUL in 7s
42 actionable tasks: 1 executed, 41 up-to-date

gui 方式

在 testapp 模块的 build.gradle 中加入自定义任务, 依赖上 assembleRelease 任务即可.

1
2
3
4
task a_buildApplication() {
group = "a_mytask"
dependsOn(":testapp:assembleRelease")
}


怎么获取任务名

直接 build 的时候可以看到执行的所有任务

1
2
3
4
> Task :testapp:assembleDebug UP-TO-DATE
> Task :testapp:assembleRelease UP-TO-DATE
> Task :testapp:assemble UP-TO-DATE
> Task :app:prepareLintJarForPublish UP-TO-DATE

去掉 任务

比如: 去掉 android 构建 apk 时的 verifyReleaseResources 任务

1
2
3
4
5
tasks.whenTaskAdded {task ->
if(task.name.contains("verifyReleaseResources")) {
task.enabled = false
}
}

自定义 插件 Plugin


执行多个命令行

参考: execute multiple commands from task - https://stackoverflow.com/questions/35561014/gradle-execute-multiple-commands-from-task

  • 错误姿势

    1
    2
    3
    4
    5
    task adbRestart(type: Exec) {
    workingDir "$projectDir"
    commandLine 'cmd', '/c', 'adb kill-server'
    commandLine 'cmd', '/c', 'adb start-server'
    }
  • 正确姿势

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    task adbRestart() {
    doLast {
    exec {
    workingDir "$projectDir"
    commandLine 'cmd', '/c', 'adb kill-server'
    }
    exec {
    workingDir "$projectDir"
    commandLine 'cmd', '/c', 'adb start-server'
    }
    }
    }

执行任务

先 cd 到 build.gradle 所在目录

  • 执行单个任务. 命令: gradle xxx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    E:\its_rummy\Rummy_AndroidStudio\app (master -> origin)
    $ D:\android-studio-3.4.2\gradle\gradle-5.1.1\bin\gradle a_ItsCopyJar

    > Configure project :app
    --- a_DelTempDir
    --- a_ItsCopyAAR
    --- a_unzip
    --- a_ItsCopyJar
    --- its build
    hello world 111

    > Task :app:lint
    Ran lint on variant release: 41 issues found
    Ran lint on variant debug: 41 issues found
    Wrote HTML report to file:///E:/its_rummy/Rummy_AndroidStudio/app/build/reports/lint-results.html
    Wrote XML report to file:///E:/its_rummy/Rummy_AndroidStudio/app/build/reports/lint-results.xml

    Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
    Use '--warning-mode all' to show the individual deprecation warnings.
    See https://docs.gradle.org/5.1.1/userguide/command_line_interface.html#sec:command_line_warnings

    BUILD SUCCESSFUL in 9s
    54 actionable tasks: 4 executed, 50 up-to-date
  • 执行多个任务. 命令: gradle xxx yyy


gradlew 构建 processDebugManifest 显示 报错信息

模块a 引用 模块b 时, 合并 Manifest 报错, 但是给的信息很有先, 只有 Manifest merger failed with multiple errors

查看具体的信息可以在 项目的根目录 (模块目录的上一级目录) 执行: gradlew processDebugManifest --stacktrace -info, 然后搜索关键之 error, fail 之类的就可以找到错误信息

1
2
3
4
5
6
7
8
9
10
11
12
E:\its_rummy\Rummy_AndroidStudio>gradlew processDebugManifest --stacktrace -info
[:app] E:\its_rummy\Rummy_AndroidStudio\app\build\intermediates\library_manifest\debug\AndroidManifest.xml:50:5-76 Warning:
Element uses-permission#android.permission.ACCESS_WIFI_STATE at [:app] AndroidManifest.xml:50:5-76 duplicated with element declared at [:app] AndroidManifest.xml:42:5-76
E:\its_rummy\Rummy_AndroidStudio\testapp\src\main\AndroidManifest.xml:7:9-43 Error:
Attribute application@icon value=(@mipmap/ic_launcher) from AndroidManifest.xml:7:9-43
is also present at [:app] AndroidManifest.xml:58:9-40 value=(@mipmap/app_icon).
Suggestion: add 'tools:replace="android:icon"' to <application> element at AndroidManifest.xml:5:5-22:19 to override.
E:\its_rummy\Rummy_AndroidStudio\testapp\src\main\AndroidManifest.xml:11:9-40 Error:
Attribute application@theme value=(@style/AppTheme) from AndroidManifest.xml:11:9-40
is also present at [:app] AndroidManifest.xml:60:9-50 value=(@style/UnityThemeSelector).
Suggestion: add 'tools:replace="android:theme"' to <application> element at AndroidManifest.xml:5:5-22:19 to override.

参考: Manifest merger failed with multiple errors, see logs问题处理 - https://blog.csdn.net/Picasso_L/article/details/53085299


gradle 中写代码逻辑

gradle 在执行脚本时,会优先执行 buildscript 代码块中的内容,然后才会执行剩余的 build 脚本。

所以在 buildscript 块中, 使用外部定义的变量是就会报错, 如:

1
2
3
4
def aaa = {}
buildscript {
println(aaa)
}

会报错; Could not get unknown property 'aaa'


执行某个任务

  • Gradle高阶-Task执行 - https://juejin.cn/post/6844904016778903560

  • 如果 cd 到项目根目录, 就需要带上模块

    1
    gradlew :Hello:assembleRelease --stacktrace
    • 表示执行 Hello 模块的 assembleRelease 任务

      • assembleRelease 在 as 中看到的只是 assemble, release 指的是 gradle 中的构建类型, 在任务中拼接起来就是 assembleRelease

        1
        2
        3
        4
        5
        6
        7
        android {
        buildTypes {
        release {

        }
        }
        }
      • 如果自定义 构建类型 wilker, 则需要在 所有依赖的工程的 gradle 中都添加这个类型

        1
        2
        3
        4
        5
        6
        7
        android {
        buildTypes {
        wilker {

        }
        }
        }

        执行任务命令则是

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
                    gradlew :Hello:assembleWilker --stacktrace



        ---

        ### 定义全局变量

        - 在 *gradle.properties* 中定义的变量, 可以在项目中的所有模块中使用

        ![image-20230405131558885](https://pic05.wilker.cn/20230405131600-985.webp)



        ---

        ### 在项目中引入任意目录下的模块

        - 这个引入配置在 *settings.gradle* 中配置, 比如引入 *:apicocos* 模块

        ```json
        include ':apicocos'
        project(':apicocos').projectDir = new File("E:/workspace/cocos/TestAtlas/build/android-001/proj/apicocos")
  • 就可以在该项目中使用该模块的资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        dependencies {
    implementation project(':apicocos')
    }



    ---

    ### 读取命令行参数

    - 参考: 向gradle命令任务传递命令行参数的不同方法 - https://juejin.cn/post/7120878611376111646



    1. 在 gradle 中读取参数

    ```json
    if (project.hasProperty("flagSo11")) {
    println("------------ flagSo11:")
    println(flagSo11)
    }
    if (project.hasProperty("flagSo22")) {
    println("------------ flagSo22:")
    println(flagSo22)
    }
  1. 命令行中加入参数

    1
    $ gradlew :MyGame:assembleRelease --stacktrace -PflagSo11=aaa -PflagSo22=bbb
    • 结果

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
              ------------ flagSo11:
      aaa
      ------------ flagSo22:
      bbb



      ---

      ### 命令行构建 apk

      1. 生成 wrapper

      ```json
      set JAVA_HOME=C:\Users\asd01\Desktop\Java\jdk1.8.0_144
      set ANDROID_SDK_ROOT=C:\Users\asd01\Desktop\android_sdk
      set GRADLE_ROOT=C:\Users\asd01\Desktop\gradle-6.7.1

      %GRADLE_ROOT%\bin/gradle wrapper
  2. 执行任务, 也就是构建 apk 等任务 (不能和生成 wrapper 同时执行, 不知道为啥)

    1
    2
    3
    4
    5
    set JAVA_HOME=C:\Users\asd01\Desktop\Java\jdk1.8.0_144
    set ANDROID_SDK_ROOT=C:\Users\asd01\Desktop\android_sdk
    set GRADLE_ROOT=C:\Users\asd01\Desktop\gradle-6.7.1

    gradlew :launcher:bundleRelease --stacktrace --info
    • 格式为 :模块名:任务名
  3. 清楚

    1
    gradlew clean

gradle 命令输出日志

  • 有两级输出重定向, 第二级才有报错堆栈信息

    1
    $ gradlew :testapp:assembleRelease --stacktrace > "c:/aaa.txt" 2> "c:/bbb.txt"

踩坑

maven http 链接不安全

报错: redirect to a secure protocol (like HTTPS)

原因是 gradle 7.0+ 之后, maven 仓库的链接默认要求是 https, 如果是 http, 需要配置安全性字段 allowInsecureProtocol = true

1
2
3
4
5
6
7
8
buildscript {
repositories {
maven {
allowInsecureProtocol = true // 配置安全性
url 'http://192.168.1.233:8081/repository/maven_central/'
}
}
}

gradle 插件要求使用 Java 11

报错: Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8

解决办法, 下载 jdk11, 然后修改 as 配置指向 jdk11

image-20220628142400946


gradle 引入错误 material

  • 报错: Can't determine type for tag '<macro name="m3_comp_assist_chip_container_shape">?attr/shapeAppearanceCornerSmall</macro>'

  • 解决办法: 将 material 版本降低一点即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
        implementation 'com.google.android.material:material:1.8.0'
    // 修改为
    implementation 'com.google.android.material:material:1.0.0'



    ---

    #### 转换 activity 报错

    - 报错: `Failed to transform activity-1.8.0.aar`
    - 解决办法:
    1. 将 项目级 和全局的 gradle.properties 配置里增加 `android.enableJetifier=false`
    2. 引入错误库, 将 `implementation 'androidx.constraintlayout:constraintlayout:2.1.4'`



    ---

    #### 报错: AAPT2

    - 报错: AAPT2 aapt2-4.1.0-6503028-windows Daemon #0: Unexpected error during link, attempting to stop daemon.

    - 解决办法: 项目级 build.gradle 升级 构建工具

    ```json
    dependencies {
    classpath 'com.android.tools.build:gradle:4.2.0'
    classpath 'com.google.gms:google-services:4.3.3'
    }
  • https://stackoverflow.com/questions/67233807/android-gradle-build-error-aapt2-aapt2-4-1-0-6503028-windows-daemon-0-unexpec


主题报错

  • 报错: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
  • 解决办法: 将 AppCompatActivity 修改为 Activity

样式 xml 报错


创建 handler 报错

  • 报错: Can’t create handler inside thread that has not called Looper.prepare()

  • 原因:非主线程中没有开启Looper,而Handler对象必须绑定Looper对象需要调用Looper.prepare()来给线程创建一个消息循环,调用Looper.loop()来使消息循环起作用。

  • 解决办法: 在主线程中创建即可

    1
    2
    3
    4
    Tools.runOnUiThread(() -> {
    // 执行代码
    SplashHelper.setIns(new SplashNew());
    });

构建时检查报错找不到 Vendor 类