I want to know do unused packages cause APK size to grow?
Consider I install dozens of NPM packages for my project but I never import and use them. These files obviously increase my project folder size but do they affect APK size when building APK?
The question can be answered about .ipa too.
APK Analyzer will not look for any unused dependent NPM packages because all your javascript code is bundled by metro before being included in your Android project as an index.android.bundle asset:
Metro is a JavaScript bundler. It takes in an entry file and various options, and gives you back a single JavaScript file that includes all your code and its dependencies.
So any unused dependencies must be pruned before creating the apk. Read about Tree shaking, which does exactly that:
Tree shaking is a process in which the bundler includes only the code that is actually used.
Note that only modules that have a dependency from your code will be included in the bundle.
Related
For a project, I am using Android gradle scripts with CMake, gradle plugin is version 3:0:0, CMake version 3.6. Both gradle and CMake files are pretty simple and uninteresting (just defining the files used - I can still copy-paste them as required).
I have the following project structure; basically a codebase producing a few tens of .so files (the native part for the Android packages that get packaged into an apk, thereby called 'Executables'), which all depend on the same shared library code (static libraries, thereby called 'Libraries'). The Library code is still (relatively) volatile, so I wish the Executables to have project-level dependencies on them, so that whenever the Executables are built, the Libraries are rebuilt on-demand every time their code is changed.
The structure looks like:
+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)(points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt
The Libraries' CMakeLists redirect their output into the Bin folder using
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY {CMAKE_CURRENT_SOURCE_DIR}/../Bin/${ANDROID_ABI}/${LibraryName})
The executable's projects add dependencies on the libraries "as normal"
add_subdirectory(${PROJECTS_ROOT}/LibProjects/${LibraryName} ${PROJECTS_ROOT}/Framework/Bin/Android/${ANDROID_ABI}/${LibraryName})...
Everything almost works, in the sense that I can get sensible executables and the Executables trigger builds of the libraries.
The problem is that when building the executables sequentially, each one does NOT reuse the library project outputs of the other ones: When I build Executable1, it will build all libraries (normal) and then it will build itself. Afterwards, when I build Executable2, it will NOT reuse the libraries that were already built for Executable1, and so on - this effectively increases my build time by a factor of ~10.
I can find the output of the build of each library inside the /Bin folder as expected, but they are not reused across executables - there are no CMake "project files" (is this the correct term) in the bin folder, all of them get generated inside the executable build directory.
The problem I am trying to resolve is the build times stemming from the fact that each library gets rebuilt for each executable.
At the moment the solutions I am considering is to somehow instruct CMake to use the Bin folder (or another folder) as a working folder for each library in its own folder instead of with the executable, hoping that the gradle android plugin will be smart enough to then spot that neither the cmakefiles nor the object files need to be regenerated, and avoid the rebuild.
The restriction that I have is that I cannot restructure the codebase itself, and that each Executable must be buildable separately of the others - there is absolutely no possibility of a top-level CMake - each Executable should be able to be triggered on its own.
CMake can guess if the build is up-to-date by reading informations froms the current build directory.
When you run CMake manualy in Executables/<x> directory, cmake retrieve information from the build directory associated to Executable/<x> directory. It then check if the timestamp of the built file correspond to the last build performed in this build directory. If not, it rebuild. What happen is that: Lib1 library file is built after you build Executable1, then you run cmake in Executalbe2, it compares the timestamp of Lib1 target file, see that this file was not produced by this instance of the cmake build and then rebuild the lib. And so on.
So you have two options:
1- Either you build the library and install their target files in the bindirectory (using install cmake command and make install bash command for exemple). Then in the Executalbe<x>/CMakeLists you use find_library command instead of add_subdirectory.
2- Or you create a super project which has the following structure:
+ supper_project
---CMakeLists.txt #add_subdirectory(LibProjects/lib<x>)... add_subdirectory(Executables/Executalbe<x>)...
+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)
(not any more:points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt
I managed to work around this problem - but in the end it was by working around rather than with CMake.
I removed the CMakeFile-level dependencies (add_subdirectory) and only left the libraries at the linking level (target_link_libraries Executable [the library files])
Afterwards, I created gradle scripts for each library and added dependencies to these scripts in each application gradle script, so that the building of the libraries gets triggered by gradle dependencies instead of CMake dependencies. It's slower than it would be if gradle could be avoided, but much faster than rebuilding every time, and the overhead is at least constant (a few seconds per project).
I think problem lies in the way you have defined your dependencies.
For each executable you are creating separate targets using add_subdirectory.
e.g. for executable 1 you have add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}) and for executable 2 also you have add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}), so cmake will create two separate targets for same library1 in each of the executable's subdirectory and thus it will create separate timestamp and cache files. That is why it looks that it is building the same library for multiple times, but in fact for cmake they are different targets.
To fix this you can include all libraries in top level CMakeLists.txt using add_subdirectory and them in each executable's CMakeLists.txt add the dependency using add_dependencies command.
I've synced the entire Android repo, and set up a build environment per the instructions here:
https://source.android.com/source/building
The build instructions seem to be assuming that you want to build the entire Android platform. I'm really interested in building a specific AOSP app, like contacts, SMS, camera, etc. I've seen mirrors of the stock app's code on GitHub, but there doesn't seem to be any build instructions within those, for example:
https://github.com/android/platform_packages_apps_contacts
https://github.com/android/platform_packages_apps_calendar
Is there a build guide for doing this? Am I stuck downloading, modifying, building this huge (100+GB) code set?
Just as you have 'mm' to build a certain target, you can also use 'mma' to build that target with its dependencies. For example:
$ mma Settings -j16
This will scan the project for the dependencies of the Settings app, and will afterward build the dependencies first before commencing the build of the Settings app.
here are compile and module-based compilation commands:
lunch: lunch <product_name>-<build_variant>
tapas: tapas [<App1> <App2> ...] [arm|x86|mips|armv5] [eng|userdebug|user]
croot: Changes directory to the top of the tree.
m: Makes from the top of the tree.
mm: Builds all of the modules in the current directory, but not their dependencies.
mmm: Builds all of the modules in the supplied directories, but not their dependencies.
To limit the modules being built use the syntax: mmm dir/:target1,target2
mma: Builds all of the modules in the current directory, and their dependencies.
mmma: Builds all of the modules in the supplied directories, and their dependencies.
cgrep: Greps on all local C/C++ files.
jgrep: Greps on all local Java files.
resgrep: Greps on all local res/*.xml files.
godir: Go to the directory containing a file.
you can look here for other and more build commands : https://source.android.com/setup/build/building
and here :https://elinux.org/Android_Build_System
And check "build/envsetup.sh" file's comments to see full list.
I am trying to build a branded Android app, that will have different resource files (mainly drawables) for different customers. The Java code in the apps will be the same, but the different apps will have a different look--meaning different color schemes and different logos etc. I have been told, and my research suggests that Ant is the best way to achieve this.
Where should I change the Android 'build.xml' file? What sort of Ant task should I use to achieve this?
For debugging, I would like to just use Eclipse and build with the default resources. But for production releases, I would like to run Ant on build.xml to produce multiple APKs from different /res folders. I do not even need any code snippets (although that would be nice), just even some tips from people that have done this before or something similar.
I ended up writing a Python script to reorganize the Android project before each build. I recommend avoiding the use of Ant for stuff like this. My 100-200 lines of Python achieved the equivalent of about 1000+ extra lines of Ant that was required in addition to the default Android build.xml Ant script.
I have encountered a similar issue where I want to compile the same code base with some changes as well as changes in the resource files. The solution I am pursuing at the moment is creating a library with the shared code/resources and separate "regular" projects for each of the different APK releases. Unfortunately, I don't have a functional final solution to the problem yet, so all I can give is these vague hints.
Requirement Setup
1. Go to the URL :
http://ant.apache.org/bindownload.cgi
and download the apache ant and extract it in to the any folder like d:/ant .
2. I think you already having the Android SDK path is like(D:/Android SDK/)
Now go to the Enviroment variables and check whether path variable is there is there add these in path otherwise create a new varible with name path and put it there in vaue
D:/ant/bin;D:/Android SDK/tools
done
Go to command prompt and navigate it to the root directory of your project and run the command
android update project -p /
Note: / if you are in the root directory of project else you need to give the path of root directory like d:/myworkspace/mysampleproject
this will generate and build.xml file in your project.
now run the command for this it is necessary to be in root directory of your project
ant debug
this will generate an apk file in bin folder signed with default debug key.
I am trying to build my android project using ant in command line mode.
It works with eclipse and it used to work with ant until i installed the latest android sdk.
I run ant release -buildfile projectdir\build.xml. The compilation process is ok, and after aligning the apk, it fails at runtime with ClassDefNotFoundError acra.ACRA.
I have tried to remove any reference to acra from the project, but it will fail at runtime when trying to execute any code coming from a library jar.
My jars are in the libs folder at the root of the project. And I sort of understood this would cause ant to link them into the apk. But it doesn't.
When I used a previous version of the android sdk, I had a file named build.properties with an attribute referencing the jars folder external.libs.dir=libs. But now I can't make this to work any more, even if I use the new attributes names jar.libs.dir=libs and the new attributes file name ant.properties.
I read that ClassDefNotFoundError is caused because at compile time the librairies are found, but they are not linked into the apk, so they can't be found at runtime.
How can I link the external jars in the apk please ?
The compilation process is ok, and after aligning the apk, it fails at runtime with ClassDefNotFoundError acra.ACRA
There is no acra.ACRA class in ACRA, at least not in the current edition. It's org.acra.ACRA.
My jars are in the libs folder at the root of the project. And I sort of understood this would cause ant to link them into the apk. But it doesn't.
Yes, it does. Then ProGuard is removing them, unless you teach ProGuard not to.
I've never made a program into an executable before, and I've been looking into how to do this for some time now. When I try to put it into a jar everything works fine but when I try to run it nothing happens.
How do I make my game into an executable so it can be run (on windows, not android)
I feel like I am not Linking it to the libraries or something... Not sure.
Thanks!
Edit:
I should add I get the error
JAR export finished with warnings. See details for additional information.
duplicate entry: com/badlogic/gdx/utils/arial-15.fnt
duplicate entry: com/badlogic/gdx/utils/arial-15.fnt
duplicate entry: com/badlogic/gdx/utils/arial-15.png
duplicate entry: com/badlogic/gdx/utils/arial-15.png
Jar export finished with problems.
See details for additional information.
Your problem is that when you use eclipse export as Executable jar file it does not include the assets (graphical, sounds ...) that you used in your gdx project. What you can do manually is either copy your assets folder right next to the generated jar file or include your assets folder in your jar file with your favorite zip management tool.
Another way would be to use this same eclipse export wizard and check "Save as ANT script" and then edit the generated ant file to include all the files and folders needed by your app.
Hope this helps
This is an old question, but if you are using a new version of LibGDX and Gradle you can use the command line to make an executable.
There are several commands, but these are for packaging:
Desktop
gradlew desktop:dist
Android (unsigned)
gradlew android:assembleRelease
iOS
gradlew ios:createIPA
Web
gradlew html:dist
Read more at https://github.com/libgdx/libgdx/wiki/Gradle-on-the-Commandline
I'm assuming your application is setup as the libgdx wiki page suggests (with a "main project" and separate "desktop" and "android" projects that share the sources from the "main" project).
Since your app is written in Java, it requires a JVM to run on a desktop. You have to decide if you want to package that up, or rely on a JVM already being installed by the user. I believe packaging up the JVM with Java class files is very complicated and raises a host of other issues (and it becomes very platform specific). So, I believe most libgdx-based games get distributed as an executable Jar file, which means the user must already have Java. (It works for Minecraft, so its probably good enough for you, too. :)
Eclipse makes that really easy: File -> Export ... -> Java -> Executable Jar File. There may be additional steps required to include assets like your app's images and sounds into this .jar file. (My game is currently "asset free", so I don't have any experience with this part.)
You might also consider side-stepping the desktop executable, and packaging your game as an applet and running it in a web browser so there is very little "installation" required by the folks you want to show it to. Here's a walkthrough for making an applet from a libgdx-based game. (I haven't actually tried this myself yet, but I do have a libgdx-based game that I'm planning on doing this for.)
If you're using Android Studio, you can create a custom configuration to distribute from within the program.
On the Run dropdown list select edit configurations.
Click the "+". Select Gradle.
On the right half of that screen give your configuration a Name.
Gradle Project: Use the browse button to select your desktop application. This will look something like (project name):desktop
Tasks: type "desktop:dist"
Apply.
Close the configuration editor and select your new configuration from the dropdown. Hit run and it should build your project.
Your new Jar file should be located in (ProjectName)/desktop/build/libs