无法使用发布标记构建我的应用程序

时间:2017-12-19 21:42:25

标签: android angular webpack nativescript

我使用 webpack 来构建我的应用程序(使用angular),命令:npm run build-android-bundle - uglify效果非常好,但是当我使用标志 - release (npm run build-android-bundle - --release --keyStorePath~ / path / to / keystore --keyStorePassword your-pass --keyStoreAlias your-alias --keyStoreAliasPassword your-alias-pass)这里发生错误是它的内容:

    Running full build
        ~/platforms/android/src/F0/AndroidManifest.xml:27:9-31 Error:
            Attribute meta-data#android.support.VERSION@value value=(25.3.1) from [com.android.support:design:25.3.1] AndroidManifest.xml:27:9-31
            is also present at [com.android.support:appcompat-v7:26.0.0-alpha1] AndroidManifest.xml:27:9-38 value=(26.0.0-alpha1).
            Suggestion: add 'tools:replace="android:value"' to <meta-data> element at AndroidManifest.xml:25:5-27:34 to override.

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':processF0F1F2F3ReleaseManifest'.
    > Manifest merger failed : Attribute meta-data#android.support.VERSION@value value=(25.3.1) from [com.android.support:design:25.3.1] AndroidManifest.xml:27:9-31
            is also present at [com.android.support:appcompat-v7:26.0.0-alpha1] AndroidManifest.xml:27:9-38 value=(26.0.0-alpha1).
            Suggestion: add 'tools:replace="android:value"' to <meta-data> element at AndroidManifest.xml:25:5-27:34 to override.  
Command ./gradlew failed with exit code 1

我想要帮助!

我的build.gradle文件:

import groovy.json.JsonSlurper

import java.nio.file.Files;
import java.nio.file.Paths;

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:2.2.3"
    }
}

apply plugin: "com.android.application"

def metadataParams = new LinkedList <String> ()
def allJarPaths = new LinkedList <String> ()
def configStage = "\tconfig phase: "
def nodeModulesDir = "../../node_modules/"
def dependenciesJson = file("dependencies.json")

// the build script will not work with previous versions of the CLI (3.1 or earlier)
if (!dependenciesJson.exists()) {
    throw new BuildCancelledException("""
'dependencies.json' file not found. Check whether the NativeScript CLI has prepared the project beforehand,
and that your NativeScript version is 3.3, or a more recent one. To build an android project with the current
version of the {N} CLI install a previous version of the runtime package - 'tns platform add android@3.2'.
""")
}

def nativescriptDependencies = new JsonSlurper().parseText(dependenciesJson.text)

def packageJsonContents = [:]

def dontRunSbg = project.hasProperty("dontRunSbg");
def asbgProject = project(":asbg")
asbgProject.ext.outDir = new File("$projectDir", "src/main/java")
asbgProject.ext.jsCodeDir = new File("$projectDir", "src/main/assets/app")

def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk : 23 }
def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk : 23 }
def computeBuildToolsVersion = { -> project.hasProperty("buildToolsVersion") ? buildToolsVersion : "25.0.2" }

project.ext.selectedBuildType = project.hasProperty("release") ? "release" : "debug"

def renameResultApks = { variant ->
    def name
    variant.outputs.each { output ->
        def apkDirectory = output.packageApplication.outputFile.parentFile
        def abiName = "";
        if (output.getFilter(com.android.build.OutputFile.ABI)) {
            abiName = "-" + output.getFilter(com.android.build.OutputFile.ABI);
        }
        def apkNamePrefix = rootProject.name + "-" + variant.buildType.name + abiName
        name = apkNamePrefix + ".apk"
        output.packageApplication.outputFile = new File(apkDirectory, name);
    }
}

////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATIONS ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

def applyPluginsIncludeGradleConfigurations =  { ->
    def taskNames = project.getGradle().startParameter.taskNames

    // don't apply plugin configurations if clean is invoked
    if (taskNames && taskNames.size() > 0 && taskNames.getAt(0).equals("clean")) {
        return []
    }

    def configurationsDir = new File(projectDir, "build/configurations")
    configurationsDir.deleteDir()

    def dimensions = []
    def includes = new ArrayList<String>()
    def flavorNumber = 0

    nativescriptDependencies.each { dep ->
        def androidDir = file("${dep.directory}/platforms/android")
        if (!androidDir.exists()) {
            return
        }

        def packageJsonPath = file("${dep.directory}/package.json")
        def packageJson = new JsonSlurper().parseText(packageJsonPath.text)
        def pluginName = packageJson.name
        def dimensionName = sanitizeDimensionName(pluginName)

        dimensions.add(dimensionName)
        def flavor = "F${flavorNumber++}"

        def includeGradleFile = new File(androidDir, "include.gradle")
        def destinationDir = file("${configurationsDir}/${pluginName}/")
        def destinationIncludeGradleFile = file("${configurationsDir}/${pluginName}/include.gradle")

        Files.createDirectories(Paths.get(destinationDir.getAbsolutePath()))

        if (includeGradleFile.exists()) {
            println "\t + add include.gradle from ${includeGradleFile}"
            destinationIncludeGradleFile.text = modifyProductFlavorInContent(includeGradleFile.text, dimensionName, flavor)
        } else {
            println "\t + creating include.gradle for plugin ${file(dep.directory)}"
            destinationIncludeGradleFile.text = createProductFlavorsContent(flavor, dimensionName)
        }

        includes.add(destinationIncludeGradleFile.getAbsolutePath());

        copyAndRenamePluginDirToFlavorName(androidDir, flavor);
    }

    includes.each {
        println "\t + applying plugin configuration from ${it}"
        apply from: it
    }

    return dimensions
}

def applyAppGradleConfiguration = { ->
    def pathToAppGradle = "$projectDir/../../app/App_Resources/Android/app.gradle"
    def appGradle = file(pathToAppGradle)
    if (appGradle.exists()) {
        println "\t + applying user-defined configuration from ${appGradle}"
        apply from: pathToAppGradle
    } else {
        println "\t + couldn't load user-defined configuration from ${appGradle}. File doesn't exist."
    }
}

android {
    compileSdkVersion computeCompileSdkVersion()
    buildToolsVersion computeBuildToolsVersion()

    defaultConfig {
        minSdkVersion 17
        targetSdkVersion computeTargetSdkVersion()
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }

    sourceSets.main {
        jniLibs.srcDir "$projectDir/libs/jni"
    }

    signingConfigs {
        release {
            if (project.hasProperty("release")) {
                if (project.hasProperty("ksPath") &&
                    project.hasProperty("ksPassword") &&
                    project.hasProperty("alias") &&
                    project.hasProperty("password")) {

                    storeFile file(ksPath)
                    storePassword ksPassword
                    keyAlias alias
                    keyPassword password
                }
            }
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }

    applicationVariants.all { variant ->
        renameResultApks(variant)
    }

    applicationVariants.all { variant ->
        def variantName = variant.name.capitalize()
        def compileSourcesTaskName = "compile${variantName}Sources"
        def compileSourcesTask = project.tasks.findByName(compileSourcesTaskName)

        def generateBuildConfigTask = variant.generateBuildConfig;
        generateBuildConfigTask.finalizedBy(collectAllJars)
        if(!dontRunSbg) {
            collectAllJars.finalizedBy(setProperties)
        }

        compileSourcesTask.finalizedBy(buildMetadata)

        // forces packaging of resources and assets AFTER producing metadata
        // Reference: https://github.com/NativeScript/android-runtime/issues/785

        // Ensure metadata has been built and copied in assets before packaging
        variant.outputs.each { output ->
            def abiName = "";
            if (output.getFilter(com.android.build.OutputFile.ABI)) {
                abiName = output.getFilter(com.android.build.OutputFile.ABI)
                def packageTask = project.tasks.findByName("package${output.name}")
                if (packageTask) {
                    packageTask.dependsOn(buildMetadata)
                }
            }
        }

        // Compile the Java sources AFTER the Java code-generation step is done
        def compileTask = project.tasks.findByName("compile${variantName}JavaWithJavac")
        if (compileTask) {
            compileTask.dependsOn("asbg:generateBindings")
        }
    }

    applyAppGradleConfiguration()

    def dimensions = applyPluginsIncludeGradleConfigurations()

    flavorDimensions(*dimensions)
}

repositories {
    jcenter()
    maven { url 'https://maven.google.com' }

    // used for local *.AAR files
    def pluginDependencies = nativescriptDependencies.collect { "${it.directory}/platforms/android" }
    pluginDependencies.add("libs/runtime-libs")

    flatDir {
        dirs pluginDependencies
    }
}

dependencies {
    def supportVer = "22.2.0";
    if (project.hasProperty("supportVersion")) {
        supportVer = supportVersion
    }

    compile "com.android.support:support-v4:$supportVer"
    compile "com.android.support:appcompat-v7:$supportVer"
    debugCompile "com.android.support:design:$supportVer"

    // take all jars within the libs dir
    compile fileTree(dir: "$projectDir/libs", include: ["**/*.jar"])
}

////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATION PHASE //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

task addNativeScriptRuntimePackageDependency {
    def useV8Symbols = nativescriptDependencies.any {
        def packageJsonPath = file("${it.directory}/package.json");
        def packageJson = new JsonSlurper().parseText(packageJsonPath.text);
        return packageJson.nativescript.useV8Symbols;
    }

    def runtime = useV8Symbols ? "nativescript-regular" : "nativescript-optimized";
    println "\t + adding nativescript runtime package dependency: $runtime"

    project.dependencies.add("compile", [name: runtime, ext: "aar"])
}

task addDependenciesFromNativeScriptPlugins {
    nativescriptDependencies.each { dep ->
        def aarFiles = fileTree(dir: file("${dep.directory}/platforms/android"), include: ["**/*.aar"])
        aarFiles.each { aarFile ->
            def length = aarFile.name.length() - 4
            def fileName = aarFile.name[0..<length]
            println "\t + adding aar plugin dependency: " + aarFile.getAbsolutePath()
            project.dependencies.add("compile", [name: fileName, ext: "aar"])
        }

        def jarFiles = fileTree(dir: file("${dep.directory}/platforms/android"), include: ["**/*.jar"])
        jarFiles.each { jarFile ->
            println "\t + adding jar plugin dependency: " + jarFile.getAbsolutePath()
        }

        project.dependencies.add("compile", jarFiles)
    }
}

static def updateProductFlavorsContent(flavor, dimensionName, oldContent) {
    def endIndex = oldContent.length() - 1;
        def index = 0;
        def newContent = "";
        def level = -1;
        def dimensionFound = false;

        while(index <= endIndex) {
            if (level == 0 && (oldContent[index] == '"' || oldContent[index] == "'")) {
                def closingQuotes = oldContent.indexOf('"', index + 1);
                if (closingQuotes == -1) {
                    closingQuotes = oldContent.indexOf("'", index + 1);
                }

                index = closingQuotes + 1;
                newContent += "\"${flavor}\"";
                continue;
            }

            if (oldContent[index] == "{") {
                level++;
            }

            if (oldContent[index] == "}") {
                level--;
            }

            if (level > 0) {
                if (!dimensionFound && oldContent.indexOf("dimension", index) == index) {
                    newContent += "dimension \"${dimensionName}\"";
                    dimensionFound = true;
                    index += "dimension ".length();
                    def openingQuoutes = oldContent.indexOf('"', index);
                    if (openingQuoutes == -1) {
                        openingQuoutes = oldContent.indexOf("'", index);
                    }

                    def closingQuotes = oldContent.indexOf('"', openingQuoutes + 1);
                    if (closingQuotes == -1) {
                        closingQuotes = oldContent.indexOf("'", openingQuoutes + 1);
                    }

                    index = closingQuotes + 1;
                }
            }

            newContent += oldContent[index];

            index++;
        }

        return newContent;
}

static def createProductFlavorsContent(flavor, dimensionName, includeAndroidContent = true) {
    if (includeAndroidContent)
    {
        def content = """
android {
    productFlavors {
        "${flavor}" {
            dimension "${dimensionName}"
        }
    }
}
"""
        return content;
    }
    else
    {
        def content = """
    productFlavors {
        "${flavor}" {
            dimension "${dimensionName}"
        }
    }
"""
      return content;
    }
}

static def sanitizeDimensionName(str) {
    return str.replaceAll(/\W/, "")
}

static def modifyProductFlavorInContent(content, dimension, flavor) {
    def indexStart = content.indexOf("productFlavors");
    def index = indexStart  + "productFlavors".length();
    def indexEnd = -1;
    def nestedOpenBracketsCount = 0;

    while (index < content.length())
    {
        // print content[index];
        if (content[index] == "}")
        {
            nestedOpenBracketsCount--;

            if (nestedOpenBracketsCount == 0)
            {
                indexEnd = index;
                break;
            }
        }
        else if (content[index] == "{")
        {
            nestedOpenBracketsCount++;
        }

        index++;
    }

    if (indexEnd != -1)
    {
        // full content of productFlavors { ... } -> the substring is parenthesis to parenthesis -> { ... }
      def oldProductFlavorsText = content.substring(indexStart, indexEnd + 1);

      def newProductFlavorsContent = updateProductFlavorsContent(flavor, dimension, oldProductFlavorsText);

      return content.replace(oldProductFlavorsText, newProductFlavorsContent);
    }
    else
    {
        def androidContentExists = content.indexOf("android {") != -1;
        def newProductFlavorsContent = createProductFlavorsContent(flavor, dimension, !androidContentExists);

        if (androidContentExists)
        {
           return content.replace("android {", "android { ${newProductFlavorsContent}");
        }
        else
        {
           return "${newProductFlavorsContent} \t ${content}"
        }
    }
}

def copyFolder(source, destination) {
    if (source.isDirectory()) {
        Files.createDirectories(destination.toPath());

        def sourceFiles = source.list();

        sourceFiles.each { file ->
            def srcFile = new File(source, file);
            def destFile = new File(destination, file);

            //Recursive function call
            copyFolder(srcFile, destFile);
        }
    }
    else {
        // Copy the file content from one place to another
        def fileName = source.getName()
        def extension = fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0 ? fileName.substring(fileName.lastIndexOf(".") + 1) : "";
        // exclude aars from package, as we've already included it in the compile dependencies, and don't want it taking up space
        if (extension == "aar") {
            return
        }

        Files.copy(source.toPath(), destination.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
    }
}

def copyAndRenamePluginDirToFlavorName(directory, flavor) {
    def targetDir = file("src/${flavor}")

    copyFolder(directory, targetDir)
}

task ensureMetadataOutDir {
    def outputDir = file("$projectDir/metadata/output/assets/metadata")
    outputDir.mkdirs()
}

////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// EXECUTUION PHASE /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

task collectAllJars {
    description "gathers all paths to jar dependencies before building metadata with them"

    def explodedAarDir = project.buildDir.getAbsolutePath() + "/intermediates/exploded-aar/"
    def sdkPath = android.sdkDirectory.getAbsolutePath();
    def androidJar = sdkPath + "/platforms/" + android.compileSdkVersion + "/android.jar"

    doFirst {
        configurations.compile.each { File dependencyFile ->
            logger.info("Task: collectAllJars: dependency file: " + dependencyFile.getAbsolutePath())
            allJarPaths.add(dependencyFile.getAbsolutePath())
        }

        allJarPaths.add(androidJar);

        def ft = fileTree(dir: explodedAarDir, include: "**/*.jar")
        ft.each { currentJarFile ->
            allJarPaths.add(currentJarFile.getAbsolutePath())
        }

        metadataParams.add("metadata-generator.jar");
        metadataParams.add("$projectDir/metadata/output/assets/metadata");
        def jars = new LinkedList<File>()
        for (def i = 0; i < allJarPaths.size(); i++) {
            metadataParams.add(allJarPaths.get(i));
            def f = new File(allJarPaths.get(i))
            if (f.getName().endsWith(".jar")) {
                jars.add(f)
            }
        }

        asbgProject.ext.jarFiles = jars
    }
}

task buildMetadata (type: JavaExec) {
    description "builds metadata with provided jar dependencies"

    inputs.files(allJarPaths)
    inputs.dir("$buildDir/intermediates/classes")

    outputs.files("metadata/output/assets/metadata/treeNodeStream.dat", "metadata/output/assets/metadata/treeStringsStream.dat", "metadata/output/assets/metadata/treeValueStream.dat")

    doFirst {
        // get compiled classes to pass to metadata generator
        // these need to be called after the classes have compiled
        def classesDir = "$buildDir/intermediates/classes"

        def classesSubDirs = new File(classesDir).listFiles()
        def selectedBuildType = project.ext.selectedBuildType

        for (File subDir: classesSubDirs) {
            if (!subDir.getName().equals(selectedBuildType)) {
                def subDirBuildType = new File(subDir, selectedBuildType)
                if (subDirBuildType.exists()) {
                    metadataParams.add(subDirBuildType.getAbsolutePath());
                }
            }
        }

        def classesDirBuildType = new File(classesDir, selectedBuildType)
        if (classesDirBuildType.exists()) {
            metadataParams.add(classesDirBuildType.getAbsolutePath())
        }

        workingDir "build-tools"
        main "-jar"

        logger.info("Task buildMetadata: Call metadata-generator.jar with arguments: " + metadataParams.toString().replaceAll(',', ''))
        args metadataParams.toArray()
    }

    doLast {
        copy {
            from "$projectDir/metadata/output/assets/metadata"
            into "$projectDir/src/main/assets/metadata"
        }
    }
}

task generateTypescriptDefinitions (type: JavaExec) {
    def paramz = new ArrayList<String>();
    def includeDirs = ["com.android.support", "/platforms/" + android.compileSdkVersion]

    doFirst {
        delete "build-tools/typings"

        workingDir "build-tools"

        main "-jar"

        paramz.add("dts-generator.jar");
        paramz.add("-input");

        for (String jarPath: project.jarFiles) {
            // don't generate typings for runtime jars and classes
            if (shouldIncludeDirForTypings(jarPath, includeDirs)) {
                paramz.add(jarPath);
            }
        }

        paramz.add("-output");
        paramz.add("typings");

        logger.info("Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', ''))
        args paramz.toArray();
    }
}

generateTypescriptDefinitions.onlyIf {
    project.hasProperty("generateTypings") && Boolean.parseBoolean(project.generateTypings)
}

static def shouldIncludeDirForTypings(path, includeDirs) {
    for (String p: includeDirs) {
        if (path.indexOf(p) > -1) {
            return true;
        }
    }

    return false;
}

task copyTypings {
    doLast {
        println "Copied generated typings to application root level. Make sure to import android.d.ts in reference.d.ts"

        copy {
            from "$projectDir/build-tools/typings"
            into "$projectDir/../../"
        }
    }
}

copyTypings.onlyIf { generateTypescriptDefinitions.didWork }

task validateAppIdMatch {
    doLast {
        def packageJsonFile = new File("$projectDir/../../package.json");
        def lineSeparator = System.getProperty("line.separator");

        if (packageJsonFile.exists() && !project.hasProperty("release")) {
            String content = packageJsonFile.getText("UTF-8")
            def jsonSlurper = new JsonSlurper()
            def packageJsonMap = jsonSlurper.parseText(content)

            if (packageJsonMap.nativescript.id != android.defaultConfig.applicationId) {
                def errorMessage = "${lineSeparator}WARNING: The Application identifier is different from the one inside 'package.json' file.$lineSeparator" +
                    "NativeScript CLI might not work properly.$lineSeparator" +
                    "Update the application identifier in package.json and app.gradle so that they match.";
                logger.error(errorMessage);
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// OPTIONAL TASKS //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

task setProperties {
    project.ext.jarFiles = []
    doLast {
        def list = [];
        allJarPaths.each({f ->
            if(f.endsWith(".jar")) {
                list.add(f);
            }
        })
        project.jarFiles = list;
    }
}

setProperties.finalizedBy("asbg:generateBindings", generateTypescriptDefinitions)

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// EXECUTION ORDER /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

collectAllJars.dependsOn(ensureMetadataOutDir)
buildMetadata.dependsOn(collectAllJars)
generateTypescriptDefinitions.finalizedBy(copyTypings)

task buildapk {
    //done to build only necessary apk
    if (project.hasProperty("release")) {
        dependsOn "assembleRelease"
    }
    else {
        dependsOn "assembleDebug"
    }
}

//////// custom clean ///////////
task deleteMetadata (type: Delete){
    delete "$projectDir/metadata/output", "$projectDir/src/main/assets/metadata"
}

task deleteFlavors (type: Delete){
    doLast {
        def srcDir = new File("$projectDir/src")
        srcDir.listFiles().each({ f ->
            def dirName = f.getName()
            if (dirName != "main" &&
                    dirName != "debug" &&
                    dirName != "release")   {
                delete f
            }
        })
    }
}

task deleteGeneratedBindings(type: Delete) {
    delete "$projectDir/src/main/java/com/tns/gen"
}

buildapk.finalizedBy("validateAppIdMatch");
deleteMetadata.dependsOn(":asbg:clean")
deleteFlavors.dependsOn(deleteMetadata)
deleteGeneratedBindings.dependsOn(deleteFlavors)
clean.dependsOn(deleteGeneratedBindings)

2 个答案:

答案 0 :(得分:0)

真正的解决方案是将所有依赖项保留在同一版本中,除非您确实需要旧版本。因此,请确保所有支持库都在26.0.0-alpha1或您想要的任何级别。

替代解决方案:

转到Android清单并添加以下行:

工具:replace =“android:value”到元数据元素。它告诉android你要用什么库来构建。

答案 1 :(得分:0)

我找到了解决问题的方法。 triniwiz帮助了我,感谢他和你。这是解决方案的the link。再次感谢

  

triniwiz

     

所以看起来你有几个使用不同版本的插件   支持lib,以便您可以尝试以下方法来锁定支持   它将它锁定到最新版本你可以选择你的版本   想要使用该应用程序也需要将其放入   app.gradle位于/SomeApp/app/App_Resources/Android/app.gradle

     

repositories {maven {               网址&#39; https://maven.google.com&#39;           }}

     

configurations.all {resolutionStrategy.eachDependency {   DependencyResolveDetails详细信息 - &gt;       def requested = details.requested       if(requested.group ==&#39; com.android.support&#39;){           if(!requested.name.startsWith(&#34; multidex&#34;)){               details.useVersion&#39; 27.0.2&#39;           }        }

     

}}