android - (Gradle and OrmLite config) How to add resource file after Java has been compiled but before .apk is generated? -
note: have accepted reply , awarded bounty, but, have in end decided approach issue far optimal. after farther thought have come conclusion modifying .apk during build process not safest or sustainable way accomplish , maintain working long term.
i have added alternative approach bottom of question, accomplishes same thing in end. approach opted utilize instead, while not perfect, not require messing around internals of .apk assembly through hacks.
i want utilize ormlite pre-generated configuration file, generated plain java class, 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); } }
the resulting ormlite_config.txt file placed under res/raw/, , looks 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-- #################################
this class needs run straight via java every time either or 1 of model classes modified, configuration up-to-date , or mapping can function expected.
since switched on android studio , gradle, , love flexibility , customization options build process, automate generation of aforementioned ormlite_config.txt via build.gradle app. have defined working task runs databaseconfiggenerator.class within app/build/classes , generates config, , have hooked compilejava gradle tasks, config generated after java files compiled , .class files 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 ${variant.name}" javatask.finalizedby runormgentask } }
this works , can see ormlite_config.txt alter within app/src/main/res/raw, reason (i guess task ordering not correct), when extract .apk, still contains outdated ormlite_config.txt previous build...
can tell me or refer me link build task order of android gradle build system? i've been searching far , wide couple of days , can't find it. need find way generate ormlite_config.txt after java files compiled, before .apk packaged, included.
it awesome automated because happen during every build, in 1 step, because config up-to-date model classes , never have think again. have gut feeling can done, need figure out how exactly.
disclaimer: i'm still @ origin stages of learning how gradle works, understanding of things mentioned here way off. please tell me if is, want learn!
edit 1:
i figured create more sense have databaseconfiggenerator write file not under:
app/src/main/res/raw
but under
app/build/res/all/<variant_name>/raw
since, afaik, final resources placed before packaged .apk (i wrong, please right me if am).
i updated build.gradle slightly, according @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, runs fine , outputs next in gradle console:
... :app:processdebugresources up-to-date :app:generatedebugsources up-to-date :app:compiledebugjavanote: input files utilize or override deprecated api. note: recompile -xlint:deprecation details. :app:predexdebug up-to-date :app:dexdebug :app:genormconfigdebug writing configurations /home/user/development/app/com.example.app.android/app/build/res/all/debug/raw/ormlite_config.txt wrote config class com.example.app.model.table1 done. :app:processdebugjavares up-to-date :app:validatedebugsigning :app:packagedebug :app:assembledebug ...
so above see app:genormconfigdebug
task neatly sandwiched between java compilation , packaging.
however, reason, resultant .apk still contains ormlite_config.txt 1 build earlier, it's not up-to-date changes create model class (e.g. defining new @databasefield)!
my hunch either:
i'm writing ormlite_config.txt wrong location (which weird, since picked .apk after sec build), or the contents ofapp/build/res/all/<variant_name>/raw
picked before compile<variant_name>java
executed if it's later, have no thought how handle this... suggestions appreciated!
edit 2:
it seems 2. case. opened 2 directories side side (app/build/apk
, app/build/res/all/<variant_name>/raw
) , order of events is:
app/build/res/all/<variant_name>/raw
the .apk created within app/build/apk
after extracting .apk, , looking under res/raw
, outdated ormlite_config.txt 1 build ago inside i appreciate if familiar internal goings-on of gradle .apk generation process tell me missing here!
edit 3
i'm not giving on yet! after more research, found diagram of android gradle build scheme workflow.
according diagram, resources (under /res) merged , collected, , r class updated right before compiling java code. makes sense, because compilation fail if classes reference resource values not included in r.
so know sure order of execution 3 steps relevant case is:
resources merged , assembled, r.java updated java compiled classes the .apk set togethernow, if ormlite_config.txt re-generated after java compilation (as defined in build.gradle snippet included in edit 2), in end not part of resulting .apk (the before version of file instead) though place under /build/res/all/<variant name>/raw
before step 3., can mean actual resource files included in .apk moved somewhere other buid/res/all/<variant name>
, between steps 1. , 2.
now have figure out is, can set freshly generated ormlite_config.txt there if it's in way possible or feasible...
as before, extremely thankful if enlighten me on issue.
an alternative (simpler) approachas stated @ top of question, in end decided go alternative approach much simpler , not hack of .apk assembly process, intended do.
the steps follows:
code database configuration generator class write ormlite_config.txt
int app's src/main/res/raw
(you can utilize databaseconfiggenerator class included @ top of question template). maintain class withing bundle construction of app, don't create separate application or module, there not reason this. can set within com.your.app.database or whatever.
in top tool bar in android studio, click on little drop-down box between "make" , "run" buttons:
it open menu can take 1 of existing run configurations or edit configurations. take later: the "run/debug configurations" window open, in top left corner should click little greenish plus sign , select "application" type new configuration: a form open define run configuration databaseconfiggenerator, needs run java application, separately android app. there few fields need modify here. first, give new run configuration name (1), select databaseconfiggenerator main class (2), under module classpath take module of app wherein databaseconfiggenerator , model classes reside (3), remove entries "before launch" section selecting them , clicking reddish minus sign (4), , finally, click "apply" (5). can click app under "android application" section left (6). the lastly thing need here of import one, set create app first build itself, generate up-to-dateormlite_config.txt
, , build 1 time again (albeit much faster first time) newly generated config included in final .apk. in order accomplish this, need modify "before launch" section of app's run configuration (1). chances have "gradle-aware make" in here, compiles app , packages .apk during usual build process. if don't have it, add together first entry. after that, add together entry, time "database configuration generator" run configuration, created few steps back, ensure ormlite_config.txt
generated based on freshly compiled model classes , up-to-date. , finally, add together "gradle-aware make", create sure new .apk generated, include up-to-date ormlite_config.txt
. now click "apply" (2), , that's it! from point on, every time click "run" button in toolbar @ top of android studio window, while "app" run configuration selected, can sure ormlite_config.txt
in resulting .apk up-to-date whatever changes made model classes or databaseconfiggenerator itself. for solution i've taken inspiration next 2 answers:
setup gradle run java executable in android studio
android studio run configuration ormlite config generation
in end decided set finish solution in single place , describe in detail right here.
there 3 little caveats approach, , ymmv on whether can live them:
this applies "run" action, not "make" action, means have initiate run in cases when want build .apk, not run it. resulting .apk can found under app/build/apk/
, named depending on variant building (for debug builds app-debug-unaligned.apk, , releases, app-release.apk).
this approach in means "gradle-aware make" run twice every time click "run", result in longer build times, haven't noticed much of difference (the android gradle plugin smart plenty recognize resources have not changed since lastly build , skip lot of unnecessary steps sec time around), resulting in maybe 20% longer build time (don't hold me number).
if working in team setting , using version control, sucks little bit configuration not trackable, every developer in team have go through process individually , can't check out part of repository in, say, .git. due fact run configurations defined within project root, under .idea/workspace.xml, universally agreed should not tracked in version command machine specific.
there ways remove manual steps of process of defining run configuration on team level, doesn't seem possible automate in clean way. i wrong though , sense free allow me know if that's case.
hope helps!
the problem resources compiled aapt
when r.java
produced (and before javac). compiled resources used build apk. afaik compiled resources kind of zip archive.
so, accomplish goal need modify compiled resources after javac compilation.
you can seek define new task (let's phone call addormtores
) invoking aapt
required arguments modify compiled resources.
aapt located under <android_sdk_home>/build-tools/<version>/
the aapt usage indicates :
aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...] add together specified files zip-compatible archive.
so executing this:
aapt add together /build/apk/myapp.apk ormlite_config.txt
or this
aapt add together <the_path_to_compiled_resources> ormlite_config.txt
in new custom task addormtores
should trick. reply edit 3 : aapt add
solution.
to integrate in build, should work:
runormgentask.dependson(variant.javacompile) addormtores.dependson(runormgentask) addormtores.dependson(<the task creating apk>) <the task signing apk>.dependson(addormtores)
note didn't identify every tasks here. guess idea.
android build gradle android-studio ormlite
No comments:
Post a Comment