I've read How can I build an Android apk without Gradle on the command line? and How to compile an Android app with aapt2 without using any build tools?, but both answers don't seem to align with my goal (tried to use aar file to build android application that have external dependency manually for the sake of learning and understanding how these android build tool works internally).
I download the aar file from https://maven.google.com/web/index.html#androidx.constraintlayout:constraintlayout:2.2.0 and used this build script as a guide to assemble android application package without gradle/android studio, it successfully builds without prompting any errors, however it throws an error on runtime:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.helloworld/com.example.helloworld.main}: android.view.InflateException: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3645)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:138)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7965)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)
Caused by: android.view.InflateException: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
Caused by: android.view.InflateException: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
Caused by: java.lang.ClassNotFoundException: androidx.constraintlayout.widget.ConstraintLayout
The reason of crash is pretty obvious, it can't resolve symbol ConstraintLayout
that are used on the layout xml file, but I'm not sure how to fix this, I have tried linking the constraintlayout-2.2.0/classes.jar
library but it still throws an error after I rebuild it.
Here's the step on how I build the application (assuming the downloaded aar file already extracted and debug.keystore already created):
aapt2 compile --dir res -o resources.zip
aapt2 compile --dir constraintlayout-2.2.0/res -o resources-constraintlayout.zip
aapt2 link --manifest AndroidManifest.xml --auto-add-overlay -R ./resources-constraintlayout.zip --java generated/ -I ~/Android/Sdk/platforms/android-34/android.jar -o ./sample.apk resources.zip
javac -classpath constraintlayout-2.2.0/classes.jar -classpath ~/Android/Sdk/platforms/android-34/android.jar -source 17 -target 17 -sourcepath com:generated generated/com/example/helloworld/R.java com/example/helloworld/main.java -d build/obj
d8 --release --classpath constraintlayout-2.2.0/classes.jar --classpath ~/Android/Sdk/platforms/android-34/android.jar --output . $(find build/obj/ -type f)
zip -uj ./sample.apk classes.dex
zipalign -p -f -v 4 ./sample.apk ./aligned_sample.apk
apksigner sign --ks debug.keystore --ks-pass pass:android --out ./signed_sample.apk ./aligned_sample.apk
To reproduce the issue, I have created a git repository that contains the build script and source code file on there.
EDIT:
turns out the classes.jar
file isn't really linked properly (but the compiler remain silent, damn). and to join jar file in the javac
command I need to separate it by :
instead of add another -classpath
option
and after I update the build script, one by one errors pop up one after another asking to fulfill dependencies that don't exist (I didn't expect there to be so many dependencies and I'm not even sure if it will be used)
I have finished some of it but there is still some left and I don't know how to resolve it:
Warning in libs/savedstate-1.2.1/classes.jar:androidx/savedstate/Recreator.class:
Type `androidx.lifecycle.LifecycleEventObserver` was not found, it is required for default or static interface methods desugaring of `androidx.savedstate.Recreator`
Warning in libs/activity-1.9.3/classes.jar:androidx/activity/PipHintTrackerKt$trackPipAnimationHintView$2.class:
Type `kotlinx.coroutines.flow.FlowCollector` was not found, it is required for default or static interface methods desugaring of `androidx.activity.PipHintTrackerKt$trackPipAnimationHintView$2`
Warning in libs/core-1.15.0/classes.jar:androidx/core/app/ComponentActivity.class:
Type `androidx.lifecycle.LifecycleOwner` was not found, it is required for default or static interface methods desugaring of `androidx.core.app.ComponentActivity`
Warning in libs/appcompat-resources-1.7.0/classes.jar:androidx/appcompat/widget/ResourceManagerInternal$ColorFilterLruCache.class:
Type `androidx.collection.LruCache` was not found, it is required for default or static interface methods desugaring of `androidx.appcompat.widget.ResourceManagerInternal$ColorFilterLruCache`
Warning in libs/activity-1.9.3/classes.jar:androidx/activity/ComponentActivity.class:
Type `androidx.lifecycle.ViewModelStoreOwner` was not found, it is required for default or static interface methods desugaring of `androidx.activity.ComponentActivity`
Warning in libs/activity-1.9.3/classes.jar:androidx/activity/ComponentActivity.class:
Type `androidx.lifecycle.HasDefaultViewModelProviderFactory` was not found, it is required for default or static interface methods desugaring of `androidx.activity.ComponentActivity`
Warning in libs/emoji2-1.5.0/classes.jar:androidx/emoji2/text/EmojiCompatInitializer$1.class:
Type `androidx.lifecycle.DefaultLifecycleObserver` was not found, it is required for default or static interface methods desugaring of `androidx.emoji2.text.EmojiCompatInitializer$1`
Warning in libs/fragment-1.8.5/classes.jar:androidx/fragment/app/FragmentManagerViewModel$1.class:
Type `androidx.lifecycle.ViewModelProvider$Factory` was not found, it is required for default or static interface methods desugaring of `androidx.fragment.app.FragmentManagerViewModel$1`
Warning in libs/lifecycle-extensions-2.2.0/classes.jar:androidx/lifecycle/ViewModelProviders$DefaultFactory.class:
Type `androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory` was not found, it is required for default or static interface methods desugaring of `androidx.lifecycle.ViewModelProviders$DefaultFactory`
Warning in libs/fragment-1.8.5/classes.jar:androidx/fragment/app/FragmentManagerViewModel.class:
Type `androidx.lifecycle.ViewModel` was not found, it is required for default or static interface methods desugaring of `androidx.fragment.app.FragmentManagerViewModel`
Warning in libs/fragment-1.8.5/classes.jar:androidx/fragment/app/DialogFragment$4.class:
Type `androidx.lifecycle.Observer` was not found, it is required for default or static interface methods desugaring of `androidx.fragment.app.DialogFragment$4`
in short, the errors is about missing lifecycle, androidx.collection, and kotlinx coroutine core
I have tried download the lifecycle, androidx collection and kotlinx coroutine artifact but it still throw a same error (after check the jar content with unzip -l
I can confirm the symbol is indeed missing but I'm not sure where it is either)
EDIT 2: after looking at the build log closely, it's not an error, it just a warning and I think it's not necessarily need to be fixed.
and after looking at the logcat output closely, the error actually changed and I just didn't notice it earlier:
--------- beginning of crash
12-30 08:52:23.851 5289 5289 E AndroidRuntime: FATAL EXCEPTION: main
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Process: com.example.helloworld, PID: 5289
12-30 08:52:23.851 5289 5289 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.helloworld/com.example.helloworld.main}: android.view.InflateException: Binary XML file line #2 in com.example.
helloworld:layout/activity_main: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3645)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:138)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7965)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Caused by: android.view.InflateException: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Erro
r inflating class androidx.constraintlayout.widget.ConstraintLayout
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Caused by: android.view.InflateException: Binary XML file line #2 in com.example.helloworld:layout/activity_main: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Caused by: java.lang.reflect.InvocationTargetException
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at java.lang.reflect.Constructor.newInstance0(Native Method)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.createView(LayoutInflater.java:863)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1018)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:973)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:663)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:485)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:477)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.Activity.setContentView(Activity.java:3602)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.example.helloworld.main.onCreate(main.java:13)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8360)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8339)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1426)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3626)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:138)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7965)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/constraintlayout/widget/R$styleable;
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at androidx.constraintlayout.widget.ConstraintLayout.init(ConstraintLayout.java:1000)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: at androidx.constraintlayout.widget.ConstraintLayout.<init>(ConstraintLayout.java:595)
12-30 08:52:23.851 5289 5289 E AndroidRuntime: ... 27 more
12-30 08:52:23.851 5289 5289 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: androidx.constraintlayout.widget.R$styleable
12-30 08:52:23.851 5289 5289 E AndroidRuntime: ... 29 more
after seeing an error at runtime: androidx.constraintlayout.widget.R$styleable
, I found this post that tell me what is possibly goes wrong, and after checking the decompiled version using apktool, the generated R class is using different package name from what is printed on the logcat, so I add additional R file with package name that match the logcat version by adding --extra-packages
option on aapt link
command.
now the error fixed but I'm not sure if it's the appropriate way to use aar file because I'm not use all files that are presented in the archive such as R.txt, I don't know how the build system such as gradle handle aar file, but this manual process is enough to make me appreciate what a tool like gradle does under the hood, it's truly a magical tool.
EDIT 3: the previous warning in the build log can be hided by specifying --no-desugaring
option on d8
EDIT 4: it seems enable desugaring is the best for now, as it will cause an error on runtime if I disabled it:
01-01 19:27:59.128 10898 10898 W mple.helloworld: Accessing hidden method Ljava/lang/invoke/LambdaMetafactory;->metafactory(Ljava/lang/i
nvoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Lj
ava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; (blocked, linking, denied)
01-01 19:27:59.128 10898 10898 D AndroidRuntime: Shutting down VM
--------- beginning of crash
01-01 19:27:59.128 10898 10898 E AndroidRuntime: FATAL EXCEPTION: main
01-01 19:27:59.128 10898 10898 E AndroidRuntime: Process: com.example.helloworld, PID: 10898
01-01 19:27:59.128 10898 10898 E AndroidRuntime: java.lang.NoSuchMethodError: No static method metafactory(Ljava/lang/invoke/MethodHandl
es$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/M
ethodType;)Ljava/lang/invoke/CallSite; in class Ljava/lang/invoke/LambdaMetafactory; or its super classes (declaration of 'java.lang.inv
oke.LambdaMetafactory' appears in /apex/com.android.art/javalib/core-oj.jar)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at androidx.activity.ComponentActivity.<init>(ComponentActivity.kt:135)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at androidx.fragment.app.FragmentActivity.<init>(FragmentActivity.java:107)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at androidx.appcompat.app.AppCompatActivity.<init>(AppCompatActivity.java:96)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at com.example.helloworld.main.<init>(main.java:7)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at java.lang.Class.newInstance(Native Method)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:
95)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.Instrumentation.newActivity(Instrumentation.java:1348)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3538)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.j
ava:101)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(Transactio
nExecutor.java:138)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor
.java:95)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7965)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:
548)
01-01 19:27:59.128 10898 10898 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)
It cannot find the resources of constraintlayout
.
These libraries seem to be missing:
androidx.constraintlayout:constraintlayout:2.2.0
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1
androidx.lifecycle:lifecycle-common:2.8.7
androidx.lifecycle:lifecycle-runtime:2.8.7
And you might be building with the wrong Java version for de-sugaring:
No static method metafactory
What you're basically trying to do is AAR to JAR conversion:
Adding AAR with flatDirs repository is not working anymore