gpt4 book ai didi

android - (Gradle和OrmLite配置)如何在Java编译之后但.apk生成之前添加资源文件?

转载 作者:行者123 更新时间:2023-12-03 16:55:25 25 4
gpt4 key购买 nike

注意:我已经接受了一个答案,并授予了赏金BUT,但最终决定我对这个问题的方法远非最佳。经过进一步的思考,我得出的结论是,在构建过程中修改.apk可能不是实现此目标并使之长期运行的最安全或最可持续的方法。

我在此问题的最底部添加了一种替代方法,最终可以完成相同的操作。我选择使用的这种方法虽然不完美,但不需要通过黑客弄乱.apk程序集的内部。

我想将OrmLite与它的pre-generated configuration file一起使用,它由普通的Java类生成,如下所示:

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 / raw /下,看起来像这样:
#
# 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--
#################################

每次对其本身或一个Model类进行修改时,都需要直接通过Java运行该类,以便使配置最新,并且OR映射可以按预期运行。

由于我最近切换到Android Studio和Gradle,并且喜欢构建过程的灵活性和自定义选项,因此我想通过我的应用程序的build.gradle自动生成上述ormlite_config.txt。我已经定义了一个可运行的任务,该任务从app / build / classes内部运行DatabaseConfigGenerator.class并生成配置,并且我还将其与compileJava Gradle任务挂钩,因此该配置是在编译Java文件并生成后生成的。 .class文件是最新的:
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
}
}

这很好用,我可以在app / src / main / res / raw中看到ormlite_config.txt的变化,但是由于某些原因(我猜想任务排序不正确),当我提取.apk时,它仍然包含来自先前版本的ormlite_config.txt已过时...

谁能告诉我或推荐我链接到Android Gradle构建系统的构建任务顺序?我已经搜寻了几天,却找不到它。在编译Java文件之后,但在打包.apk之前,我需要找到一种生成ormlite_config.txt的方法,因此将其包括在内。

像这样自动化它真是太棒了,因为然后它会在每个构建过程中一步完成,因为配置将始终与模型类保持最新,而我不必再考虑了。我有一种直觉,认为他可以做到,我只需要弄清楚到底是怎么做到的。

免责声明:我仍处于学习Gradle的工作原理的起步阶段,因此我对这里提到的某些事情的理解可能还很遥远。请告诉我是否要学习!

编辑1:

我认为让DatabaseConfigGenerator将文件写入NOT会更有意义:
app/src/main/res/raw 

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

由于AFAIK,这是将最终资源打包到.apk中之前的位置(我可能是错的,因此请更正)。

根据@pepyakin的回答,我还稍微更新了build.gradle:
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)
}
}

再次,这运行良好,并在Gradle控制台中输出以下内容:
...

: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

...

因此,在上面我看到 app:genOrmConfigDebug任务被整齐地夹在Java编译和打包之间。

但是,由于某种原因,生成的.apk STILL包含一个较早版本的ormlite_config.txt,它与我对模型类所做的更改(例如,定义新的@DatabaseField)不是最新的!

我的预感是:
  • 我将ormlite_config.txt写入错误的位置(
    会很奇怪,因为它在一秒钟后被拾取到.apk中
    构建),或
  • 提取app/build/res/all/<variant_name>/raw的内容
    在执行compile<variant_name>Java之前

  • 如果是以后的版本,我不知道该如何处理...任何建议,不胜感激!

    编辑2:

    看来 2.确实是。我并排打开了两个目录( app/build/apkapp/build/res/all/<variant_name>/raw),事件的顺序为:
  • 最新的ormlite_config.txt是在app/build/res/all/<variant_name>/raw
  • 内部生成的
  • .apk是在app/build/apk
  • 内部创建的
  • 提取.apk,并在res/raw下查看后,一个生成版本之前过时的ormlite_config.txt位于


  • 如果熟悉Gradle .apk生成过程的内部流程的人可以告诉我我在这里缺少的内容,我将非常感谢!

    编辑3

    我还没有放弃!经过更多研究后,我发现了 diagram of the android gradle build system workflow

    根据该图,资源(在/ res下)被合并和收集,并且R类在编译Java代码之前被更新。这是有道理的,因为如果类引用R中未包含的资源值,则编译将失败。

    所以现在我确定与我的情况相关的三个步骤的执行顺序是:
  • 资源已合并和组装,R.java已更新
  • Java被编译成类
  • .apk放在一起

  • 现在,如果我的ormlite_config.txt是在Java编译后重新生成的(如我在EDIT 2中包含的build.gradle片段中所定义的那样),但最后却不是生成的.apk的一部分(文件而是),即使我将其放置在步骤3之前的 /build/res/all/<variant name>/raw下,这也仅意味着要包含在.apk中的实际资源文件已经在步骤1和2之间移至 buid/res/all/<variant name>以外的其他位置。

    现在我只需要弄清楚那里是什么,所以我可以将新生成的ormlite_config.txt放在任何可能或可行的地方...

    和以前一样,如果有人可以启发我解决这个问题,我将非常感激。

    替代(简化)方法

    正如问题的开头所述,最终,我决定采用一种更简单的方法,而不是像我最初打算的那样对.apk汇编过程进行修改。

    步骤如下:
  • 对数据库配置生成器类进行编码,以将ormlite_config.txt写入应用程序的src/main/res/raw中(您可以将我在本问题的最开头所包含的DatabaseConfigGenerator类用作模板)。使此类与应用程序的包结构保持一致,不要将其制成单独的应用程序或模块,没有理由这样做。因此,您可以将其放入com.your.app.database或任何其他内容。
  • 在Android Studio的顶部工具栏中,单击“制作”和“运行”按钮之间的小下拉框:


  • 它将打开一个菜单,您可以在其中选择现有的运行配置之一或编辑配置。选择以后:


  • 将打开“运行/调试配置”窗口,在该窗口的左上角,应单击绿色的小加号,然后选择“应用程序”作为新配置的类型:


  • 将打开一个表单,您将在其中定义DatabaseConfigGenerator的运行配置,因为它需要作为Java应用程序与Android应用程序分开运行。您只需在此处修改几个字段。首先,给新的运行配置起一个名称(1),然后选择DatabaseConfigGenerator作为主类(2),然后在模块类路径下选择您的应用程序所在的模块,其中您的DatabaseConfigGenerator和模型类位于其中(3),然后删除所有通过选择“启动前”部分中的条目并单击红色减号(4),最后单击“应用”(5)。现在,您可以单击左侧“Android应用程序”部分下的应用程序(6)。


  • 您在这里要做的最后一件事也是最重要的一件事,它将把所有内容放在一起,以使您的应用程序首先自行构建,然后生成最新的ormlite_config.txt,然后再次自行构建(尽管比第一次),以便该新生成的配置实际上包含在最终的.apk中。为此,您需要修改应用程序运行配置的“启动前”部分(1)。您可能已经在这里有了“可识别Gradle的代码”,这实际上是在通常的构建过程中编译您的应用程序并将其打包为.apk的过程。如果没有,请将其添加为第一项。之后,添加另一个条目,但是这次是“数据库配置生成器”运行配置,您已经向后创建了几步,因为这将确保ormlite_config.txt是基于新编译的模型类生成的,并且是最新的。最后,添加另一个“Gradle-aware Make”,以确保生成了一个新的.apk,它现在还将包括此最新的ormlite_config.txt现在单击“应用”(2),就这样!


  • 从现在开始,每次单击Android Studio窗口顶部工具栏中的“运行”按钮时,在选择“应用”运行配置后,您可以确保生成的.apk中的ormlite_config.txt将您对模型类或DatabaseConfigGenerator本身所做的任何更改都是最新的。

  • 对于此解决方案,我从以下两个SO答案中获得了启发:
  • Setup Gradle to run Java executable in Android Studio
  • Android Studio run configuration for ORMLite config generation

  • 最后,我决定将完整的解决方案放在一个地方,并在此处进行详细描述。

    此方法有三个小警告,YMMV关于您是否可以与它们一起生活:
  • 这仅适用于“运行”操作,而不适用于“制造”操作,这意味着即使在您只想构建.apk而不实际运行它的情况下,也必须启动运行。然后,可以在app/build/apk/下找到生成的.apk,并根据要构建的变体进行命名(对于调试版本,通常将其命名为app-debug-unaligned.apk;对于发行版,则通常为app-release.apk)。
  • 这种方法本身意味着,每次单击“运行”时,“可识别Gradle的make”将运行两次,这将导致构建时间略长,但是我没有注意到很大的不同(android gradle插件很聪明足以识别自上次构建以来哪些资源没有发生变化,并且第二次将跳过很多不必要的步骤),从而可能使构建时间增加20%(请耐心等待)。
  • 如果您在团队环境中工作并且正在使用版本控制,这有点让人无法识别此配置,因此您团队中的每个开发人员都必须单独进行此过程,并且不能简单地将其 check out 为仓库中的一部分,例如.git。这是由于以下事实:运行配置是在项目根目录下的.idea / workspace.xml下定义的,该协议(protocol)已被普遍认为是特定于计算机的,因此不应在版本控制中进行跟踪。

  • 可能有一些方法可以在团队级别上删除定义运行配置的过程中的一些手动步骤,但是似乎不可能以一种干净的方式完全自动化它。 但我可能是错的,如果是这种情况,请随时告诉我。

    希望这可以帮助!

    最佳答案

    问题在于,生成aapt时,资源是由R.java编译的(因此 javac之前是)。这些编译的资源然后用于构建apk。 AFAIK那些编译后的资源只是一种zip存档。

    因此,要实现您的目标,您需要在javac编译后修改那些已编译的资源。

    您可以尝试定义一个新任务(将其称为addOrmToRes),并使用必需的参数调用aapt来修改已编译的资源。

    aapt位于<ANDROID_SDK_HOME>/build-tools/<version>/

    aapt用法表示:

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

    所以执行这样的事情:
    aapt add /build/apk/myapp.apk ormlite_config.txt

    或这个
    aapt add <the_path_to_compiled_resources> ormlite_config.txt

    在新的自定义任务addOrmToRes中应该可以解决问题。因此,要回答您的,请编辑3 :aapt add可能是解决方案。

    要将其集成到构建中,类似这样的方法应该起作用:
    runOrmGenTask.dependsOn(variant.javaCompile) 
    addOrmToRes.dependsOn(runOrmGenTask)
    addOrmToRes.dependsOn(<the task creating the apk>)
    <the task signing the apk>.dependsOn(addOrmToRes)

    请注意,我没有在此处识别所有任务。但是我想你明白了。

    关于android - (Gradle和OrmLite配置)如何在Java编译之后但.apk生成之前添加资源文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24323709/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com