The Android Developer Challenge is back! Submit your idea before December 2.

Android Studio 和 Android Gradle 插件的已知问题

此页面记录了 Android Studio 和 Android Gradle 插件的当前已知问题。要报告本页中未提及的问题,请参阅报告错误

Android Studio 的已知问题

  • 扫描基于 C++ 的项目时出现内存不足错误:如果 Gradle 扫描的项目在同一驱动器上的多个位置都有 C++ 代码,则扫描会涵盖这些位置的首个共通目录下的所有目录。扫描大量目录和文件可能会导致出现内存不足错误。

    如果您在项目中遇到这种情况,建议您使用 Android Studio 3.2。要详细了解此问题,请参阅与该问题相关的错误

  • Espresso 测试记录器编译失败:当您尝试对使用 Espresso 测试记录器的项目进行编译时,编译失败,并显示错误消息 Execution failed for task ':app:compileDebugAndroidTestJavaWithJavac'。此问题会影响使用 3.0.2 版或更高版 espresso-core 依赖项的 Android Studio 3.2 以下版本。此问题不会影响 Android Studio 3.2 及更高版本。

    如果您使用的是 Android Studio 3.1 或更低版本,则可通过以下方法解决此问题:将 3.0.2 以下版本的 espresso-core 设为一个依赖项,或添加单独的 rules 依赖项(如 Espresso 设置说明中所示)。

  • @RestrictTo lint 检查在 Windows 计算机上无法正常工作:在 Android Studio 2.3 中,@RestrictTo lint 检查在 Windows 计算机上无法正确触发错误消息。

  • 名称中带有括号的虚拟设备无法运行:在 Android Studio 2.2 版中,虽然您可以在虚拟设备的名称中添加括号(事实上,对于 Android TV 之类的设备,其名称中会自动包含括号),但无法运行其名称中包含括号的虚拟设备。要避免此问题,请修改虚拟设备以从名称中移除所有“(”和“)”字符。

    从 Android Studio 2.3 开始,此问题已得到解决

  • Instant Run 与 Jack 不兼容:Instant Run 目前与 Jack 编译器不兼容,因此在使用 Jack 编译器的项目中,它会处于停用状态(只有在使用 Java 8 语言功能时,才需要使用 Jack 编译器)。

  • 需要应用类文件的工具和库与 Jack 不兼容:读取 .class 文件的各种工具(如 JaCoCo、Mockito 和一些 lint 检查)目前与 Jack 编译器不兼容。

  • 当项目位于 Linux 中的 NTFS 文件系统上时,Gradle 编译系统无法清除输出文件夹:由于 NTFS 的文件锁定行为,在 Windows 计算机上,Android Studio 会在编制索引之前自动将相关类的 JAR 文件复制到其他位置,以便后续的 Gradle 编译可以清除并更改编译/树。如需了解详情,请参阅问题 202297。在 Linux 或 OSX 计算机上使用 NTFS 时,系统不会启用此行为,但您可以通过取消注释下面这行代码,在 idea.properties 文件中手动指定此行为:

    idea.jars.nocopy=false

  • Mac 性能问题:Android Studio 2.2 捆绑的 OpenJDK 1.8.0_76 在 Mac 上存在一些问题。如问题 203412IDEA-144261 中所述,以非原生分辨率使用外部 4K 显示器可能会对渲染性能产生负面影响,甚至可能导致 IDE 停止响应。此外,正如问题 223749IDEA-158500 中所报告的那样,滚动操作在 Mac 10.12 (Sierra) 上非常敏感。

  • Gradle 同步失败:管道无效:问题在于,Gradle 守护进程会尝试使用 IPv4 而非 IPv6。

    • 解决方法 1:在 Linux 上,将以下内容放入 ~/.profile~/.bash_profile 中:
      export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true"
    • 解决方法 2:在 Android Studio 的 vmoptions 文件中,将 -Djava.net.preferIPv6Addresses=true 行更改为 -Djava.net.preferIPv6Addresses=true。要了解详情,请参阅网络 IPv6 用户指南
  • Gradle 同步或 SDK 管理器发生“对等设备未经过身份验证”(peer not authenticated) 错误:此类错误的根本原因在于 $JAVA_HOME/jre/lib/certificates/cacerts 中缺少证书。要解决此类错误,请按以下步骤操作:

    • 如果您使用了网络代理,请尝试直接连接。如果直接连接有效,那么为了通过代理进行连接,您可能需要使用 keytool 将代理服务器的证书添加到 cacerts 文件中。
    • 重新安装受支持且未经修改的 JDK。请注意,有一个会影响 Ubuntu 用户的已知问题会导致空的 /etc/ssl/certs/java/cacerts。要解决此问题,请在命令行中执行以下命令:
      $ sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure
  • 从 Android Studio 运行时,JUnit 测试在类路径中找不到资源:如果您的 Java 模块使用了特定的资源文件夹,那么从 IDE 运行测试时将找不到这些资源。您可以从命令行使用 Gradle 运行测试。您也可以从 IDE 执行 Gradle check 任务。请参阅问题 64887 了解详情。

    出现此问题的原因是,从 IntelliJ 13 起,您只能将一个文件夹用作类路径。IntelliJ 的编译工具会将所有资源复制到该编译文件夹中,但 Gradle 不会复制这些资源。

    • 解决方法 1:从 IDE 运行 Gradle check 任务,而不是运行单元测试。
    • 解决方法 2:更新编译脚本以手动将资源复制到编译文件夹中。如需了解详情,请参见此处的第 13 条评论
  • 运行 JUnit 测试可能会编译两次代码:创建新项目时,系统可能会在 Make 和 Gradle-aware Make 这两个“发布前”步骤中创建模板 JUnit 配置。然后,系统会将此配置传播到所有已创建的 JUnit 运行配置。

    • 要为当前项目解决此问题,请依次点击 Run > Edit Configurations,然后将默认的 JUnit 配置更改为仅包含 Gradle-aware Make 步骤。
    • 要为今后的所有项目解决此问题,请依次点击 File > Close Project。您应该会看到欢迎屏幕。然后,依次点击 Configure > Project Defaults > Run Configurations,并将 JUnit 配置更改为仅包含 Gradle-aware Make 步骤。
  • 某些测试运行配置无效:右键点击某个测试方法时,并非所有可用的运行配置都有效。具体而言,以下配置无效:

    • Gradle 运行配置(其图标为 Gradle 徽标)无效。
    • JUnit 运行配置(其图标不带绿色的 Android)不适用于插桩测试(此类测试无法在本地 JVM 上运行)。
    Android Studio 还会记住在给定上下文中创建的运行配置(例如,右键点击特定类或方法),并且以后不会为您提供在其他配置中运行的选项。要解决此问题,请依次点击 Run > Edit Configurations,然后移除错误创建的配置。

  • Linux 和 Awesome WM 3.4:Android Studio 0.8.3 及更高版本可能无法与“Awesome WM”窗口管理器 3.4 版正常搭配使用。要解决此问题,请升级到 Awesome WM 3.5 版。

  • 键盘输入冻结 - Linux 上的“iBus”问题:Linux 上的 iBus 守护进程与 Android Studio 之间存在一些已知的互动问题。在某些情况下,IDE 会停止响应键盘输入或开始输入随机字符。此错误由 iBus 和 XLib + AWT 之间的同步缺漏而引发,并且已报告给上游的 JetBrainsiBus 开发者。此问题目前有三种解决方法:

    • 解决方法 1:强制 iBus 进入同步模式。在启动 Android Studio 之前,请在命令行中运行以下命令:
      $ IBUS_ENABLE_SYNC_MODE=1 ibus-daemon -xrd
    • 解决方法 2:在 Android Studio 中停用 iBus 输入方式。要仅为 Android Studio 停用 iBus 输入方式,请在命令行中运行以下命令:
      $ XMODIFIERS= ./bin/studio.sh
      这样做只会为 Android Studio 停用输入法,而不会影响您可能正在运行的任何其他应用。请注意,如果您在 Android Studio 处于运行状态时重启 iBus 守护进程(例如,通过运行 ibus-daemon -rd),则相当于为所有其他应用停用了输入法,并可能导致 Android Studio 的 JVM 崩溃并出现分段错误。
    • 解决方法 3:仔细检查快捷键设置,确保未将下一种输入法的快捷键设置为 Control+Space,因为这也是 Android Studio 中的代码补全快捷键。Ubuntu 14.04 (Trusty) 中的默认快捷键是 Super+Space,但也可能沿用了先前版本的设置。要检查快捷键设置,请在命令行中运行 ibus-setup 以打开“IBus Preferences”窗口。在 Keyboard Shortcuts 下,选中 Next input method。如果它已被设为 Control+Space,请将其更改为 Super+Space 或您所选的其他快捷键。
  • Ubuntu 和 JAyatana:JAyatana 让 Java Swing 应用可与 Ubuntu 的 Unity 图形 shell 中的全局菜单集成。在某些情况下,Android Studio 可能会在 Unity 中遇到 NullPointerException,并显示一条类似如下的错误消息:

    java.lang.NullPointerException
        at com.jarego.jayatana.swing.SwingGlobalMenu.getSwingGlobalMenuWindowController(SwingGlobalMenu.java:204)
        at com.jarego.jayatana.swing.SwingGlobalMenu.installLockParentGlobalMenu(SwingGlobalMenu.java:160)
        at ...
    如需了解详情,请参阅问题 187179。由于此问题,较新版本的 Ubuntu 默认会停用 JAyatana。如果您遇到此问题,有两种可能的解决方法(有关详情,请参阅这篇 Stack Overflow 帖子):

    • 解决方法 1:运行 Android Studio 时取消设置 JAVA_TOOL_OPTIONS 环境变量。
    • 解决方法 2:卸载 JAYatana。
  • 调试原生代码时添加 Java 断点:当您的应用在原生代码的断点处暂停时,AutoDual 调试程序可能无法立即识别您设置的新 Java 断点。要避免此问题,请在启动调试会话之前或在 Java 断点处暂停应用时添加 Java 断点。如需了解详情,请参阅问题 229949

  • 退出原生调试程序:使用 AutoDual 调试程序调试 Java 和原生代码时,如果您通过 Java 代码进入原生函数(例如,调试程序在调用原生函数的某行 Java 代码处暂停执行,并且您点击 Step Into )并且希望返回到 Java 代码,请点击 Resume Program (而非 Step Out Step Over )。您的应用进程仍将处于暂停状态,因此请点击 your-module-java 标签页中的 Resume Program 将其恢复。如需了解详情,请参阅问题 224385

  • 呈现异常误报:具体的呈现错误消息为“The following classes could not be found: -android.support.v7.internal.app.WindowDecorActionBar”。尽管出现此错误消息,但布局预览依然是正确的,并且您可以安全地忽略此消息。

    此问题已在 Android Studio 2.0 预览版中得到修正。

  • macOS High Sierra 上的 Android 模拟器 HAXM:macOS High Sierra (10.13) 上的 Android 模拟器需要 HAXM 6.2.1+ 才能实现最佳的 macOS 兼容性和稳定性。不过,在 macOS 10.13 上安装 HAXM 等内核扩展的流程更繁琐一些。您需要按以下方式手动允许安装内核扩展:

    1. 首先,尝试通过 SDK 管理器安装最新版本的 HAXM。
    2. 在 MacOS 中,依次转到 System Preferences > Security and Privacy
    3. 如果您看到“System software from developer "Intel Corporation Apps" was blocked from loading”,请点击 Allow

    如需了解详情和解决方法,请参阅此 Apple 网页问题 62395878

Android Gradle 插件的已知问题

  • 在 Gradle 4.6 及更高版本中使用按需配置:如果您搭配 Gradle 4.6 及以上版本使用 Android Gradle 插件 3.0.x 或 3.1.x,则应停用按需配置,以避免一些不可预知的编译错误(如果您使用的是 Android Gradle 插件 3.2.0 或更高版本,则无需执行操作来停用按需配置)。

    gradle.properties 文件中停用按需配置,如下所示:

    org.gradle.configureondemand=false
        

    要在 Android Studio 设置中停用按需配置,请依次选择 File > Settings(在 Mac 上,则依次选择 Android Studio > Preferences),选择左侧面板中的 Compiler 类别,然后取消选中 Configure on demand 复选框。

    在 Android Studio 3.2 Beta 1 及更高版本中,用于启用按需配置的选项已被移除。

  • 多次加载 Android 插件 3.0.0 时出现项目同步错误:在一次编译中多次加载 Android 插件会导致出现项目同步错误。如果您有多个子项目,并且每个子项目的编译脚本类路径中都包含 Android 插件,则可能会发生这种情况。这是 Gradle 中新增的变体感知型 (variant-aware) 依赖项管理机制的一个局限,该机制尚无法处理来自不同类加载器的匹配属性。如果您使用的是 Android 插件 3.0.0 或更低版本,请将该插件升级到 Android 插件3.1.0 及更高版本,或者按照以下步骤解决此问题:

    • 多模块编译:请务必仅将 Android 插件添加到顶级 build.gradle 文件的编译类路径中,具体如下所示:

      // Additionally, make sure that you don't wrap this in a
          // subprojects block.
          buildscript {
              ...
              dependencies {
                  classpath 'com.android.tools.build:gradle:3.4.2'
              }
          }
          
    • 复合编译:对于主项目和使用了 Android 插件的每个包含的项目,您还需要确保编译脚本类路径完全相同。另外,还需要确保添加到 buildscript 代码块的类路径的顺序相同。例如,假设主项目的 build.gradle 文件中包含以下类路径依赖项:

      buildscript {
              ...
              dependencies {
                  classpath "com.android.tools.build:gradle:3.4.2"
                  classpath "me.tatarka:gradle-retrolambda:3.7.0"
              }
          }
          

      现在考虑一下复合编译中包含的另一个项目的 build.gradle 文件:

      buildscript {
              dependencies {
                  // Note that the order of plugins differs from that
                  // of the main project's build.gradle file. This results
                  // in a build error because Gradle registers this as a
                  // different classloader.
                  classpath "me.tatarka:gradle-retrolambda:3.7.0"
                  classpath "com.android.tools.build:gradle:3.4.2"
              }
          }
          
  • Firebase 插件 1.1.0 版导致出现 Guava 依赖项不匹配错误:Firebase 插件 1.1.0 版可能导致 Guava 依赖项不匹配,从而导致出现以下错误:

        Error:Execution failed for task ':app:packageInstantRunResourcesDebug'.
        com.google.common.util.concurrent.MoreExecutors.directExecutor()Ljava/util/concurrent/Executor;
        
    要修复此编译错误,请将以下内容添加到项目级 build.gradle 文件的 dependencies 代码块中:

    dependencies {
            classpath ('com.google.firebase:firebase-plugins:1.1.0') {
                        exclude group: 'com.google.guava', module: 'guava-jdk5'
            }
            ...
        }
        

    有关详情,请参阅问题 #63180002

  • 要使用 Protobuf,您必须将 Protobuf 插件升级到 0.8.2 或更高版本。

  • 不再支持第三方 android-apt 插件。您应该切换到内置注解处理器支持功能,该功能已经过改进,能以惰性方式解析依赖项。

  • JAR 签名(v1 方案)不支持包含回车符 (CR) 字符的文件名。(参阅问题 #63885809。)

API 变更

在 Android Gradle 插件 3.0.0 及更高版本引入的 API 变更中,部分功能被移除,因此您现有的编译可能会出现异常。插件的更高版本可能会引入新的公共 API 来替代失效的旧功能。

在编译时可能无法正常修改变体输出

新插件不支持使用 Variant API 来操纵变体输出,但仍然支持使用该 API 处理某些简单任务,例如在编译时更改 APK 名称,具体如下所示:

    // If you use each() to iterate through the variant objects,
    // you need to start using all(). That's because each() iterates
    // through only the objects that already exist during configuration time—
    // but those object don't exist at configuration time with the new model.
    // However, all() adapts to the new model by picking up object as they are
    // added during execution.
    android.applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = "${variant.name}-${variant.versionName}.apk"
        }
    }
    

不过,涉及访问 outputFile 对象的复杂任务已不再受支持。这是因为在配置阶段不会再创建专门针对特定变体的任务。这导致插件不能预先了解所有的输出,但也缩短了配置时间。

manifestOutputFile 不再可用

processManifest.manifestOutputFile() 方法不再可用,您在调用该方法时将会遇到以下错误:

    A problem occurred configuring project ':myapp'.
       Could not get unknown property 'manifestOutputFile' for task ':myapp:processDebugManifest'
       of type com.android.build.gradle.tasks.ProcessManifest.
    

您可以调用 manifestOutputFile() 来获取包含所有生成的清单的目录路径,而无需调用 processManifest.manifestOutputDirectory() 来获取每个变体的清单文件。然后,您可以找到相应清单,并对该清单运用您的逻辑。以下示例将在清单中动态更改版本代码:

    android.applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.processManifest.doLast {
                // Stores the path to the maifest.
                String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml"
                // Stores the contents of the manifest.
                def manifestContent = file(manifestPath).getText()
                // Changes the version code in the stored text.
                manifestContent = manifestContent.replace('android:versionCode="1"',
                        String.format('android:versionCode="%s"', generatedCode))
                // Overwrites the manifest with the new text.
                file(manifestPath).write(manifestContent)
            }
        }
    }