您的位置:首页 > 移动开发 > Android开发

[Android]_[gradle]_[gradlew.bat报错KotlinNullPointerException]

2020-05-10 04:09 2923 查看

场景

  1. 在构建
    Android App
    的时候,最常用的构建工具就是
    gradle
    ,这个工具使用一种
    .gradle
    的文本进行任务描述. 最常见的就是根据
    build.gradle
    的配置指定使用
    gradle
    的版本。接着根据项目的配置下载所依赖的
    jar
    包并编译.
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
}
  1. 我对
    gradle
    还没系统的学习过. 今天在编译
    google
    的例子项目时在项目根目录使用命令行运行
    gradlew.bat
    就报以下错误. 项目都是用的
    java
    代码编写,何来的
    kotlin
    错误?
* What went wrong:
A problem occurred configuring project ':app'.
> kotlin.KotlinNullPointerException (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

说明

  1. 注意这个
    gradle
    是针对
    android
    的构建插件,而
    android
    目前官方推荐使用
    kotlin
    语言开发, 所以
    gradle
    插件需要集成
    kotlin
    包也不奇怪. 我们根据提示运行增加参数
    gradlew.bat --stacktrace
    . 在命令行运行输出了一段比较长的错误, 其中就有
    KotlinNullPointerException
    抛出的源码位置. 可见在文件
    DataBindingCompilerArguments.kt
    的 170 行的
    createArguments
    方法抛出了异常. 而这个 170 行就是
    sdkDir = globalScope.sdkComponents.getSdkFolder()!!,
    获取
    SDK
    目录时抛出的异常。很明显了,就是获取不到
    Android SDK
    目录.
Caused by: kotlin.KotlinNullPointerException
at com.android.build.gradle.internal.tasks.databinding.DataBindingCompilerArguments$Companio
n.createArguments(DataBindingCompilerArguments.kt:170)
  1. 那么设置

    Android SDK
    我所知道的有3种方法.

    [ol] 在我的电脑右键属性->高级->环境变量->用户变量增加
    ANDROID_HOME
    作为变量名,
    E:\software\Android\sdk
    你自己的
    Android SDK
    安装目录. 这个变量值在所有新建的命令行有效.
  2. 在当前命令行输出回车
    set ANDROID_HOME=E:\software\Android\sdk
    ,那么这个变量值在当前的命令行有效.
  3. 在当前的项目目录增加一个
    local.properties
    的文本文件,增加文本值
    sdk.dir=E\:\\software\\Android\\sdk
    即可.
  • 设置完之后这个编译步骤就会成功,当然剩下的下载

    jar
    包可能由于网络不通造成下载失败就是另外的问题了。

  • 至于这个文件

    DataBindingCompilerArguments.kt
    源码只能通过
    google
    搜索,
    bing
    是搜不到的. 至于这个类所在的包
    com.android.build.gradle.internal.tasks.databinding
    和它所在的
    jar
    gradle
    下载的包
    gradle-3.6.2.jar
    里, 当然根据依赖的
    gradle
    插件版本判断,我这里是
    com.android.tools.build:gradle:3.6.2
    . 所以在
    3.6.2
    目录下.

  • [/ol]
    C:\Users\用户名\.gradle\caches\modules-2\files-2.1\com.android.tools.build\gradle\3.6.2\a5e817cf4833326b12f3e599f97486a04fe62756\gradle-3.6.2.jar

    顺便说一下,

    gradle
    下载的第三方
    jar
    ,包括
    gradle
    android
    插件包是在以下目录里:

    C:\Users\用户名\.gradle\caches\modules-2\files-2.1

    而安装的

    gradle
    ,注意不是插件包, 是在以下目录:

    C:\Users\用户名\.gradle\wrapper\dists
    1. 我们来看看这个项目的
      .gitigore
      忽略设置, 就包含了当前项目的
      local.properties
      文件,所以这个项目里这个文件的是提交不了的.
    *.iml
    .idea
    .gradle
    /local.properties
    .DS_Store
    build/
    /captures
    .externalNativeBuild

    源码参考

    DataBindingCompilerArguments.kt

    /*
    * Copyright (C) 2018 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    *      http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    
    package com.android.build.gradle.internal.tasks.databinding
    
    import android.databinding.tool.CompilerArguments
    import com.android.build.gradle.internal.scope.InternalArtifactType
    import com.android.build.gradle.internal.scope.InternalArtifactType.DATA_BINDING_BASE_CLASS_LOG_ARTIFACT
    import com.android.build.gradle.internal.scope.InternalArtifactType.DATA_BINDING_DEPENDENCY_ARTIFACTS
    import com.android.build.gradle.internal.scope.InternalArtifactType.DATA_BINDING_LAYOUT_INFO_TYPE_MERGE
    import com.android.build.gradle.internal.scope.InternalArtifactType.DATA_BINDING_LAYOUT_INFO_TYPE_PACKAGE
    import com.android.build.gradle.internal.scope.InternalArtifactType.FEATURE_DATA_BINDING_BASE_FEATURE_INFO
    import com.android.build.gradle.internal.scope.InternalArtifactType.FEATURE_DATA_BINDING_FEATURE_INFO
    import com.android.build.gradle.internal.scope.VariantScope
    import com.android.build.gradle.options.BooleanOption
    import org.gradle.api.file.Directory
    import org.gradle.api.file.RegularFile
    import org.gradle.api.provider.Provider
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.InputFiles
    import org.gradle.api.tasks.Internal
    import org.gradle.api.tasks.Optional
    import org.gradle.api.tasks.OutputDirectory
    import org.gradle.api.tasks.OutputFile
    import org.gradle.api.tasks.PathSensitive
    import org.gradle.api.tasks.PathSensitivity
    import org.gradle.process.CommandLineArgumentProvider
    import java.io.File
    
    /**
    * Arguments passed to data binding. This class mimics the [CompilerArguments] class except that it
    * also implements [CommandLineArgumentProvider] for input/output annotations.
    */
    @Suppress("MemberVisibilityCanBePrivate")
    class DataBindingCompilerArguments constructor(
    
    @get:Input
    val incremental: Boolean,
    
    @get:Input
    val artifactType: CompilerArguments.Type,
    
    // Use module package provider so that we can delay resolving the module package until execution
    // time (for performance). The resolved module package is set as @Input (see getModulePackage()
    // below), but the provider itself should be set as @Internal.
    private val modulePackageProvider: () -> String,
    
    @get:Input
    val minApi: Int,
    
    // We can't set the sdkDir as an @InputDirectory because it is too large to compute a hash. We
    // can't set it as an @Input either because it would break cache relocatability. Therefore, we
    // annotate it with @Internal, expecting that the directory's contents should be stable and this
    // won't affect correctness.
    @get:Internal
    val sdkDir: File,
    
    @get:InputFiles
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val dependencyArtifactsDir: Provider<Directory>,
    
    @get:InputFiles
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val layoutInfoDir: Provider<Directory>,
    
    @get:InputFiles
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val classLogDir: Provider<Directory>,
    
    @get:Optional
    @get:InputFiles
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val baseFeatureInfoDir: Provider<Directory>,
    
    @get:Optional
    @get:InputFiles
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val featureInfoDir: Provider<Directory>,
    
    @get:Optional
    @get:OutputDirectory
    val aarOutDir: Provider<Directory>,
    
    @get:Optional
    @get:OutputFile
    val exportClassListOutFile: File?,
    
    @get:Input
    val enableDebugLogs: Boolean,
    
    // We don't set this as an @Input because: (1) it doesn't affect the results of data binding
    // processing, and (2) its value is changed between an Android Studio build and a command line
    // build; by not setting it as @Input, we allow the users to get incremental/UP-TO-DATE builds
    // when switching between the two modes (see https://issuetracker.google.com/80555723).
    @get:Internal
    val printEncodedErrorLogs: Boolean,
    
    @get:Input
    val isTestVariant: Boolean,
    
    @get:Input
    val isEnabledForTests: Boolean,
    
    @get:Input
    val isEnableV2: Boolean
    ) : CommandLineArgumentProvider {
    
    @Input
    fun getModulePackage() = modulePackageProvider()
    
    override fun asArguments(): Iterable<String> {
    val arguments = CompilerArguments(
    incremental = incremental,
    artifactType = artifactType,
    modulePackage = getModulePackage(),
    minApi = minApi,
    sdkDir = sdkDir,
    dependencyArtifactsDir = dependencyArtifactsDir.get().asFile,
    layoutInfoDir = layoutInfoDir.get().asFile,
    classLogDir = classLogDir.get().asFile,
    baseFeatureInfoDir = baseFeatureInfoDir.orNull?.asFile,
    featureInfoDir = featureInfoDir.orNull?.asFile,
    aarOutDir = aarOutDir.orNull?.asFile,
    exportClassListOutFile = exportClassListOutFile,
    enableDebugLogs = enableDebugLogs,
    printEncodedErrorLogs = printEncodedErrorLogs,
    isTestVariant = isTestVariant,
    isEnabledForTests = isEnabledForTests,
    isEnableV2 = isEnableV2
    ).toMap()
    
    // Don't need to sort the returned list as the order shouldn't matter to Gradle.
    // Also don't need to escape the key and value strings as they will be passed as-is to
    // the Java compiler.
    return arguments.map { entry -> "-A${entry.key}=${entry.value}" }
    }
    
    companion object {
    
    @JvmStatic
    fun createArguments(
    variantScope: VariantScope,
    enableDebugLogs: Boolean,
    printEncodedErrorLogs: Boolean
    ): DataBindingCompilerArguments {
    val globalScope = variantScope.globalScope
    val variantData = variantScope.variantData
    val variantConfig = variantScope.variantConfiguration
    val artifacts = variantScope.artifacts
    
    return DataBindingCompilerArguments(
    incremental = globalScope.projectOptions
    .get(BooleanOption.ENABLE_INCREMENTAL_DATA_BINDING),
    artifactType = getModuleType(variantScope),
    modulePackageProvider = { variantConfig.originalApplicationId },
    minApi = variantConfig.minSdkVersion.apiLevel,
    sdkDir = globalScope.sdkComponents.getSdkFolder()!!,
    dependencyArtifactsDir =
    artifacts.getFinalProduct(DATA_BINDING_DEPENDENCY_ARTIFACTS),
    layoutInfoDir = artifacts.getFinalProduct(getLayoutInfoArtifactType(variantScope)),
    classLogDir = artifacts.getFinalProduct(DATA_BINDING_BASE_CLASS_LOG_ARTIFACT),
    baseFeatureInfoDir = artifacts.getFinalProduct(
    FEATURE_DATA_BINDING_BASE_FEATURE_INFO
    ),
    featureInfoDir = artifacts.getFinalProduct(FEATURE_DATA_BINDING_FEATURE_INFO),
    aarOutDir = artifacts.getFinalProduct(InternalArtifactType.DATA_BINDING_ARTIFACT),
    exportClassListOutFile = variantScope.generatedClassListOutputFileForDataBinding
    .takeIf { variantData.type.isExportDataBindingClassList },
    enableDebugLogs = enableDebugLogs,
    printEncodedErrorLogs = printEncodedErrorLogs,
    isTestVariant = variantData.type.isTestComponent,
    isEnabledForTests = globalScope.extension.dataBinding.isEnabledForTests,
    isEnableV2 = true
    )
    }
    
    /**
    * Returns the module type of a variant. If it is a testing variant, return the module type
    * of the tested variant.
    */
    @JvmStatic
    fun getModuleType(variantScope: VariantScope): CompilerArguments.Type {
    val variantData = if (variantScope.variantData.type.isTestComponent) {
    variantScope.testedVariantData!!
    } else {
    variantScope.variantData
    }
    return if (variantData.type.isAar) {
    CompilerArguments.Type.LIBRARY
    } else {
    if (variantData.type.isBaseModule) {
    CompilerArguments.Type.APPLICATION
    } else {
    CompilerArguments.Type.FEATURE
    }
    }
    }
    
    /**
    * Returns the appropriate artifact type of the layout info directory so that it does not
    * trigger unnecessary computations (see bug 133092984 and 110412851).
    */
    @JvmStatic
    fun getLayoutInfoArtifactType(variantScope: VariantScope): InternalArtifactType<Directory> {
    return if (variantScope.variantData.type.isAar) {
    DATA_BINDING_LAYOUT_INFO_TYPE_PACKAGE
    } else {
    DATA_BINDING_LAYOUT_INFO_TYPE_MERGE
    }
    }
    }
    }

    参考

    DataBindingCompilerArguments.kt

    kotlin.KotlinNullPointerException (no error message) while building APK using Jenkins

    infoworld 博客专家 原创文章 347获赞 126访问量 120万+ 关注 他的留言板
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: