(摇篮和OrmLite配置)如何添加资源文件Java已经被编译之后,但.apk文件之前生成? [英] (Gradle and OrmLite config) How to add resource file after Java has been compiled but before .apk is generated?

查看:364
本文介绍了(摇篮和OrmLite配置)如何添加资源文件Java已经被编译之后,但.apk文件之前生成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我已经接受了答案,并获得赏金,但是,到底有决定,我的方法对这一问题远非理想。进一步后以为我是来的结论是,在生成过程中修改.apk文件可能不是做到这一点,并保持它的工作长期最安全的或最可持续的方式。

我添加的替代方法这个问题,它完成到底同样的事情的最底部。这种方法我选择使用替代,虽然并不完美,并不需要与.apk文件汇编,通过黑客的内部乱搞。

我想用 OrmLite 其的 pre-生成的配置文件,这是一个普通的Java类生成的,是这样的:

I want to use OrmLite with its pre-generated configuration file, which is generated by a plain Java class, like this:

public final class DatabaseConfigGenerator extends OrmLiteConfigUtil{

private static final Class<?>[] MODELS = {
        Table1.class
};

private static final String ORMLITE_CONFIGURATION_FILE_NAME = "ormlite_config.txt";

public static void main(String[] args) throws Exception {
    File configFile = new File(new File("").getAbsolutePath().split("app" +File.separator + "build")[0] +
                           File.separator +
                           "app" + File.separator +
                           "src" + File.separator +
                           "main" + File.separator +
                           "res" + File.separator +
                           "raw" + File.separator +
                           ORMLITE_CONFIGURATION_FILE_NAME);
    if (configFile.exists()){
        configFile.delete();
    }
    writeConfigFile(configFile, MODELS);
}
}

然后将得到的ormlite_config.txt文件将被划归RES /生/,看起来是这样的:

The resulting ormlite_config.txt file will then be placed under res/raw/, and looks something like this:

#
# generated on 2014/06/20 10:30:42
#
# --table-start--
dataClass=com.example.app
tableName=table1
# --table-fields-start--
# --field-start--
fieldName=field1
# --field-end--
# --table-fields-end--
# --table-end--
#################################

本类需要直接通过Java每次自行或运行模型的一个类被修改,从而使配置是最新的和预期的OR映射函数即可。

This class needs to be run directly via Java every time either itself or one of the Model classes are modified, so that the configuration is up-to-date and the OR mapping can function as expected.

由于我最近切换到Android Studio和摇篮,我爱的构建过程中的灵活性和定制选项,我想通过的build.gradle我的应用程序来自动执行上述ormlite_config.txt的产生。我已经定义它运行DatabaseConfigGenerator.class从应用程序内的工作任务/建设/ classes和生成的配置,而我也与compileJava摇篮任务迷上它,因此Java文件进行编译后生成的配置和.class文件是最新的更新:

Since I recently switched over to Android Studio and Gradle, and I love the flexibility and customization options for the build process, I would like to automate the generation of the aforementioned ormlite_config.txt via the build.gradle for my app. I already have defined a working task which runs DatabaseConfigGenerator.class from inside the app/build/classes and generates the config, and I have also hooked it up with the compileJava Gradle tasks, so the config is generated after the Java files are compiled and the .class files are up-to-date:

android.applicationVariants.all { variant ->
    ext.variantname = "compile" + variant.name.capitalize() + "Java"
    def javaTask = project.tasks.findByName("${variantname}")
    if (javaTask != null) {
        println "Adding post-compile hook to ${variant.name}"
        javaTask.finalizedBy runOrmGenTask
    }
}

这工作得很好,我可以看到应用程序内部的变化ormlite_config.txt /钢骨混凝土/主/资源/原材料,但由于某种原因(我猜的任务顺序是不正确的),当我解压.apk文件,它还包含了从previous构建过时ormlite_config.txt ...

This works well and I can see the ormlite_config.txt change inside the app/src/main/res/raw, but for some reason (I guess the task ordering is not correct), when I extract the .apk, it still contains the outdated ormlite_config.txt from the previous build...

谁能告诉我,或参考我一个链接,Android的摇篮的构建任务顺序构建系统?我一直在寻找远近几天现在并不能找到它。我需要找到一种方法来生成ormlite_config.txt后的Java文件进行编译,但之前.apk文件打包,所以它会被包括在内。

Can anyone tell me or refer me to a link where the build task order of the Android Gradle build system? I've been searching far and wide for a couple of days now and can't find it. I need to find a way to generate the ormlite_config.txt AFTER the Java files are compiled, but BEFORE the .apk is packaged, so it will be included.

这将是真正真棒自动化像这样因为那将每次构建过程中发生的,一步到位,因为配置会始终保持最新的模型类,我永远也不会去想它再次。我有一种直觉,他可以做到的,我只需要弄清楚究竟如何。

It would be really awesome to automated it like this because then it would happen during every build, in one step, because the config would always be up-to-date with the model classes and I would never have to think about it again. I have a gut feeling that his can be done, I just need to figure out how exactly.

免责声明:我仍然在学习的初期阶段摇篮是如何工作的,所以我的一些事情我这里提到的了解可能是路要走。请告诉我,如果是这样,我想学!

DISCLAIMER: I'm still at the very beginning stages of learning how Gradle works, so my understanding of some things I mentioned here could be way off. Please tell me if it is, I want to learn!

编辑1:

我想这会更有意义有DatabaseConfigGenerator写入文件不低于:

I figured it would make more sense to have the DatabaseConfigGenerator write the file NOT under:

app/src/main/res/raw 

但在

app/build/res/all/<variant_name>/raw

一直以来,据我所知,这是他们被打包成.apk文件前的最后资源放置(我可能是错的,所以请纠正我,如果我)。

Since, AFAIK, this is where the final resources are placed before they are packaged into the .apk (I could be wrong, so please correct me if I am).

我也更新了我的build.gradle咯,根据@ pepyakin的回答是:

I also updated my build.gradle slightly, according to @pepyakin's answer:

gradle.projectsEvaluated {
    android.applicationVariants.all { variant ->
        def ormGenTask = project.tasks.findByName("genOrmConfig" + variant.name.capitalize())
        def javaCompileTask = project.tasks.findByName("compile" + variant.name.capitalize() + "Java")
        def packageTask = project.tasks.findByName("package" + variant.name.capitalize())
        ormGenTask.dependsOn(javaCompileTask)
        packageTask.dependsOn(ormGenTask)
    }
}

同样,这个运行良好并输出的摇篮控制台以下内容:

Again, this runs fine and outputs the following in the Gradle console:

...

:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:compileDebugJavaNote: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

:app:preDexDebug UP-TO-DATE
:app:dexDebug
:app:genOrmConfigDebug
Writing configurations to /home/user/development/app/com.example.app.android/app/build/res/all/debug/raw/ormlite_config.txt
Wrote config for class com.example.app.model.Table1
Done.
:app:processDebugJavaRes UP-TO-DATE
:app:validateDebugSigning
:app:packageDebug
:app:assembleDebug

...

所以上面我看到应用程序。genOrmConfigDebug 任务夹整齐的Java编译和包装之间的

So above I see that the app:genOrmConfigDebug task is neatly sandwiched between the Java compilation and the packaging.

然而,由于某种原因,将所得的apk仍然包含来自一个构建同期ormlite_config.txt,它没有达到日期变化,我对模型类(例如定义一个新@DatabaseField)!

HOWEVER, for some reason, the resultant .apk STILL contains an ormlite_config.txt from one build earlier, it's not up-to-date with the changes that I make to the model class (e.g. defining a new @DatabaseField)!

从此我的直觉是,要么是:

My hunch from this is that either:


  1. 我写的ormlite_config.txt到错误的位置(这
    将是不可思议的,因为它捡起进入.apk文件第二次后,
    建)或

  2. 的内容应用程序/建设/ RES /所有/&LT;&VARIANT_NAME GT; /生拾取
    编译&LT;&VARIANT_NAME GT;的Java 执行

  1. I'm writing the ormlite_config.txt to the wrong location (which would be weird, since it IS picked up into the .apk after a second build), OR
  2. The contents of app/build/res/all/<variant_name>/raw are picked up before compile<variant_name>Java is executed

如果它是过去了,我不知道如何处理这...任何建议是AP preciated!

If it's the later, I have no idea how to handle this... Any suggestions are appreciated!

编辑2:

似乎 2 果然是这样。我并排打开两个目录侧(应用程序/编译/ APK 应用程序/建设/ RES /所有/&LT; VARIANT_NAME&GT; /生)和事件的顺序是:

It seems that 2. really is the case. I opened the two directories side by side (app/build/apk and app/build/res/all/<variant_name>/raw) and the order of events is:


  1. 是内部产生向上最新ormlite_config.txt 应用程序/建设/ RES /所有/&LT;&VARIANT_NAME GT; /生

  2. 的apk文件的应用程序/编译/ APK中创建

  3. 提取.apk文件,并在 RES细算/原料,从一年前构建过时ormlite_config.txt里面

  1. The up-to-date ormlite_config.txt is generated inside app/build/res/all/<variant_name>/raw
  2. The .apk is created inside app/build/apk
  3. After extracting the .apk, and looking under res/raw, the outdated ormlite_config.txt from one build ago is inside

我真的AP preciate,如果有人熟悉内部发生的事情 - 在摇篮.apk文件生成过程能告诉我什么,我在这里失踪了!

编辑3

我不会对这个放弃,只是还没有!一些调查研究后,我发现了Android构建的gradle系统的图流程

I'm not giving up on this just yet! After some more research, I found a diagram of the android gradle build system workflow.

据图中,资源(下/ RES)的右编译Java code合并之前,收集和R类被更新。这样做是有意义的,因为如果类引用不包括R中的资源值的汇编将失败。

According to the diagram, the resources (under /res) are merged and collected, and the R class is updated right before compiling the Java code. Which makes sense, because the compilation would fail if the classes reference resource values that are not included in R.

所以,现在我知道肯定执行相关对我的情况的三个步骤的顺序是:

So now I know for sure that the order of execution for the three steps relevant for my case is:


  1. 资源合并和组装,R.java更新

  2. 的Java编译成类

  3. 的apk文件放在一起

现在,如果我的ormlite_config.txt在Java编译后重新生成(如在的build.gradle片段我包含在EDIT 2的定义),但到底是不是造成.apk文件的一部分(早期该文件的版本是不是),即使我把它在 /建设/ RES /所有/&LT;变量名称&gt; /生第3步之前,这只能意味着被列入.apk文件的实际资源的文件比打造专业化/ RES /所有/&LT已经搬到什么地方等;变种名称&gt; ,步骤1和2之间。

Now, if my ormlite_config.txt is re-generated after the Java compilation (as is defined in the build.gradle snippet I included in EDIT 2), but in the end is not part of the resulting .apk (the earlier version of the file is instead) even though I place it under /build/res/all/<variant name>/raw before step 3., that can only mean that the actual resource files to be included in the .apk are already moved somewhere other than buid/res/all/<variant name>, between steps 1. and 2.

现在我只需要找出其中也就是说,这样我就可以把新生成的ormlite_config.txt存在,如果它在任何可能的方式还是可行的......

Now I only have to figure out where that is, so I can put the freshly generated ormlite_config.txt there if it's in any way possible or feasible...

与以前一样,我将非常感激,如果有人可以见识一下这个问题。

截至问题的最高层表示,在最后,我决定去与另一种方法是简单得多,是不是.apk文件装配工艺的黑客,因为是我原本打算做的事。

As stated at the very top of the question, in the end I decided to go with an alternative approach which is much simpler and is not a hack of the .apk assembly process, as is what I originally intended to do.

的步骤如下:


  • code数据库配置生成器类写的 ormlite_config.txt INT您的应用程序的的src / main / RES /生(你可以使用我在包括这个问题作为模板的顶部的DatabaseConfigGenerator类)。保持这个类withing您的应用程序的封装结构,不要让它单独的应用程序或模块,没有理由这样做。所以,你可以把它里面com.your.app.database或什么的。

  • Code your database configuration generator class to write the ormlite_config.txt int your app's src/main/res/raw (You can use the DatabaseConfigGenerator class that I included at the very top of this question as a template). Keep this class withing the package structure of your app, don't make it a separate application or module, there is not reason to do this. So you can put it inside com.your.app.database or whatever.

在Android Studio中的顶部工具栏,点击小下拉框品牌和运行按钮之间:

In the top tool bar in Android Studio, click on the little drop-down box between the "Make" and "Run" buttons:


  • 这将打开一个菜单,你可以选择现有的运行配置中的一个或编辑的配置。选择后:


  • 运行/调试配置窗口将打开,其中左上角,你应该点击绿色的小加号,然后选择应用程序作为一种为您的新配置:


  • 的表格将打开,你会从你的Andr​​oid应用程序定义一个运行配置为您DatabaseConfigGenerator,因为它需要运行一个Java应用程序,分别。只有你需要在这里修改几个字段。首先,给你的新运行配置的名称(1),然后选择DatabaseConfigGenerator作为主类(2),然后在模块类路径中选择您的应用程序的模块,其中的DatabaseConfigGenerator和你的模型类驻留(3),然后删除所有通过选择并单击红色的减号(4),最后是发射之前部分的条目,点击应用(5)。现在,你可以在Android应用程序部分中点击应用到左边(6)。


  • 您需要做的最后一件事,也是最重要的,这将把一切融合在一起,使你的应用程序先建本身,然后生成一个上最新 ormlite_config.txt ,然后重新建立自己(虽然比第一次更快),使这个新生成的配置实际上是包含在最终的apk文件。为了做到这一点,你需要在你的应用程序的运行配置(1)的发射之前,部分修改。可能你会已经在这里了摇篮感知使,这是实际上编译您的应用程序,并在平时的构建过程中,它打包到一个.apk文件。如果没有它,将其添加为第一个条目。在此之后,添加其他的记录,但这次对于数据库配置生成器运行配置,它创建了几步,因为这将确保 ormlite_config.txt 生成基于刚编译模型类,它的最大最新的。最后,增加一个摇篮感知使,以确保新的.apk文件生成,现在将包括这件事最新 ormlite_config.txt 立即点击应用(2),这就是它!

  • The very last thing you need to do here is also the most important one, which will put everything together to make your app first build itself, then generate an up-to-date ormlite_config.txt, and then build itself again (albeit much faster than the first time) so that this newly generated config is actually included in the final .apk. In order to accomplish this, you need to modify the "Before launch" section of your app's run configuration (1). Chances are you will already have a "Gradle-aware Make" in here, which is what actually compiles your app and packages it into an .apk during the usual build process. If you don't have it, add it as the first entry. After that, add another entry, but this time for the "Database Configuration Generator" run configuration, which you created a few steps back, as this will ensure that the ormlite_config.txt is generated based on freshly compiled model classes and is up-to-date. And finally, add another "Gradle-aware Make", to make sure that a new .apk is generated, which will now also include this up-to-date ormlite_config.txt. Now click "Apply" (2), and that's it!


  • 从这个角度上,每次你点击了Android Studio窗口上方工具栏中的运行按钮,同时选中应用程序运行配置,可以肯定的是, ormlite_config.txt 在生成的.apk文件将高达最新与您的模型类或DatabaseConfigGenerator本身做出任何改变。

  • From this point on, every time you click the "Run" button in the toolbar at the top of the Android Studio window, while the "app" run configuration is selected, you can be sure that the ormlite_config.txt in the resulting .apk will be up-to-date with whatever changes you made to your model classes or the DatabaseConfigGenerator itself.

对于这个解决方案我已经采取灵感来自于以下两个SO答案:


  1. 安装摇篮运行Java可执行文件Android Studio中

为ORMLite配置的Andr​​oid一代工作室运行配置

最后,我决定放在一起完整的解决方案在一个地方,并详细描述它在这里。

有三个小的警告这一做法,并因人而异你是否能和他们一起生活:


  1. 这仅适用于运行行动,而不是品牌的行动,这意味着你将不得不在情况下,甚至启动运行,当你只是想建立一个.apk文件,但不实际运行它。由此产生的apk文件然后可以在应用程序/编译/ APK / ,被命名为取决于你正在构建的变种(建立调试它通常是应用程序,调试 - 发现unaligned.apk,并发布,APP-release.apk)。

  1. This only applies to the "Run" action, not the "Make" action, which means that you will have to initiate a run even in cases when you just want to build an .apk, but not actually run it. The resulting .apk can then be found under app/build/apk/ and is named depending on the variant you are building (for debug builds it will usually be app-debug-unaligned.apk, and for releases, app-release.apk).

这做法本身就意味着摇篮感知使将为您单击运行,每次运行两次,这将导致稍长的构建时间,但我还没有发现多大的差别(在安卓插件的gradle是足够聪明的识别哪些资源没有自上次构建变化,会跳过很多不必要的步骤,第二次左右),因此可能有20%不再建造时间(不持有我数)

This approach in itself means the "Gradle-aware make" will run twice every time you click "Run", which will result in slightly longer build times, but I haven't noticed much of a difference (the android gradle plugin is smart enough to recognize which resources have not changed since the last build and will skip a lot of unnecessary steps the second time around), resulting in maybe a 20% longer build time (don't hold me to the number).

如果你是在一个团队的设置工作,使用版本控制,它吸收一点点,这个配置不是可追踪,所以在你的团队每一个开发商将不得不经历这个过程单独或不能简单地检查出来的,比方说,git的存储库中的一部分。这是由于运行配置你的项目的根中定义,在.idea / workspace.xml,这被普遍认为是东西,不应该在版本控制进行跟踪,因为它是机器的具体事实。

If you are working in a team setting and are using version control, it sucks a little bit that this configuration is not trackable, so every developer in your team will have to go through this process individually and can't simply check it out as part of the repository in, say, .git. This is due to the fact that the run configurations are defined inside your project root, under .idea/workspace.xml, which is universally agreed to be something that should not be tracked in version control as it is machine specific.

有可能的方式来消除对一支球队的水平定义你这样的运行配置的过程中的一些手工步骤,但它似乎并不可能在一个干净的方式完全自动化。 我可能是错的,但并随时让我知道,如果是这样的话。

There are probably ways to remove some manual steps of the process of defining your run configuration like this on a team level, but it doesn't seem possible to fully automate it in a clean way. I could be wrong though and feel free to let me know if that's the case.

希望这有助于!

推荐答案

的问题是资源的编译的由 AAPT R.java 生产(从而之前 javac的)。那些编译资源的,然后用于构建APK。据我所知那些的编译资源的只是一种zip归档。

The problem is that the resources are compiled by aapt when R.java is produced (and so before javac). Those compiled resources are then used to build the apk. AFAIK those compiled resources is just a kind of zip archive.

那么,要实现你的目标,你需要修改这些的编译的javac编译的后资源。

So, to achieve your goal you need to modify those compiled resources after javac compilation.

您可以尝试定义一个新的任务(我们称之为 addOrmToRes )调用 AAPT 与所需参数修改在编译资源的。

You can try to define a new task (let's call it addOrmToRes) invoking aapt with required arguments to modify the compiled resources.

AAPT位于&LT; ANDROID_SDK_HOME&GT; /编译工具/&LT;&版GT; /

该AAPT使用表明:

aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]
   Add specified files to Zip-compatible archive.

所以执行是这样的:

So executing something like this:

aapt add /build/apk/myapp.apk ormlite_config.txt

或本

aapt add <the_path_to_compiled_resources> ormlite_config.txt

在新的自定义任务 addOrmToRes 应该做的伎俩。因此,要回答你的修改3 AAPT添加可能是解决方案

in your new custom task addOrmToRes should do the trick. So to answer to your edit 3 : aapt add is probably the solution.

要它在构建整合,这样的事情应该工作:

To integrate it in the build, something like this should work:

runOrmGenTask.dependsOn(variant.javaCompile) 
addOrmToRes.dependsOn(runOrmGenTask)
addOrmToRes.dependsOn(<the task creating the apk>)
<the task signing the apk>.dependsOn(addOrmToRes)

请注意,我没有发现这里的每一个任务。但我猜你的想法。

Note that I didn't identify every tasks here. But I guess you get the idea.

这篇关于(摇篮和OrmLite配置)如何添加资源文件Java已经被编译之后,但.apk文件之前生成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆