How to list all Android dependencies from an Expo project? - java

As most people familiar with Expo are aware, development has been a breeze thanks to its many layers of abstraction.
However, I've hit a wall and need to break out of my Expo bubble. I don't mean ejecting or re-writing the entire app. What I mean is to start gaining awereness of what's going on under the hood. This question specifically refers to dependency management & bundling.
I'm no expert on Android development, but I do have some basics. As far as I understand, dependencies are managed in a Java-like fashion. With concepts like the Java package, and tools like Gradle.
Expo manages dependencies using a NodeJS fashion. With concepts like the package.json and tools like npm/yarn.
When the time comes to build the android binary, Expo does something with the Javascript code & bundles it along several Andriod dependencies required for the project to run.
Therefore, what I need to get is a full list of all the Android native dependencies the
resulting binary will include. i.e: com.company.example:identifier:x.y.z
I've used JADX to de-compile a resulting .aab from Expo and while the result is quite insightful, it's missing a reliable manifest listing all the bundled packages. Said manifest might not even exist, as all the bundled packages will probably be included along the rest of the source code, so there's no need to list them separetly. A manifest like that would make most sense before building. It does have an Android Manifest, but that one doesn't list dependencies.
What I did though, is to cd into the de-compiled project and run the command:
grep -rh . -e '^package.\+;' | sort -u > packages.log
The output looks promising, but I'm no expert and I need to be 100% sure before telling my boss. Decompiling isn't always 100% reliable due to some code being impossible to decode.
I've also tried expo prebuild but the resulting gradle files will not list all dependencies directly. Instead they require dependencies defined in a package.json using a weird directive like so:
url(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../android"))
Not sure how to manually execute that directive, or how that gets eventually translated to native android dependencies (i.e com.facebook.react.uimanager).
Please, I need help listing all the Android dependencies for an Expo project and being 100% sure about it.

Related

Get javac to use androidx

I am now coding Android apps without using Android Studio, and when I compile, I encountered the errors:
./src/com/example/projectname/GamePanel.java:8: error: cannot find symbol
import androidx.annotation.NonNull;
where the "^" points at the period before "NonNull", and
error: package androidx.appcompat.app does not exist
And my compile command is:
javac -d obj -sourcepath src -classpath ../android/platforms/android-32/android.jar ./src/com/example/projectname/*.java
The internet tells me that I should set android.useAndroidX to true, but I am not using Android Studio. Is there any way to let javac know that I am using AndroidX?
OK, so the problem is that the NonNull annotation is not defined in that JAR file. (Or at least, not in the android.jar that I found ... on Github.)
I managed to find a JAR containing androidx.annotation.NonNull in the Maven Central Repository: https://mvnrepository.com/artifact/androidx.annotation/annotation/1.3.0
But I suspect that you are going to find more of these issues as your project gets more complicated.
Is there any way to let javac know that I am using AndroidX?
No there isn't. The javac compiler understands nothing about Android let alone AndroidX. It only knows about what you added to the compile-time classpath. So if you are going to persist with compiling using javac directly, you are going to have to figure out how to find the JARs that you need for yourself1.
My recommendation would be:
Just use Android Studio. It really isn't that slow ... when you take into account all of the features it provides to make coding, testing, debugging, etc.
You can also use the Gradle build tool2 independently of Android Studio. It has a plugin designed especially for building Android apps; see https://developer.android.com/studio/build. Among other things, it will automate the downloading of the dependencies and the configuration of the classpath.
1 - And down the track you will need to manually update the JARs that you manually downloaded, etc.
2 - There are alternatives such as Maven, Ant and so on, but AFAIK Gradle has the best integration for Android.
Is there any way to let javac know that I am using AndroidX?
Yes, you can download the JAR files for the libraries you are using and add them to the classpath.
However, this leads down a path of suffering and sadness because you will have to download many different JAR files that are implement different parts the androidx package, depending on what features you need.
I strongly suggest you to use Android Studio. It is an incredible tool that makes Android development easier than it otherwise would be.
If your goal here is to compile your app from the command line, then you need to learn about gradle. This is a tool that will download the dependencies for you then run javac with the correct classpath set. Basically it automates all the steps you would need to take to do this manually.

How to use Jpackage to make a distribution format for JavaFX applications

since .jar is not anymore the best format to use to distribute our JavaFX project, I'm willing to use the tool JPackage for that instead, but after reading this post : https://stackoverflow.com/a/68823040/4262407, I ended up having multiple questions, but first of all, I just wanna make sure I ve well understood the process that I should follow :
the process :
1-create a modular project
2-package the project in a .jar format
3-use the tool Jlink to create a customized run-time image (to reduce the size of the output)
4-use the tool jpackage (it takes 2 and 3 as inputs)
I'm also wondering if I can rely on Intellij artifacts to create the .jar file (the 2 step) is it better to use a specific plugin ?
The last thing that is not clear is do we need to include the dependencies in the .jar file ? since I believe they will be included in the customized run time, won't they?
If you take a look here, there is an explanation on how to create JavaFX projects starting from a template that includes Maven plugins to easily pack the application using jlink.
Doing it like this will allow you to completely rely on IntelliJ, making things much easier.
Once you have your runtime image, you can pack it with jpackage. There was already a discussion about this topic here.
And here is a fast link to the article mentioned there. The article there shows it using Gradle, but you can do the same with Maven, just use the appropriate plugin (jpackage-maven-plugin, as stated in another answer here).
Also, from what I can read in your comments, it seems that you have both modular and non-modular dependencies. In that case, you can use jdeps to achieve what you need. There is a nice article here about having mixed dependencies, that specifically uses JavaFX as an example of modular library within a non-modular application.
Just have look here https://github.com/dlemmermann/JPackageScriptFX for a tutorial with a working example. Its especially useful for non-modular projects.
I used the jpackage maven plug-in to build the native executable(https://search.maven.org/artifact/org.panteleyev/jpackage-maven-plugin).
You will first have to use maven-javafx-plugin to create a jlink runtime image(https://github.com/openjfx/javafx-maven-plugin).
You will then use that runtime image within jpackage plugin(... ).should create an executable successfully then.
The jpackage tool does not require a modular project. Though if your project is not modular then your project will be mixed due to JavaFX being modular. In that case, you'll add the JavaFX modules to the custom run-time image while telling jpackage to treat your code as non-modular (i.e. it will configure the executable to place your code on the class-path).
You can also combine steps 3 and 4 into a single step. The jpackage tool can generate the custom run-time image. It will use jlink "behind the scenes".
As for what format your code needs to be in, packaging it in a JAR file will be, in my opinion, the most straightforward. But I'm not sure that's strictly required.
Any dependencies of your application will of course need to be included with the final application. If those dependencies are modular then you can have them included via the custom run-time image. But if you want them on the class-path then you can include them the same way as your code (i.e. --input).
Note the jpackage tool has a user guide: https://docs.oracle.com/en/java/javase/16/jpackage/packaging-overview.html

JDK11/JavaFX: How do I make a fat jar without build/depdency management?

I think it goes without saying that I should be able to use Oracle's own JDK with JavaFX (from gluonhq) to build a distributable jar file that users can just USE.
After an exhaustive search, much reading (24 hours or more over the last few months)and finally this Google search query:
how to make a fat jar -maven -gradle -scala -eclipse -ant -docker -hadoop -netbeans -jerkar -phy -mozni -yogurt -pizza - throwing -python -bacon
I'm absolutely at the end of the road. Why on earth is this so much work? How can I build a JavaFX application and give it to people that want to actually use it without knowing anything else except how to use the application itself?
This has been answered a few times already for Maven and Gradle. Build tools make things way easier than doing it on command line, and not only because of the dependency management.
Since you ask specifically about command line, there is already a full set of instructions documented for it here: https://openjfx.io/openjfx-docs/#modular.
Non modular App
The section Non-Modular from CLI covers JavaFX non-modular projects from command line, and gives you the whole set of instructions to create an old classic fat jar, where all the dependencies, including the JavaFX ones, are bundled all together.
There is a note that warns you not to use this procedure:
Warning: This is a discouraged tedious error-prone manual process that should be avoided by using the Maven's shade plugin or the Gradle's jar task, in case jlink is not applicable.
After you get the fat jar (it can be cross-platform), you can distribute it, and your user will need to have Java installed and run:
java -jar myFat.jar
Modular App
The section Modular from CLI covers JavaFX modular projects from command line, and refers to the use of the jlink command, in terms of distribution, as it creates a custom image that you can send to your users. It is not a fat jar, but it will allow you sending a zip to your user that needs only to be unzipped and run like:
hellofx/bin/java -m hellofx/hellofx.HelloFX
In this case your user won't even need to have Java installed.
And with a little bit of extra work you can also create a batch, so you can run:
hellofx
However, if you still want to do a fat jar with a modular app, you can still apply the exact same instructions from the non-modular apps. In this case, you will probably have to remove the module-info.java file, as it doesn't really makes sense at this point.
Other options
You still have a few more options to distribute your application.
Custom Java+JavaFX image
Another option, covered in the same document, section Custom JDK+JavaFX image, explains how to create your own "JDK" that includes JavaFX. Then you will produce your jar as usual in Java 8 and you will be able to run it with:
/path/to/custom/java -jar myFat.jar
Note that there are already some JDK distributions that bundle JavaFX, like this one.
jpackage
jpackage tool is not there yet, but there is an early access: http://jdk.java.net/jpackage/, that is using Java 13-internal. The exiting documentation explains what are the command line options you need to produce a custom image or an installer.
Note that you can still use JavaFX 11 or 12 with this.
Build tools
And finally, you can still decide to use build tools (Maven or Gradle), that will really help you in many ways. See any of the linked questions above.

Android app dependencies ClassNotFoundException

I'm new in Android development. Not very new in ordinary EE Java and Gradle.
So I am trying to build a REST consumer app for Android. I have a (1) .jar file I will need (contains DTOs and api consumers). That (1) .jar has dependencies on other (2) jars from Nexus repo. These (2) do depend on other (3) jars (e.g. apache commons lang3, etc.) from maven repos.
The funny thing is that... The app compiles and install just fine. But on runtime it occasionaly tends to lose some classes from (1) (at least (1) -- dunno about (2) and (3) yet).
I know SO does not like pics in questions, but in this case I believe pics = clarity.
See below. Same runtime, same jar. Except one of the classes is not loaded, and another one, sitting right next to it, is available.
Why is that so? What did I do wrong?
One more thing... If I attempt to instantiate one of the missing classes (there's more than one) in main activity (inside onCreate()), sometimes that class appears in the classpath and creates an object just fine. But as ridiculous as it may sound some other class goes missing! It feels like Classloader has limited number of slots for classes it could possibly handle.
EDIT:
Okay, it gets better. It appears that for some reason gradle decided not to include some files from (1).jar into generated .apk...
Any ideas why?
Gradle 4.1. Linux Mint 18. Android Studio 3.0 Canary 8
Left - decompiled APK structure; right - original jar
Probably, you have ProGuard activated. ProGuard removes from the final .apk the unused classes. ProGuard

Local Java package management system in Python PIP style?

I want to program in Java or other JVM languages like Scala, Kotlin, or Groovy. When I am programming on my projects, I only want to have import statements in my Java/Scala/Kotlin source files without the need to state the packages a second time in a Gradle/Maven build script. Instead I want to work as I would do in Python, i.e. have my import statements at the beginning of my source files and I am done.
The packages should then automatically included when I am compiling if all packages are installed in a central local package management system or otherwise get an error message telling me that I have to install a missing package. It should essentially work the same as for Python and PIP respectively.
Is a workflow like this possible preferably with Groovy or Maven?
Thanks in advance!
The closest I can think is Grape:
Grape is a JAR dependency manager embedded into Groovy. Grape lets you quickly add maven repository dependencies to your classpath, making scripting even easier. The simplest use is as simple as adding an annotation to your script:
#Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')
import org.springframework.jdbc.core.JdbcTemplate
Like in this example:
#Grab('net.sourceforge.nekohtml:nekohtml:1.9.16')
def parser = new org.cyberneko.html.parsers.SAXParser()
def page = new XmlParser(parser).parse('https://news.google.com/nwshp?hl=zh-TW&tab=wn')
page.depthFirst().DIV.grep{ it.'#class'=='title' }.each {
println it.A.SPAN.text()
}
I can't judge the Groovy landscape since I don't have any experience there, but for developing Java or Scala applications this exact workflow is not possible as far as I know.
Regarding "I only want to have import statements..." I think the closest you can get is good Maven/Gradle/sbt integration in an IDE, like IntelliJ that automatically adds the desired library to your build system's configuration file when using the correct shortcut. It (at least) works for some Java libraries when you're dealing with a Maven project in IntelliJ.
And regarding your other wish to have packages automatically included when compiling: On the JVM there is the concept of the fat JAR (also called uber JAR), which is basically a JAR (Java archive) that contains all dependencies and is thus self-contained. Usually you can start the application contained in it with a single java command.
To build fat JARs you need to have the approriate plugin for your build system:
For Maven that would be the maven shade plugin, see https://maven.apache.org/plugins/maven-shade-plugin/
For sbt you can use the assembly plugin, see https://github.com/sbt/sbt-assembly
Gradle probably has something similar
A lot of Java frameworks also come with their own build plugins that make building such self-contained applications relatively simple (Spring Boot is one example, but only suitable for applications that on top of an HTTP server)
Hope this helps, althought it's not an accurate answer to your question. :)

Categories

Resources