2017-01-16 7 views
0

私はAndroid StudioとAndroidプロジェクトの開発に慣れています。 AndroidのメーカーでIntelliJを使ってjarファイル名にバージョン情報を追加

私はbuild.gradleファイルでこれを置く:私はmyapp.1.0.1.apk取得ビルドすると、

defaultConfig { 
    applicationId "com.domain.myapp" 
    minSdkVersion 19 
    targetSdkVersion 19 
    versionCode 1 
    versionName "1.0" 
    setProperty("archivesBaseName", "myapp.$versionName.$versionCode") 
    signingConfig signingConfigs.config 
} 
buildTypes { 
    release { 
     minifyEnabled false 
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
     applicationVariants.all { variant -> 
      variant.outputs.each { output -> 
       def newName = output.outputFile.name 
       newName = newName.replace("-release", "") 
       output.outputFile = new File(output.outputFile.parent, newName) 
      } 
     } 
     signingConfig signingConfigs.config 
    } 
    debug { 
     signingConfig signingConfigs.config 
    } 
} 

を見事に動作します。

今、Android StudioではなくIntelliJを使用してJavaプロジェクトの.jarを開発しています。

どうすれば同じことができますか?私はまばらな情報を探しています...

答えて

0

R.javaファイルを作成するタスクを追加することで、Androidがこれを行います。 Androidが動作を複製するように見えるように簡単なことは、少しの労力を要します。独自のgradleタスクを作成して同じ目的を達成することができます。作成、拡張、およびタスクを行うためのgradleプラグインが必要です。拡張子は

ここ
// create DSL model 
    target.extensions.create('buildConfig', BuildConfigModel) 
    // create task to generate file 
    def buildConfigTask = target.tasks.create('generateBuildConfig', BuildConfigTask) 
    target.tasks.findByName('clean').configure { 
     delete new File("$project.projectDir/src/main", "generated-sources") 
    } 
    // this task must always run... it's never `upToDate` 
    buildConfigTask.outputs.upToDateWhen { false } 
    // java compiler depends on this task... allows us to reference generated code from 
    // human written code 
    target.tasks.getByName('compileJava').dependsOn buildConfigTask 

は、あなたが発生したソースがファイルを追加するためにあなたのタスクを使用する方法である拡張機能を作成する必要がありbuild.gradle

プラグインで追加された値とタスクを追跡するために使用されます

project.configure(project, { Project configuredProject -> 
     // compilerJava task {@link JavaCompile} 
     def compileJava = configuredProject.compileJava 
     // add the created java file to source path so it gets compiled 
     compileJava.source(project.buildConfig.createBuildConfig(project, compileJava)) 
    }) 

私たちの拡張は、このようになります

package com.jbirdvegas.q41680813; 

import com.squareup.javapoet.CodeBlock; 
import com.squareup.javapoet.FieldSpec; 
import com.squareup.javapoet.JavaFile; 
import com.squareup.javapoet.MethodSpec; 
import com.squareup.javapoet.TypeSpec; 
import org.gradle.api.GradleException; 
import org.gradle.api.Project; 
import org.gradle.api.tasks.compile.JavaCompile; 

import javax.lang.model.element.Modifier; 
import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 

/** 
* Handles creating the BuildConfig.java from a module project 
* <p> 
* Warning... Keep this in java, gradle doesn't have the streams api we are using 
*/ 
public class BuildConfigModel { 
    /** 
    * Final java file output path pattern for {@link String#format(String, Object...) String#format} formatting of 
    * the file's path. Directory structure will be created if needed 
    */ 
    private static final String OUTPUT_PATH_FORMAT = "%s/src/main/generated-sources/%s/%s/BuildConfig.java"; 

    /** 
    * List of DSL supplied {@link BuildValue buildConfig#add} 
    */ 
    private List<BuildValue> mBuildValues = new ArrayList<>(); 

    /** 
    * Required... do not remove 
    */ 
    public BuildConfigModel() { 
    } 

    /** 
    * Create a new field to the project's generated `BuildConfig.java`'s inner class for each type 
    * 
    * @param clazz Type of value to be written (will be grouped by clazz) 
    * @param name field name to be created 
    * @param value value to be assigned to field's name 
    */ 
    @SuppressWarnings({"unused", "WeakerAccess"}) 
    public void add(Class clazz, String name, Object value) { 
     mBuildValues.add(new BuildValue(clazz, name, value)); 
    } 

    /** 
    * Create `BuildConfig.java` and add it to the {@link JavaCompile#source(Object...)} compileJava#source(Object...)} 
    * 
    * @param project  module to generate BuildConfig for 
    * @param javaCompile project's `compileJava` task 
    * @return generated `BuildConfig.java` file 
    */ 
    public File createBuildConfig(Project project, JavaCompile javaCompile) { 
     File buildConfigFile = getBuildConfigFile(project); 
     createJavaClass(project, buildConfigFile); 
     javaCompile.source(buildConfigFile); 
     return buildConfigFile; 
    } 

    /** 
    * Destination file for given project's `BuildConfig.java` 
    * 
    * @param project module to generate BuildConfig for 
    * @return File representing the destination of the created `BuildConfig.java` 
    */ 
    @SuppressWarnings("WeakerAccess") 
    public File getBuildConfigFile(Project project) { 
     return project.file(String.format(OUTPUT_PATH_FORMAT, 
       project.getProjectDir().getAbsolutePath(), 
       project.getGroup().toString().replaceAll("\\.", "/"), 
       project.getName())); 
    } 

    /** 
    * Create `BuildConfig.java` with a few default values and any values supplied 
    * to the `buildConfig`'s {@link #add(Class, String, Object) add} method. 
    * <p> 
    * Default BuildConfig fields will be generated by {@link #getDefaultFields} 
    * <p> 
    * Fields added via {@link #add(Class, String, Object) add} method will be grouped into inner classes 
    * named <pre>{@code Class#getSimpleName().toLowerCase() + "s"}</pre> 
    * 
    * @param project   module to generate BuildConfig for 
    * @param buildConfigFile File representing the destination of the BuildConfig.java output 
    */ 
    @SuppressWarnings("WeakerAccess") 
    public void createJavaClass(Project project, File buildConfigFile) { 
     //noinspection unchecked 
     Collections.sort(mBuildValues); 
     // group our configs by their types into a map of groups 
     Map<Class, List<BuildValue>> groupedConfigs = mBuildValues.stream() 
       // put the values in groups based on the simple name of the class in lowercase 
       .collect(Collectors.groupingBy(BuildValue::getValueType)); 

     // create the fully qualified class that will contain our build settings 
     TypeSpec.Builder buildConfigJavaBuilder = TypeSpec.classBuilder("BuildConfig") 
       .addModifiers(Modifier.PUBLIC, Modifier.FINAL) 
       // note for javadoc 
       .addJavadoc("$S\n", "DO NOT MODIFY; this class is written automatically by the compiler") 
       // replace public constructor with private 
       .addMethod(createPrivateConstructor()); 

     // add any fields that will be in all BuildConfig classes 
     buildConfigJavaBuilder.addFields(getDefaultFields(project)); 

     groupedConfigs.forEach((aClass, buildValues) -> { 
      // create the inner class 
      String safeInnerClassName = aClass.getSimpleName().toLowerCase() + 's'; 
      TypeSpec.Builder innerClass = TypeSpec.classBuilder(safeInnerClassName) 
        .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) 
        // make a constructor that's private since all the members of this class are public static final 
        .addMethod(createPrivateConstructor()); 
      // for each inner class type create a field 
      // each object type gets it's own inner class 
      //noinspection SimplifyStreamApiCallChains 
      buildValues.stream().forEachOrdered(buildValue -> { 
       // create the requested field in the class 
       FieldSpec fieldSpec = FieldSpec.builder(buildValue.clazz, buildValue.name) 
         .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) 
         .initializer(CodeBlock.of(getStringFormatter(buildValue.clazz), buildValue.value)) 
         .build(); 
       // add the field to the inner class 
       innerClass.addField(fieldSpec); 
      }); 
      // add the inner class to the fully qualified class 
      buildConfigJavaBuilder.addType(innerClass.build()); 
     }); 

     // determine the package name from project.group + '.' + project.name 
     String packageName = project.getGroup() + "." + project.getName(); 
     // create a java file writer 
     JavaFile.Builder builder = JavaFile.builder(packageName, buildConfigJavaBuilder.build()); 
     // don't import java.lang.* it's redundant 
     builder.skipJavaLangImports(true); 
     // use four spaces for indent instead of default two spaces 
     builder.indent(" "); 
     // create the file in memory 
     JavaFile javaFile = builder.build(); 

     // ensure file structure 
     if (!buildConfigFile.getParentFile().exists() && !buildConfigFile.getParentFile().mkdirs()) { 
      throw new GradleException("Failed to create directory structure for " + buildConfigFile.getAbsolutePath()); 
     } 

     // write BuildConfig.java to location 
     try (FileWriter writer = new FileWriter(buildConfigFile)) { 
      javaFile.writeTo(writer); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Strings require being treated specially in order to be encapsulated in quotes correctly 
    * All other classes are treated as literals... We may want to handle more {@link java.lang.reflect.Type Type} 
    * 
    * @param clazz Class formatter is needed for 
    * @return "$S" if the class is a {@link String} else a literal formatter is returned "$L" 
    */ 
    private String getStringFormatter(Class clazz) { 
     switch (clazz.getSimpleName().toLowerCase()) { 
      case "string": 
       // causes the formatter used to wrap the value in quotes correctly 
      case "date": 
       // date objects are serialized to a string 
       return "$S"; 
      case "long": 
       return "$LL"; 
      case "double": 
       return "$LD"; 
      case "float": 
       return "$LF"; 
      default: 
       // for the reset use literal 
       return "$L"; 
     } 
    } 

    /** 
    * get project added build values 
    * 
    * @return List of build values added by project's `buildConfig` closure 
    */ 
    @SuppressWarnings("unused") 
    public List<BuildValue> collectBuildValues() { 
     return mBuildValues; 
    } 

    /** 
    * Make a private constructor for the class. Default is public but our classes only contain 
    * <pre>{@code public static final {@link Object}}</pre> so public constructors are redundant 
    * 
    * @return private constructor method 
    */ 
    private MethodSpec createPrivateConstructor() { 
     return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build(); 
    } 

    /** 
    * Create default field references 
    * 
    * @param project module to generate BuildConfig for 
    * @return List of fields to write to generated BuildConfig 
    */ 
    private List<FieldSpec> getDefaultFields(Project project) { 
     List<FieldSpec> fields = new ArrayList<>(); 

     // set current version 
     fields.add(FieldSpec.builder(String.class, "version") 
       .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) 
       .initializer(CodeBlock.of(getStringFormatter(String.class), project.getVersion())) 
       .build()); 
     return fields; 
    } 

    class BuildValue implements Comparable { 
     /** 
     * Type of field's value 
     */ 
    /* package */ Class clazz; 

     /** 
     * Field name 
     */ 
    /* package */ String name; 

     /** 
     * Field's value Value must be able to be serialized as a string 
     */ 
    /* package */ Object value; 

     /* package */ BuildValue(Class clazz, String name, Object value) { 
      this.clazz = clazz; 
      this.name = name; 
      this.value = value; 
     } 

     /* package */ Class getValueType() { 
      return clazz; 
     } 

     @Override 
     public boolean equals(Object o) { 
      if (this == o) return true; 
      if (!(o instanceof BuildValue)) return false; 

      BuildValue that = (BuildValue) o; 

      if (clazz != null ? !clazz.equals(that.clazz) : that.clazz != null) return false; 
      if (name != null ? !name.equals(that.name) : that.name != null) return false; 
      return value != null ? value.equals(that.value) : that.value == null; 
     } 

     @Override 
     public int hashCode() { 
      int result = clazz != null ? clazz.hashCode() : 0; 
      result = 31 * result + (name != null ? name.hashCode() : 0); 
      result = 31 * result + (value != null ? value.hashCode() : 0); 
      return result; 
     } 

     @Override 
     public int compareTo(Object o) { 
      return (name != null && o != null) ? name.compareTo(o.toString()) : -1; 
     } 

     @Override 
     public String toString() { 
      final StringBuilder sb = new StringBuilder("BuildValue{"); 
      sb.append("class=").append(clazz.getCanonicalName()); 
      sb.append(", name='").append(name).append('\''); 
      sb.append(", value=").append(value); 
      sb.append('}'); 
      return sb.toString(); 
     } 
    } 
} 

ここでは、デフォルトではその後、実行時に、あなたがBuildConfig.valueを参照の値を取得し、あなたの上記の例のために可能性のプラグインは、versionのデフォルトのフィールドでBuildConfig.javaを作成しますが、あなたはまた、

buildConfig { 
    add Boolean, 'myKey', false 
} 

を独自の値を追加することができますでしょうもフィールドBuildConfig.myKeyBooleanタイプとして入手可能です。

編集:私の例では、プラグイン・クラスとタスク・クラスにgroovyを使用していますが、拡張子はBuildConfigModelです。これはjavaで書かれています。私のソースはすべてsrc/main/groovy

+0

Wowにあります。詳細な対応をありがとうございます。私は今日これに到達することができませんが、私はすぐにこれを実装することを見ていきます。バージョン情報を手動で手動で設定するほうが簡単ですが、私のプロジェクトリストは成長していますので、長期的には自動化されたソリューションをセットアップする価値があります。 –

関連する問題