I have been researching and trying to understand how different mobile technologies compile apps under the hood, this is my findings so far:... I might update it in the future
article tip: in this article, "One aside" sections are helpful text or general knowledge pointers and explanations about concepts used within the article.
These are helpful concept explanations that can help you get more insight and understanding of the article
Most delicate utilities and products we use and consume in our day to day activities need to be prepared,processed, packaged or arranged to meet a specific target before we use or consume them. Food needs to be cooked and served, gym facilities need to be installed, computers need to be assembled together, you get the point!. Some sort of pre-processing or conversion needs to be carried out to ease usage and consumption. This preparation is akin to compilation in software development, where a piece of code needs to be converted to a form consumable by the computer, and by extension the user gets the results.
So what does compilation really mean?.... Simply put it involves the conversion of the source code written in a programming language to the target code which could be the same or a different programming language(usually a different language) for use or further processing. Most times this involves the conversion from a high level language written by you and i (python,java,javascript, dart, etc) to a lower level language (machine code,assembly language,byte code etc) to be used or processed by the computer. There are different types of compilers for different use cases, compilers that : convert from one high level language to another high level language, convert from high level to low level language ,that convert code to run on another machine - cross compilers etc. More to that, compilation usually consists of different steps, which depends on the compiler in use, steps such as preprocessing, lexical analysis, parsing, semantic analysis …. but that's not what this article is about. We will focus on the compilation process of some mobile development technologies: flutter,native android(kotlin) and native ios(swift), but before then let's make a little analogy....
For our analogy lets pick something about food .. a restaurant , well because who doesn’t like food. When you walk into a restaurant , you usually go there with an intention to eat. Now the process of the food preparation by the chef is like the compilation process,and the chef is the compiler, and you, yes you are the computer -> The food(could be raw) needs to be converted to a form you deem edible. The computer understands and executes machine code, so also you eat cooked and prepared meals. The compiler converts code from one language(the source code) to another(target code), to be used(eg. When converted to machine code ) or further processed(when converted to another language eg… assembly code or another higher level language), so also the chef converts raw foods to delicious meals. When meals are prepared some are made right away to be consumed, (eg tea, coffee), while others for further preparation before consumption (eg the processes of baking a cake).
One aside: interpretation and compilation: There are actually two methods of processing source code to a target code. Compilation and interpretation. We have met compilation above, it involves processing the whole code from source to target before it is run or executed by the computer, this is like a situation in a restaurant where the meals are cooked and fully prepared in advance and probably refrigerated, so when you come to eat the meal is served instantly or almost instantly (if the food is refrigerated and need to be heated). Interpretation involves processing and converting source code to target code line by line, and executing it. That is , the whole file is not converted to the target code before the execution starts, rather each line is converted and executed and then the next line follows. This is like a situation where you go to a restaurant and the food is cooked fresh, that is when you place an order the chef starts to prepare the meal step by step. Interpreted code usually takes longer to execute compared to its compiled counterpart. These days there usually is a combination of both, which you will see shortly.
Before we delve into the different mobile frameworks, we need to understand two modes of compilation :
Just in time (JIT) compilation
JIT Compilation(sometimes referred to as dynamic compilation) is a compilation that garners features from compilation and interpretation. It's a form of compilation where the source code is compiled to the target code during execution. This means when the code is run or executed, it starts to run like an interpreted language(line by line), but then parts of the code are compiled to machine code, this combination of some parts of the code being interpreted and others compiled during runtime is what makes JIT compilation a combo of both worlds. The selection of parts of the code to run (interpret) and parts to compile as the code is executed is determined by the compiler, this includes conditions such as when a piece of code is frequently accessed by other parts of the code(example: when a function is frequently called by other parts of the source code) , it is compiled as the code is executed .The compiler uses optimizations such as lazy compilation where parts of the code that is never accessed is not compiled or interpreted. These and many more optimizations are carried out by the compiler. JIT compilation is like a situation where you go to a restaurant and order a meal , and the meal is prepared right then, step by step, but then some optimizations are done based on customer demands, season or weather to improve customer service. Optimizations like making large portions of meals that are high in demand ready to be served and keeping it aside for fast access while making other foods based on orders , like coffee or hot chocolate during early hours of the morning and during cold weather, cold lemonade and ice cream on hot summer days,afternoon and hot weather. Also , making less or none at all of less ordered meals, like hot chocolate on a sweltering summer afternoon. Optimizations like this improve customer service because as meals are prepared on the spot when customers order, high in demand meals can be quickly served as required, thereby generally reducing the waiting time of customers, furthermore time is not wasted preparing food that is not ordered or not in high demand.
Ahead of time(AOT) compilation
AOT compilation (also referred to as static compilation) is a type of compilation where the source code is translated to target code in full before the target code is executed. This means the entire source code ( eg.. high level language: java, kotlin,GO etc) is translated to the target code(eg. Machine code), then the target code is executed afterwards. This compilation method takes an initial amount of time in order to process and convert an entire source code to target code , but runs very fast after compilation, because the entire code is converted to the target code, which usually runs fast (e.g. machine code), compared to JIT compilation . This situation is like going to a restaurant where the chefs prepare every meal ready before customers arrive. It takes an initial amount of time to prepare the meal, but once it is done , serving the customers becomes really fast , compared to making the meal or part of the meal when the customer places an order.
one aside: _it is flawed to say a language is strictly compiled or interpreted. Any programming language is mainly syntax and definition of instructions, to be interpreted or compiled is determined by the implementation and runtime of the language. So koltin is not a compiled language,rather its implementation is, eg kotlinc compiles kotlin to run on JVM, while kotlin can also be used in scripting mode , which is executed line by line like an interpreter, python is typically interpreted using CPython, but can be compiled using projects like pypy, Javascript is interpreted in the browser by engines like v8, but tools like Node.Js and other AOT compiler can compile javascript code, C++......well i think you get the point.
In the context of mobile applications, compilation refers to the conversion of the source code(kotlin,dart,swift) along with all resources (images,storage,layout files etc) needed for the app into a form executable by the device.
Let's start off with native android:
Native android compilation under the hood:
The compilation of the android app consists of several steps and it involves the conversion of the source code, which in this case includes the main code (kotlin,java) ,plugins,libraries and all the resources(images,audio,icons,xmls etc : the res folder and other layout files) required by the app to the target code, in this case an Android package(APK) or Android App Bundle(AAB) file(a form executable by the android system or uploaded to Google play). Android uses Gradle as its build system, and the Android Gradle plugin(AGP) from Gradle is tasked with this conversion process using different tools .
Resource compilation: the AGP uses the Android Asset Packaging Tool(AAPT) to compile the resources of the app, these are non code files usually under the res folder needed by your app to function. The xml resources(layout files,string and value files etc) are converted to a binary format that android can easily read. Media files like images(PNG,JPEG) and audio files are not converted but left as they are, unless some form of optimization like image compression is applied. After the AAPT compiles these resources it packages them in a resources.arsc file for easy access by the app when running . The AAPT generates an R file (R.java for java, R.kt for kotlin) which is the bridge the app uses to access the resources in the resources.arsc.
java/kotlin code compilation: In this step your main source code, java and kotlin files,is converted to .class files, which are bytecodes. This bytecode is executable on the Java Virtual Environment (JVM). The AGP invokes kotlinc or the javac compiler for this. Kotlin files are converted to bytecode using the kotlinc compiler while java codes are converted to bytecode using the javac compiler.
One aside: The Java Virtual Machine (JVM) is a core component of the Java Runtime Environment (JRE). It serves as the engine responsible for running bytecode. The JVM abstracts the underlying machine (operating system), providing a platform-independent environment for executing code written in JVM-based languages, such as Kotlin, Java, Groovy, and others. Code written in these languages is compiled into platform-agnostic .class files containing bytecode. This bytecode can be executed on any JVM, regardless of the underlying operating system (Windows, Linux, macOS, etc.). This platform independence is a key feature of the JVM, enabling consistent code execution across different environments.
- Bytecode compilation: In this step, the bytecode(.class files) is converted to .dex files, which is also bytecode, but executable in android. To achieve this the AGP invokes the D8 compiler which then converts the .class files to .dex files, this is called dexing. This conversion is necessary because even though .class bytecode is executable on the JVM its not executable in Android because android does not use JVM but uses the Dalvik Virtual Machine (DVM) or Android Runtime (ART) which requires Dalvik bytecodes( .dex bytecodes). DVM is used on older devices(android 4 and earlier),while ART is used on newer devices (android 5 and later). Also multidex (creation of multiple dex files) is enabled here if your app exceeds the 65k method limit.
one aside: multidex means generating multiple dex files, this is because of the limitation that came from older android versions(android 4 and earlier), that android apps cannot have more than 65k(65,536 ) methods in a dex file,this is because a .dex file uses 16-bit index(2^16=65,536) for methods, meaning the maximum number of methods it can hold is 65536, this count includes methods from the android SDK, third-party libraries and your code. So, if your app exceeds the 65k limit, the android build system automatically enables multidex, the D8 compiler creates multiple .dex files to cater for the overflow. This functionality is built-in in newer android versions (android 5 and later), while older versions (android 4 and earlier) require additional configuration for this.
Optimization with R8: This is an optional step, but if enabled the R8 compiler makes optimizations to the .class bytecode during processing before the .dex bytecode is produced. It performs shrinking: removes unused codes and resources, obfuscation: by renaming methods, classes and variables to make the code harder to reverse engineer, and other optimizations for better performance, and then converts the .class bytecode to .dex bytecode.
Resource Packaging: This is the step where the APK or AAB file is produced. The AGP invokes the AAPT to package the compiled resources(resources.arsc), raw files(images ,audio etc),configuration files(e.g. app manifest files) and the .dex bytecode to form the APK or AAB file. (one Aside: APK files are the standard format for distributing android applications, and can be directly installed on the android device, while AAB( which usually contains split APKs each tailored to a specific architecture of android device,eg CPU,screen etc), is an optimized format which was introduced by Google , with this the Google play Store can create optimized APKs depending on the android device.)
APK signing: This step involves signing of an app by the developer to ensure the authenticity and integrity of the app and the jarsigner(or apksigner which is an older tool replaced by jarsigner) tool is used for this. As a requirement by android, the app needs to be signed using a digital signature, some reasons for this are: security- to make sure no one has tampered with the APK since its signed, identity verification - it identifies the developer of the app, and ensures that any future update for the app actually comes from the same developer . During development and testing of the app, in the development environment(android studio) ,the debug keystore(an automatically generated keystore) is used to sign the apks, while for release and production(ready to distribute the app, directly or using playstore), the release keystore is used to sign the APK, which is private and accessible only to the developer of the application. The app is now distributable on the playstore or installed directly on an android device
one aside: A keystore is a file containing one or more private keys(each key belongs to a developer or an organization), used for signing APKs.The keys in The keystore consist of key pairs: private - used to sign the APK and public key - part of the key distributed along with the APK. Access to the keystore and keypairs is protected by passwords set by the developer., and it can be generated using java keytool which comes with the java development kit
overview of contents in a .apk file
Native ios compilation under the hood
Like the android build process, the compilation of ios apps also involves several compilation steps to convert the source code(main source code:swift and objective-c, storyboards, xibs, resources: images, audio, etc) to the target code that runs on ios platforms(.ipa files).
- Source code compilation: Ios apps are written majorly in two languages, swift and objective-c. Different compilers are required for each of these languages.To compile swift, the swift compiler(SwiftC) is used, and to compile objective-c the clang compiler is used. Both swift and objective c are compiled to a format known as intermediate Representation(IR) , which is a platform independent representation(which means regardless of the hardware or cpu e.g. regardless if it is ios or MacOs, ARM or Intel, it's still the same format) or format of the source code. The IR is then optimized by the LLVM for better performance: e.g. eliminating dead code(code that is unreachable,and not used, e.g. functions that are not called), inlining functions(placing frequently called or small functions directly into code that call them), etc, and produces object files(.o files) which is specific to the target CPU architecture (eg. ARM64 for most ios devices). Each source code file(Swift or objective-c) is compiled to a different object file (.o file). This allows faster development , because when a change is made to a particular file, only that file is to be recompiled.
one aside: Before objective-c is compiled, usually the preprocessor processes certain directives(they start with #) in the code producing the preprocessed code which is fed to the compiler. Pre Processing includes actions like: resolving #import by including code dependencies while avoiding duplications, #define macros, by replacing every definition of constants with the actual values etc.
one aside: LLVM is a project that is an umbrella housing different tools used for building compilers for languages. LLVM originally stood for low level virtual machine, but now it's known as LLVM not as an acronym but as its name because the project has grown to become a compiler infrastructure, which provides various tools for developers to build compilers. Usually building compilers for languages involves a front end : for processing the language syntax , middle end :to optimize the code and a backend: to convert the code to machine code. LLVM provides tools to make these steps easier for developers. A very important concept in LLVM is the Intermediate Representation(IR), this is a language independent format of representing any code from any language which is the language LLVM understands and uses .So anyone who wants to build a compiler for a particular language or build a new language does not need to go through a lot of heavy work, but could instead create the frontend for the compiler to convert the source code written in the language of choice to IR, which then allows the developer to benefit all the features of LLVM. The first step:front end, is usually made by the developer by leveraging existing tools or building from scratch, in order to convert from source code to IR. Some front ends also exist as part of the tools that LLVM provides, like clang for C++,C and obj-c. Next, in the middle end step the LLVM applies optimizations to the IR, and then lastly in the backend step, it converts the IR to the target platform machine code.
Linking: This step involves the combination of all the object files required by an app (.o files from main source code by the developer, from ios standard libraries and from external libraries) to run into a single executable, connecting them appropriately as they are referenced. This is done by the Linker. Linking could either be static or dynamic. In static linking the object files are combined directly with the rest of the app while compiling, making it a part of the executable and making the app independent of any libraries at runtime, while dynamic linking involves linking object files at runtime, that is when they are loaded in memory and are called while the app is running.
Asset compilation: In this step all non code resources are processed and converted to be efficiently accessed within the app. Interface Builders(storyboards and XIBs) are compiled to binary formats(.nibs for XIBs and .storyboardc for storyboards) for better and faster access. Images,icons, and other visual assets which are organized and managed in Asset catalogs(.xcassets files which is a centralized way to manage and organize access to images for different screen densities , sizes etc) are compiled in to Assets.car, which is a binary containing the processed assets. Xcode activates ibtool compiler for interface builders and actool for images and other media files. Localized resources(resources that allows the app support multiple languages and locales, eg es.lproj for spanish, fr.lproj for french etc)are processed and bundled in language specific folders within the app’s resources structure, to enable the app load the appropriate asset for region or language specific assets based on the settings of the user. Other metadata files (Plist files,e.g. Info.plist, config files like JSON files) are optimized and included in the app bundle. All these assets are compiled and organized into the app bundle alongside the executable , and the bundle structure makes it possible for the app to access them efficiently and quickly on the device.
one aside: compile time refers to the period a code is converted to machine code or an executable, while runtime is the period when the compiled code(machine code or executable ) is started or is running
Bundling: In this step xcode bundles the linked object files executable, configuration files(plist ,json ,etc required by the app),compiled visual assets and interface builders, and all other resources required by the app into a .app executable. This is the main executable that is run by ios apps.
Archiving: This step produces an intermediate .xcarchive format before the app is packaged for distribution. Xcode is used to archive the app. The .app bundle, along with additional resources like debug symbols (used for crash reporting) and Xcode-specific metadata (e.g., build settings and provisioning profile details), are packaged into the .xcarchive. This archive format is not directly distributable but is used to prepare the app for further processing.
Code signing: This is an essential security measure required from apps intended to run on ios devices or be distributed via the app store. It verifies that the app was built by an authorized developer and also verifies the app's integrity, that is making sure that the app has not been tampered with since it was signed. This process consists of two parts: provisioning profile and code signing identity. Provisioning profile is a file that links the app to the developer's apple developer account. It contains:App id, the id of the app, device id(s): the devices that can run this app, and entitlement file: this includes the permissions necessary for the app to run, e.g. allowing push notifications. The provisioning profile depends on the development stage of the application: while the app is under development the development profile is used , this allows the app run on registered devices connected to the developers account, Ad hoc profile is used for testing outside of the App store(limited number of devices) and finally App store Distribution profile, for distribution on the App store. Furthermore, a code signing identity is a digital certificate that Apple issues to a developer or organization that uniquely identifies them. The certificate contains information about the developer and also holds a public key for verification, and is stored in the developers keychain, along with the private key generated by the developer. Apps meant for the App store use App store distribution certificates, while Ad hoc or Development certificates are used for testing and development purposes. The code signing process involves signing the whole app bundle, the certificate and the private key is used to sign the app, this in turn generates a digital signature, which is embedded in the app bundle ,and is used for verification whenever the app is launched on the ios device ( the ios system verifies that the app has not been tampered with after it was signed and also confirms the identity of the developer using Apples certificate chain.) . Code signing includes: development code signing that allows apps to be installed on registered devices by signing using development certificate, App store code signing for distribution on the App store by signing using distribution certificate, and enterprise code signing for internal distribution within an organization, by signing using enterprise certificates.
one aside: the keychain is a secure storage in Macos that stores private and sensitive information like passwords,certificates and private keys, used for tasks like signing and authentication. Also,signing can occur at different stages for ios development , during development or creating of app bundle(mostly development signing),or after archiving (mostly for distribution), the .ipa can also be signed too for distribution
- Packaging/Exporting: The .xcarchive is exported and packaged into a .ipa file, the format required for app distribution. During this process: The .app bundle is extracted from the .xcarchive, then the app is signed with a distribution certificate and provisioning profile if not already signed, then the .app is placed inside a Payload directory, compressed, and exported as an .ipa file. The .ipa is the final output, ready for uploading to the App Store or distributing through other means.
one aside: .ipa is basically a zip file for ios, you can rename its extension from .ipa to .zip to view its contents
- Deployment: This involves the deployment of the app for testing locally to a mobile device through xcode, or to testflight , for pre release testing, or deployment to the App store for distribution to the public.
There are optimizations that can be applied to ios apps to make them more efficient and to reduce the storage demands on devices. some include:
Bitcode(optional): when building apps in Xcode there is an option for Bitcode. If this option is enabled the compilation does not complete to machine code, rather to an intermediate format that is platform-agnostic, known as Bitcode, this format is recompiled by Apple to machine code depending on the Architecture of the device that wants to install the app
Slicing(optional): This involves creating versions of apps specific to a device and architecture. This involves creating device specific variants , for different screen sizes and models, eg. an Iphone 12 will only receive iphone12 assets, and nothing belonging to other models. Code is also cut down to only that needed by a specific architecture, e.g. ARM64, and if an app contains multiple versions of an image(eg 1x 2x 3x), only the one for that device is downloaded. Generally this reduces download size and eliminates redundancy, and users get the most optimized version of an app for their device.
On Demand-Resources(ODR): This feature allows developers to specify some resources as on-demand , which means these resources are not part of the initial app bundle rather they are downloaded when they are needed. These resources are not major necessities for the app and are hosted on the Apple servers, and when the user needs them(eg. When a user reaches a certain level in a game), they are downloaded to the user's device. This frees up user’s storage to only the necessary things needed.
The sequence of images that follow, shows an overview of the contents of a .ipa bundle.
payload: helloworld.ipa/payload/
overview of files in a .ipa file
.app: helloworld.ipa/payload/helloworld.app/
Flutter compilation process:
Unlike the previous two compilation processes, flutter is cross platform, since it compiles for both android and ios. At the end of the compilation, a .apk or .aab file (like android native compilation) and a .ipa file (like ios native compilation) is produced. The compilation of flutter apps include the flutter build tools and SDK, as well as the platform specific build tools (Xcode and gradle) depending on which platform the app is built for. The steps involved includes:
One aside: the name "flutter" refers to the flutter framework and is also used for the flutter SDK as well. This means flutter is used to refer to the code (framework) used to build the application, as well as the build tools used to compile and run the application
-
Source code compilation: First of, flutter determines the target platform(android or ios, as well as the cpu architecture) and compiles the written dart code and the flutter engine code(written in c++) to machine code of the target platform. This can go two ways depending if its a debug app (app built while writing and testing the code) or release and profile build app (app to publish to the public for use, or to completely test the behavior of the app on real device, in case of profiling)
- Release/profile build: The release compilation is an Ahead Of Time compilation (AOT). The Dart AOT compiler compiles the dart code to machine code of the required platform(android or ios) and cpu architecture(ARM,ARM64, etc). This produces machine code that is directly runnable on the device. On android this compiled native code is packaged as a shared object or library and included in the apk (libapp.so in android), while in ios it is included directly in the .app executable (App.Framework in the Runner.app executable). The flutter engine code (written in C++) is also compiled to native code, but this is done by the target platforms native compiler, (LLVM for ios , and android NDK for android), and also packaged as a shared library to be run on android(libflutter.so in android), while being included directly in the executable binary in ios (flutter.Framework in the Runner.app). Additional native libraries and plugins are also compiled to machine code, (e.g. databases like isar to produce libisar.so, while they produce static libraries or frameworks : .a or .framework on ios ).
one aside: shared objects these are dynamic libraries used on linux based systems, and android is a linux based system. They contain compiled code or machine code, that is, multiple machine codes eg: functions ,classes etc, that can be run directly and reused by the system.
one aside: the flutter engine provides a runtime for the flutter app written, and also flutter does not use native components , that is , the codes eg a bottom navigation bar is not converted to the equivalent on the target platform, rather flutter draws its own bottom navigation bar on the screen
- Debug build: The debug compilation is a Just In Time(JIT) compilation, and this is carried out by the dart JIT compiler. The flutter engine code is still converted to machine code of the target platform, but the dart code is not compiled directly to machine code, rather it is converted to an intermediate representation called kernel format. This is a bytecode that is interpreted as the app is run by the dart VM. The dart VM is part of the compiled flutter engine code.
one aside: JIT is what enables the hot reload of flutter apps, when changes are made to the code, flutter compiles it to the kernel bytecode, which is sent to the device,where the dart vm converts the updated code to machine code,and the flutter engine updates the user interface accordingly
Assets bundling: All assets and resources used(e.g. images,fonts), usually defined in pubspec.yaml, are bundled and packaged in the app. These resources are copied into a structured app directly to the app, making it possible for the running app to access them efficiently(These are usually stored in the flutter_assets folder in both android apk, and in ios ipa). Optimizations could be applied to these resources, like compressing images to make them smaller and improve efficiency. Also , platform specific assets defined in the respective native folders(android and ios), are compiled separately as they would natively, as explained in the previous sections of android compilation and ios compilation.
Native code compilation ( Platform channels and plugin resolution) : Flutter allows the use of native codes to implement platform specific functionalities as required by the developer, this is usually done through platform channels .Android specific codes are added to android folder, while ios specific codes to ios folder . Platform channels allow communication between dart and platform specific native code; this allows flutter to access native functionalities that are not natively supported in flutter, but can be accessed through native platform APIs,e.g. using sensors,or accessing device files. Plugins are packages that provide access to platform native functionalities, and plugins use platform channels. So all native codes are compiled using their respective native build systems(gradle for android and xcode: using Cocoapods for dependency management for ios). Moreover, the platforms specific codes are compiled as explained in the previous sections: Android specific codes are compiled as explained in android compilation above ,and produces the .dex file, so also ios specific codes are compiled and produces an ios executable binary file as explained in ios compilation previously. This compilation involves all native code, including code from external plugins that use native code.
One aside: For each plugin, Flutter makes the necessary modifications to platform-specific folders (e.g., downloading and adding files, creating and modifying files). It also adds native dependencies to the dependency management files (build.gradle for Android and Podfile for iOS), which are then resolved by the respective dependency management tools (Gradle for Android and CocoaPods for iOS).
App packaging: This involves bundling and structuring all the compiled resources and packaging them in the required manner.flutter delegates the platform specific build tools(gradle or xcode) the task of bundling all compiled codes and resources into the platform executable format.(.apk for android and .ipa for ios). For android , the .apk file contains all resources,assets,native code,dart code, and manifests files required to run the app, and usually contains: the compiled kotlin/java files (.dex),compiled native code for flutter and dart(.so libraries: eg libflutter.so for flutter engine, and libapp.so for the developer written dart code), resources: which is the res folder holding xml,colors and other assets for the android code, assets which holds flutter specific resources , like images and fonts, and the manifest.xml file which holds the app’s permissions and configuration files. In the same vein, the ios .ipa archive holds everything required by the app to run, including the .app payload folder and other resources. The .app payload houses: the compiled flutter engine code flutter.framework, the developer written code app.framework ,The compiled “runner” executable which initializes the flutter engine, native libraries .dylib,info.plist for the apps configuration and permissions, The compiled assets used in the projects ( fonts, images, etc)- assets.car, and code signature folder, holding the signing of the app.
Testing,signing and deployment: This is platform specific, and same as explained in the previous sections on android and ios 😌.
Code obfuscation(optional): If enabled the dart code is obfuscated in order to protect the code from reverse engineering, before being compiled to platform specific machine code(eg libapp.so for android and app.framework for ios). While for platform specific code obfuscation is the same process as explained in the sections above. Refer to the sections above on android and also on ios to get a refresh.
flutter android compilation steps
the following sections , shows some images of the overview of the contents in an anroid .apk file, built with flutter
overview of flutter android .apk file
helloworld.apk/lib
helloworld.apk/lib/arm64-v8a: showing compiled flutter codes
helloworld.apk/assets/
helloworld.apk/assets/flutter_assets
Top comments (0)