In a fairytale world, you would be able to build React Native applications without having to know anything about the native mobile development, However the reality is far from that. During my time working with React Native, in so many occasions, I faced bugs that I struggled to fix, mainly because I knew nothing about IOS, nor Android.
Driven by shame 😅 and curiosity, I decided to to dig a little bit in native mobile development, and combine it with things I have learned during my time working with React Native, to write this article, and save you some pain learning all this by yourself.
The content of this article may seem like a basic knowledge for someone coming for a mobile background, however most people learning and working with React Native are coming from a frontend background.
In the first part of our sequel, we will focus on Android, more precisely understanding concepts and files that you will interact with as React Native developer.
I hope you’re ready for your first walk of atonement .
Android Versioning and API
Version name and code name
The first Android mobile was publicly released with Android 1.0 in 2008, today Android goes from version 1 to 13 , We tend to have one major version per year, and each of these (except 1.0) has a Codename. Codenames are inspired by tasty treats, for example Android Pie aka Android 10.
As a developer, you will rarely need to know about Android versions, except in some rare cases where knowing the Android version a phone is operating on, will help you conclude which Api level it is using, but what is an API level you may ask?
Api level aka Sdk number
Api number is consecutive integer that express the current version of the api. It is a number that we are going to interact with several time during the development of our app.
Each application has three different api numbers:
Minimum SDK version : defines instability, it indicates the minimum api number that we are going to support. In a simple way, your application will only work in phones with equal or greater api level.
Android Studio has a way to help you pick the best minimum sdk . In order to to that, Open Android studio and create a new project, you will see the window below.
Click on help me choose, and you’ll see a diagram that represents each api level in addition to the percentage of users you’re going to cover.
Depending on your business, and how many users you would like to reach, you choose the right sdk level.
Target SDK version : the version of the sdk that we tested our app on. This number tells the Android operating system that our application was working fine in this version, so the OS will act accordingly to make sure our app is working fine in versions that may come up in the future.
Assume, for example, that foldable phones were not included in the Android SDK until API 30, If we compile the app with a target of 28, it means we were unaware of foldable phones at the time. As a result, we are not foldable compatible. Even if you run your app on a foldable device, the phone will recognize that your app is incompatible with the concept of a foldable device.
Compile SDK : This is not shipped with the app; rather, it is a compiler that we are using. The more modern the compiler, the more efficient and superior the output. And we usually use the most recent version.
Configuration files
build.gradle
Now that you know what is an sdk number, you might be wondering where can I change my sdk values?
If you opened android/build.gradle
in a React Native project, you will see something like:
buildscript {
ext {
buildToolsVersion = "31.0.0"
minSdkVersion = 23
compileSdkVersion = 31
targetSdkVersion = 31
ndkVersion = "21.4.7075529"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.0.4")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:4.1.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
mavenCentral {
// We don't want to fetch react-native from Maven Central as there are
// older versions over there.
content {
excludeGroup "com.facebook.react"
}
}
google()
maven { url 'https://www.jitpack.io' }
}
}
project.ext {
excludeAppGlideModule = true
}
Every Android project requires a Gradle to generate an apk from the project’s.java and.xml files. Simply put, a gradle takes all of the source files (java and XML) and applies appropriate tools, such as converting the java files into dex files and compressing them all into a single file called apk that is actually used.
android/gradle.build
is a top-level build file where you can add configuration options common to all modules.
You can see the different values that we talked to about earlier, like minSdkVersion and targetSdkVersion, and you can change them directly from there.
You can see also see some additional values like:
build Tools Version, the version of the compilers that you want to use.
Ndk Version, The Android Native Development kit is a tool set that lets you implement parts of your app in native code, using languages such as C and C++.
Different architectures may require different ndk versions, to guarantee that, you can set different ndk values based on your architecture as below
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// For Android Users, we need to use NDK 23, otherwise the build will
// fail due to paths longer than the OS limit
ndkVersion = "23.1.7779620"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
}
Gradle can resolve dependencies from one or many repositories. You can list them in repositories like
repositories {
google()
mavenCentral()
}
These are the most popular repositories, and you will usually find most of your required dependencies in them. Actually, during my time with React Native, I only had to change this part of build.gradle one time, when we needed to use a dependency that resides in the JCenter repository.
For the rest of the file, I never had to change any of these values, but if you need more information about Gradle, and how to configure it, you can visit the docs.
In addition to the top level build.gradle
, there is also what we call module-level build.gradle
inside android/app
. Here you can add dependencies you need in your Android application.
Android manifest
The manifest is an xml file that describes essential informations about your app to the Android build tools, the Android operating system, and Google Play.
A manifest file usually looks like
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.obytes.development">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:allowBackup="false"
android:theme="@style/BootTheme"
android:usesCleartextTraffic="true"
android:screenOrientation="portrait"
>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
the manifest does the following things:
-
Declaring the app component
-
Identifies any user permissions that the app requires, such as Internet access or contact read-access.
-
Declares the hardware and software features that the app uses or requires, such as a camera, Bluetooth services, or a multitouch screen.
-
Declares which API libraries (other than the Android framework APIs) the app must be linked against, such as the Google Maps library.
I have never came a cross a project where I didn’t need to interact with this file, therefore it would help you to know the main element of a manifest file and their purposes, which are:
<manifest>
The manifest is the main component of the AndroidManifest.xml file. The package field describes the package name of the activity class. It must include an xmlns:android and package attribute-specified application> element.
<application>
A manifest can contain only one application node. It uses attributes to specify the metadata for your application (including its title, icon, and theme).
<activity>
Declares an activity (an Activity subclass) that implements part of the application’s visual user interface. All activities must be represented by <activity>
elements in the manifest file. Any that are not declared there will not be seen by the system and will never be run.
<uses-permission>
It is contained within the <manifest>
element and describes a system permission that the user must grant for the app to function properly.
<intent-filter>
An Intent is a messaging object you can use to request an action from another app component. By adding <intent-filter>
to your activity, you what an activity can do.
I invite you to check intents-filters docs to understand more the subject.
If you need more details about each and every element of the manifest file, you can reach out to this guide
- Bundling App For production
You probably heard of Android package, and Android bundle, if you’re not sure what is the difference, I got you.
APK
An Android package, which is an archive file with an .apk suffix, contains the contents of an Android app that are required at runtime and it is the file that Android-powered devices use to install the app.
to generate an APK you run
cd android && ./gradlew assembleRelease
ABB
An Android App Bundle, which is an archive file with an .aab suffix, contains the contents of an Android app project including some additional metadata that is not required at runtime. An AAB is a publishing format and is not installable on Android devices, it defers APK generation and signing to a later stage.
When distributing your app through Google Play for example, Google Play’s servers generate optimized APKs that contain only the resources and code that are required by a particular device that is requesting installation of the app.
to generate an ABB you run
cd android && ./gradlew bundleRelease
Now that you know the difference between these formats and how to generate them, you may be wondering how can you publish your android app in Play Store, I will not be covering it in this article, since my colleague Youssouf Elazizi wrote a really detailed article about how to publish apps using Github Actions, I highly recommend you follow his tutorial.
Congratulations, you have confessed your Android sins, and walked your first walk of shame, don’t forget to keep an eye on our blog for the next part of this sequel, which will cover your IOS sins.