Call an Android build-tool from an Eclipse "builder"? - android

I've been asked to automate the process of building a 'secondary dex' that can be loaded by a DexClassLoader. The idea is that instead of manually exporting to a .jar file and then running the dx script to add classes.dex to a new .jar in the main project's assets directory, normal compilation of the secondary project would automatically copy a dynamically loadable .jar to the main project.
It does look like I can do this by marking the secondary project as an Android Library (so that it compiles to a .jar) and adding an Eclipse Builder that calls the dx script. I've got a bash script and a .launch wrapper for it that passes ${project_loc}/bin/${resource_name}.jar to the script; if I place the bash script in the main project's root directory, %0 tells me where to copy the loadable .jar.
Of course, dx is not on the path. I figured I'd do a `which adb` and then use find ... but adb is not on the path, either!
So, my question: Is there an Eclipse string variable that contains the location of the Android SDK?

A coworker pointed out that ${project_classpath} contains a path to annotations.jar in the SDK directory. That let me write this script:
#!/bin/bash
#####
##### Get the directory this script is running in.
##### We will write our output to ${client}/assets
#####
client=${0%/*}
#####
##### Get the input parameter; calculate the output
#####
input=$1
output=${client}/assets/${input##*/}
#####
##### Use the classpath parameter to find the latest dx script:
#####
# Turn : into \n
classpath=${2//:/\\n}
# Find the line that refers to annotations.jar
annotations=`echo -e $classpath | grep annotations`
# Strip the filename
path=${annotations%/*}
# There may be multiple copies. We get access time and path.
# We output : instead of \n because bash "Word Splitting" is complicated.
jars=`find $path -name dx.jar -printf "%A# %p:"`
until [ "$jars" ]
do
path=${path}/..
jars=`find $path -name dx.jar -printf "%A# %p:"`
done
# Turn : into \n
jars=${jars//:/\\n}
# We want the last accessed jar
sorted=`echo -e "$jars" | sort -nrk 1,2`
# Get the jar filename
last_used=`echo -e "$sorted" | grep -om 1 "/.*$"`
# Strip the filename
last_path=${last_used%/*}
# Find the dx script
dx=`find $last_path -name dx`
until [ "$dx" ]
do
last_path=${last_path}/..
dx=`find $last_path -name dx`
done
#####
##### Add classes.dex to input jar
#####
$dx --dex --keep-classes --output $output $input
Here's it's .launch file, with the project name and path redacted:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.core.ATTR_REFRESH_RECURSIVE" value="false"/>
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?>
<resources>
<item path="/MAIN_PROJECT_NAME/assets" type="2"/>
</resources>}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/../MAIN_PROJECT_DIRECTORY/secondary-dexxer"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="${project_loc}/bin/${resource_name}.jar
${project_classpath}"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>
Not exactly optimal, and definitely not something I can add to the source tree (we have people who use Windows for some reason) but a start: painful though some of the bash "Word Splitting" issues were, they presumably do pale next to the learning curve that will be involved in turning this into a 'proper' Eclipse plugin, in Java.

Fwiw, I never did find "an Eclipse string variable that contains the location of the Android SDK". Instead, what I did was
Read the dx script and notice that it just passed arguments to dx.jar.
Add the most recent available dx.jar to my Builder project, and simply call it directly, from my Java code. The source was not hard to find. It turned out that the main main(String[]) simply dispatched to one of several internal main(String[]) methods, so I just called the right one directly.
Split my Builder into two pieces: a) a 'stand-alone dexxer' which is just a jar file that can be called from an ant action, and which calls into dx.jar; and b) an Eclipse Builder which contains the build control logic and a bit of Eclipse console code, and which calls into the stand-alone dexxer.
This worked fine. We figured that if Google ever released a dx.jar that somehow offered significantly better dexification, we could just rebuild the Builder with the new jar; this hasn't been an issue, yet.

Related

How to check obfuscation results of flutter app?

In native android development I could check whether my minifyEnabled had taken effect.
I used this script (in linux) which allows me to extract the apk and view the java files to see if my code is readable, or has been obfuscated :
#! /bin/bash
d2j=/work/installs/dex2jar-2.0
jdgui=/work/installs/jd-gui-1.4.0.jar
apk_loc=/work/projects/my_app/build/app/outputs/app-release.apk
mkdir -p /work/tmp/dex
rm -rf /work/tmp/dex/*
cd /work/tmp
cp $apk_loc ./app-release.zip
unzip app-release.zip -d dex
cd dex
chmod +x $d2j/*.sh
$d2j/d2j-dex2jar.sh classes.dex
java -jar $jdgui classes-dex2jar.jar
If I use this script on a flutter apk, I don't see any files containing anything related to my original code.
Flutter's dart code is compiled to native and embedded to flutter.so runtime, so decompiling flutter is not as easy as byte code of java/kotlin
However decompiling .so file is possible. You can use the toolchains inside the android ndk to perform the type of disassembling you want to
./android-ndk-r15b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -T "flutter.so | less
but this is just give you an objdump.

How are shared libraries packed into apk?

I'm working on some script for custom build system and i need to pack some .so files in android apk (aars with native libs are not yet supported).
I've invoked ./gradlew assembleDebug --debug for the apk project that depends on aar with native libraries (.so) to get full log but did not find any .so files paths passed to aapt or any other android build tool (though i've seen .so stripping commands with ndk strip tool).
How is it done in details? Does aapt tool do it? Are there any aapt arguments for this or they should be just stored on some specific paths (eg. libs).
Yes, aapt via an invocation like aapt add -v MyApp.apk lib/armeabi/libMyLib.so.
Use aapt --list MyApp.apk to ensure that it is in the apk with that directory structure (a lib folder, an armeabi subfolder, and MyApp.apk within that).
After installing the app, look in /data/app/com.Company/android/MyApp-X/lib/arm/ for libMyLib.so to ensure it got copied.
If problems, logcat output is actually really useful, telling you the path tried, the function tried, etc.
Obviously, replace the app name, company name, and armeabi architecture to fit your projects' parameters.

Jenkins - Warnings Plugin & IntelliJ IDEA Parser

I am having issues opening the files that contains IntelliJ IDEA Inspection warnings using Jenkins and Warnings Plugin.
The path to my files looks weird - file://$PROJECT_DIR$/app/src/main..../Foo.java in the .xml generated files by ./inspect.sh
When I click on the file I get the following error:
`java.io.IOException: Failed to copy file:/$PROJECT_DIR$/app/src/main/java`/
These are some screenshots of my files:
I am using the ./inspect.sh from Android Studio, not from actual IntelliJ. Could that be the problem?
Thanks in advance.
In the end I have added an extra build step where I clean the .xml files that are output by ./inspect.sh.
I have also added a line of code that removes all the inspects related to the build (generated) directory. Hope this helps anyone who was stuck with this issue.
Below you have the tweaked inspect.sh file and the two separate build steps:
inspect.sh
#!/bin/sh
#
# ------------------------------------------------------
# Android Studio offline inspection script.
# ------------------------------------------------------
#
export DEFAULT_PROJECT_PATH="$(pwd)"
cd ..
exec "MacOS/studio" inspect "$#"
Build Step 1
cd ${WORKSPACE}/inspectionsresults
rm *.xml
cd "${ANDROID_STUDIO_HOME_BIN}"
./inspect.sh ${WORKSPACE} ${WORKSPACE}/inspections_profile.xml ${WORKSPACE}/inspectionsresults -v2 -d ${WORKSPACE}/app
Build Step 2
cd ${WORKSPACE}/inspectionsresults
sed -i .bak "s,file://\\\$PROJECT_DIR\\\$,${WORKSPACE},g" *.xml
sed -i .bak "s,file:///,,g" *.xml
/usr/local/bin/xml ed -L -d "/problems/problem[contains(file,'generated')]" *.xml
rm *.bak
I have used xmlstarlet to remove the "generated" problems.
brew install xmlstarlet

Script to generate a copy of android project with another package name

i'm looking to write (or find :D) a script to convert an exisisting Android Project Source to a copy with another package name, that i provide.
Source have package like it.pinco.pallino.source and Copy will be like it.pinco.pallino.test1 etc etc...where test1 is a parameter.
I'm looking to use ANT or this script https://github.com/lijunjieone/RenameAndroidPackage, but there's no README and i don't know python..
Any suggestion?
Thanks
This is what I have written to change the package name without having to duplicate any code (for maintainability reasons, I use the same code for the free and pro version of my app).
Here's the script that converts Free version to Pro. It should be pretty easy to adapt it to your needs (provided you work under Linux, or use Cygwin or a linux virtual machine)
# 1- rename src folder
mv src/com/lulo/scrabble/dico src/com/lulo/scrabble/dicopro
# 2- replace references to package in Java, XML and CFG (proguard) files
find . \( -name "*xml" -o -name "*.java" -o -name "*.cfg" \) -print0 | xargs -0 sed -ri 's/scrabble.dico/scrabble.dicopro/g'
# 3- change the application name
find . -name "*.xml" -print0 | xargs -0 sed -ri 's/\(Free\)/Pro/g'
# 4- change the icon
cp ../IMAGES/LOGODICO_V2_2012_96px.png res/drawable-xhdpi/icon.png
cp ../IMAGES/LOGODICO_V2_2012_72px.png res/drawable-hdpi/icon.png
cp ../IMAGES/LOGODICO_V2_2012_48px.png res/drawable-mdpi/icon.png
cp ../IMAGES/LOGODICO_V2_2012_36px.png res/drawable-ldpi/icon.png
After this I just need to Refresh, Build and Export using Eclipse.

aapt not working with absolute path

I have a kind of strange issue. In my bash script or Makefile, using aapt with absolute path does not work but if I am in the local directory it does.
If I do the following, it does not work:
aapt add $OUT/device.jar $OUT/classes.dex
The command does run and print this output:
'/homes/rsevile/CS307/bin/Device/classes.dex'...
But when trying to load the jar, the class that I am trying to load end up being not found.
The following does work though:
cd $OUT
aapt add device.jar classes.dex
Printing:
'classes.dex'...
This is the whole code being executed in the script (which works):
javac -d $(OUT)/classes -classpath ./layoutlib.jar src/com/device/client/*.java
jar cf $(OUT)/device.jar $(OUT)/classes $(OUT)/layoutlib
dx --dex --no-strict --output=$OUT/classes.dex $OUT/device.jar
cd $OUT
aapt add device.jar classes.dex
cd $ROOT
adb push $OUT/device.jar $ANDROID_OUT_DIR
I am confused why my class ends up being not found when using an absolute path with aapt.
Could anyone please explain to me why it is not working and how I could fix it to use a proper absolute path please?
Thank you.
I realized that aapt actually keeps the absolute path, there is no way around it.
I fixed the problem by reusing jar and using the -C option that lets me specify a directory.

Categories

Resources