Android App Development Lab Manual
Android App Development Lab Manual
LAB MANUAL
MISSION
1. To provide value-based education through multi grade teaching
methodologies and modern education facilities.
Once you launched Android Studio, its time to mention JDK7 path or later version in
android studio installer.
Below the image initiating JDK to android SDK
Need to check the components, which are required to create applications, below the image has
selected Android Studio, Android SDK, Android Virtual Machine and performance(Intel chip).
Need to specify the location of local machine path for Android studio and Android SDK, below
the image has taken default location of windows 8.1 x64 bit architecture.
Need to specify the ram space for Android emulator by default it would take 512MB of
local machine RAM.
At final stage, it would extract SDK packages into our local machine, it would take a while time
to finish the task and would take 2626MB of Hard disk space.
After done all above steps perfectly, you must get finish button and it gonna be open
android studio project with Welcome to android studio message as shown below.
You can start your application development by calling start a new android studio project. in a new
installation frame should ask Application name, package information and location of the project.
After entered application name, it going to be called select the form factors your application
runs on, here need to specify Minimum SDK
The next level of installation should contain selecting the activity to mobile, it specifies the default
layout for Applications
Step 3 - Create Android Virtual Device
To test your Android applications, you will need a virtual Android device. So before we start
writing our code, let us create an Android virtual device. Launch Android AVD Manager
Clicking AVD_Manager icon as shown below
After Click on a virtual device icon, it going to be shown by default virtual devices which are
present on your SDK, or else need to create a virtual device by clicking Create new Virtual
device button
EXPERIMENT -2
Aim: Building a Basic User Interface.
• Design a simple user interface using XML
• Add various user interface components, such as buttons, text fields, and images.
• Implement event handling for user interactions.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<RelativeLayout xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="[Link]">
</RelativeLayout>
[Link]
package [Link].project2;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState)
{ [Link](savedInstanceState);
setContentView([Link].activity_main);
activity_main.xml
<!-- activity_main.xml -->
<RelativeLayout
xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter your text here"
android:layout_marginTop="20dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
android:layout_below="@id/editText"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
</RelativeLayout>
Activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Data from MainActivity:"
android:layout_centerInParent="true"/>
</RelativeLayout>
[Link]
package [Link].project2;
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
[Link](new [Link]()
{ @Override
public void onClick(View v) {
// Get text from EditText
String textToSend = [Link]().toString();
[Link]
package [Link].project2;
import [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_second);
/ Retrieve the text from the
Intent Intent intent = getIntent();
if (intent != null && [Link]("text")) { String
receivedText = [Link]("text");
Output:
EXPERIMENT-4
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
xmlns:app="[Link]
xmlns:tools="[Link]
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context="[Link]">
<fragment
android:id="@+id/fragment1"
android:name="[Link].Fragment1"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/fragment2"
android:name="[Link].Fragment2"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
fragment_fragment1.xml
<FrameLayout xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5DC"
tools:context="[Link].Fragment1">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
File: fragment_fragment2.xml
<FrameLayout xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0FFFF"
tools:context="[Link].Fragment2">
[Link]
package [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState)
{ [Link](savedInstanceState);
setContentView([Link].activity_main);
/ Method to replace Fragment1 with Fragment2 and add the transaction to the
backstack public void replaceFragment() {
Fragment2 fragment2 = new Fragment2();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
[Link]([Link].fragment_container, fragment2);
[Link](null); // Add transaction to backstack [Link]();
}
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
{ getSupportFragmentManager().popBackStack(); // Pop transaction from backstack
} else {
[Link](); // Default back button behavior
}
}
}
[Link]
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class Fragment1 extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState); }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return [Link]([Link].fragment_fragment1, container, false);
}
}
File: [Link]
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class Fragment2 extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container, Bundle savedInstanceState) {
return [Link]([Link].fragment_fragment2, container, false);}}
OUTPUT:
EXPERIMENT-5
activity_main.xml.
activity_alarm_receiver.xml.
if([Link]()>time)
{
if (calendar.AM_PM == 0)
time = time + (1000*60*60*12);
else
time = time + (1000*60*60*24);
}
[Link](AlarmManager.RTC_WAKEUP, time, 10000, pendingIntent);
}
else
{
[Link](pendingIntent);
[Link]([Link], "ALARM OFF", Toast.LENGTH_SHORT).show();
}
}
}
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class AlarmReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
[Link](context, "Alarm! Wake up! Wake up!",
Toast.LENGTH_LONG).show(); Uri alarmUri =
[Link](RingtoneManager.TYPE_ALARM); if (alarmUri == null)
{
alarmUri =
[Link](RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone = [Link](context, alarmUri);
[Link]();
}}
[Link].
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[Link]
package="[Link]" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="[Link]" />
<category android:name="[Link]" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver" >
</receiver>
</application>
</manifest>
Output:
EXPERIMENT-6
Aim: Implementing Data Storage and Retrieval
1. Use shared preferences for saving and retrieving data.
2. Implement SQLite database for data persistence.
3. Fetch data from web services and parse JSON responses.
[Link]:
public class MainActivity extends
AppCompatActivity { private EditText
rollNoEditText, nameEditText,
marksEditText; private Spinner branchSpinner; private Button addButton,
retrieveButton; private StudentDbHelper dbHelper; @Override protected
void onCreate(Bundle
savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
rollNoEditText = findViewById([Link].roll_no_edit_text); nameEditText
= findViewById([Link].name_edit_text); marksEditText =
findViewById([Link].marks_edit_text); branchSpinner
= findViewById([Link].branch_spinner); addButton =
findViewById([Link].add_button); retrieveButton =
findViewById([Link].retrieve_button); dbHelper = new
StudentDbHelper(this);
[Link](new [Link]() {
@Override
public void onClick(View v) {
String rollNo = [Link]().toString().trim();
String name = [Link]().toString().trim();
String branch = [Link]().toString();
String marksString = [Link]().toString().trim();
[Link].
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link]; import
[Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link]);
buttonSend = findViewById([Link]);
buttonCapture = findViewById([Link]);
buttonSelect = findViewById([Link]);
textSMS = findViewById([Link]); textLon =
findViewById([Link]); imageView =
findViewById([Link]); videoView =
findViewById([Link]);
/ Obtain the SupportMapFragment and get notified when the map is ready to be
used. SupportMapFragment mapFragment = (SupportMapFragment)
getSupportFragmentManager().findFragmentById([Link]);
[Link](this);
[Link](view -> {
dispatchTakePictureIntent();
});
[Link](view -> {
openGallery();
});
/ Play video
playVideo(); }
@Override
protected void onDestroy() {
[Link]();
/ Stop location updates when activity is destroyed
if (mlocManager != null) {
[Link](mlocListener);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
grantResults) {
[Link](requestCode, permissions,
grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION) {
if ([Link] > 0 && grantResults[0]
== PackageManager.PERMISSION_GRANTED) {
/ Location permission
granted } else {
/ Location permission denied
[Link](this, "Location permission denied", Toast.LENGTH_SHORT).show();
}
}
}
public class MyLocationListener implements LocationListener
{ public void onLocationChanged(Location loc) {
double lat = [Link]();
double lon = [Link]();
[Link]([Link](lat));
[Link]([Link](lon));
/ Move camera to current location
[Link]([Link](new LatLng(lat, lon),
15));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{ [Link](requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK)
{ Bundle extras = [Link]();
Bitmap imageBitmap = (Bitmap) [Link]("data");
[Link](imageBitmap);
} else if (requestCode == REQUEST_PICK_IMAGE && resultCode == RESULT_OK &&
data != null) {
Uri selectedImage = [Link]();
[Link](selectedImage);
}
}
}
[Link]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="System" />
<EditText
android:id="@+id/editTextSMS"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="top" />
<EditText
android:id="@+id/textlon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="top" />
<Button
android:id="@+id/buttonSend"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Send" />
<Button
android:id="@+id/buttonCapture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Capture Image" />
<Button
android:id="@+id/buttonSelect"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Select Image" />
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp" />
</LinearLayout>
Output:
EXPERIMENT-8
Aim: Testing and Debugging Android Apps
Use debugging tools in Android Studio to identify and fix
issues.
Perform unit testing to ensure app functionality.
Optimize app performance using profiling tools
Debug your app
Android Studio provides a debugger that lets you do the
following and more:
• Select a device to debug your app on.
• Set breakpoints in your Java, Kotlin, and C/C++ code.
• Examine variables and evaluate expressions at runtime.
Enable debugging
Use a build variant that includes debuggable true (isDebuggable = true in Kotlin
scripts) in the build configuration.
Usually, you can select the default "debug" variant that's included in every
Android Studio project, even though it's not visible in the [Link] file.
However, if you define new build types that should be debuggable, you must
add debuggable true to the build type:
GroovyKotlin
android {
buildTypes {
customDebugType {
debuggable true
...
}
}
}
If your app depends on a library module that you also want to debug, that library
must also be packaged with debuggable true so it retains its debug symbols. To
ensure that the debuggable variants of your app project receive the debuggable
variant of a library module, publish non-default versions of your library.
Start debugging
If you don't have any devices configured, then you need to either connect a device via
USB, connect a device via Wi-Fi, or create an AVD to use the Android Emulator.
If your app is already running on the device, a dialog is displayed asking if you want to
switch from Run to Debug. The device will need to restart in order to begin debugging. To
keep the same instance of the app running, click Cancel Debug and instead attach the
debugger to a running app. Otherwise, Android Studio builds an APK, signs it with a
debug key, installs it on your selected device, and runs it.
If you add C and C++ code to your project, Android Studio also runs the LLDB debugger
in the Debug window to debug your native code.
If the Debug window isn't open, select View > Tool Windows > Debug, or
If your app is already running on your device, you can start debugging without
restarting your app as follows:
The Processes tab in the Device Explorer (View > Tool Windows > Device
Explorer) also has a list of debuggable processes. From there you can select a
process .
Because different debugger tools are required to debug Java/Kotlin code and C/C+
+ code, the Android Studio debugger lets you select which debugger type to use. By
default, Android Studio decides which debugger to use based on which languages it
detects in your project using the Detect Automatically debugger type.
To manually select the debugger in the debug configuration, click Run > Edit
Configurations. You can also select the debugger in the dialog that appears
when you click Run > Attach debugger to Android process.
The debug types available include the following:
Detect Automatically
Select this debug type if you want Android Studio to automatically choose the
best option for the code you are debugging. For example, if you have any C or
C++ code in your project, Android Studio automatically uses the Dual debug
type. Otherwise, Android Studio uses the Java-Only debug type.
Java Only
Select this debug type if you want to debug only code written in Java or
Kotlin. The Java-Only debugger ignores any breakpoints or watches you set
in your native code.
Select this debug type if you want to use only LLDB to debug your code.
When using this debug type, the Java debugger session view is not available.
By default, LLDB inspects only your native code and ignores breakpoints in
your Java code. If you want to also debug your Java code, switch to either the
Detect Automatically or Dual debug type.
Native debugging only works on devices that meet the following requirements:
To check whether the device supports run-as, run the following command on
the ADB shell that is connected to your device:
sysctl [Link].ptrace_scope
Select this debug type if you want to switch between debugging both Java
and native code. Android Studio attaches both the Java debugger and LLDB
to your app process so you can inspect breakpoints in both your Java and
native code without restarting your app or changing your debug configuration.
In figure 2, notice the two tabs to the right of the Debug window title. Because
the app has both Java and C++ code, one tab is for debugging the native
code and the other for debugging Java code, as indicated by -java.
Figure 3. Tab for debugging native code and tab for debugging Java code.
Note: While debugging native code that is optimized by the compiler, you may get
the following warning message:
This function was compiled with optimizations enabled. Some
debugger features may not be available.
The system log shows system messages while you debug your app. These
messages include information from apps running on the device. If you want to use
the system log to debug your app, make sure your code writes log messages and
prints the stack trace for exceptions while your app is in the development phase.
The following example shows how you might add log messages to determine
whether previous state information is available when your activity starts:
Java
import [Link];
...
public class MyActivity extends Activity {
private static final String TAG = [Link]();
...
@Override
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
Log.d(TAG, "onCreate() Restoring previous state");
/* restore state */
} else {
Log.d(TAG, "onCreate() No saved state available");
/* initialize app */
}
...
}
}
During development, your code can also catch exceptions and write the stack trace
to the system log:
Java
void someOtherMethod() {
try {
...
} catch (SomeException e) {
Log.d(TAG, "someOtherMethod()", e);
}
}
You can view and filter debug and other system messages in the Logcat window,
as shown in figure 4. For example, you can see messages when garbage collection
occurs or messages that you add to your app with the Log class.
For a description of Logcat and its filtering options, see Write and view logs with
Logcat.
Line breakpoint
The most common type is a line breakpoint that pauses the execution of your
app at a specified line of code. While paused, you can examine variables,
evaluate expressions, and then continue execution line by line to determine
the causes of runtime errors.
Method breakpoint
A method breakpoint pauses the execution of your app when it enters or exits
a specific method. While paused, you can examine variables, evaluate
expressions, and then continue execution line by line to determine the
causes of runtime errors. When you set a breakpoint on a composable
function, the debugger lists the parameters of the composable and their state
to help identify what changes might have caused the recomposition.
Field breakpoint
A field breakpoint pauses the execution of your app when it reads from or
writes to a specific field.
Exception breakpoint
You can set conditional breakpoints that will only suspend execution if specific
conditions are met. You can also set logging breakpoints that write to Logcat without
suspending execution. This can help avoid littering your code with log statements.
A red dot appears next to the line when you set a breakpoint, as shown in figure 5.
When your code execution reaches the breakpoint, Android Studio pauses
execution of your app.
To identify the state of the app, use the tools in the Debugger tab:
• To examine the object tree for a variable, expand it in the Variables view. If the
Over .
• To advance to the first line inside a method call, click Step Into .
• To advance to the next line outside the current method, click Step Out .
When Android Studio deploys your app to your target device, the Debug
window opens with a tab or debug session view for each debugger process, as
shown in figure 6.
While debugging C/C++ code, you can also set special types of breakpoints,
called watchpoints, that can suspend your app process when your app interacts
with a particular block of memory. To learn more, read the section about how to add
watchpoints.
The Breakpoints window lets you enable or disable each breakpoint from the list in
the pane. If a breakpoint is disabled, Android Studio doesn't pause your app when it
hits that breakpoint.
Select a breakpoint from the list to configure its settings. You can configure a
breakpoint to be disabled at first and have the system enable it after a different
breakpoint is hit. You can also configure whether a breakpoint should be disabled
after it is hit. To set a breakpoint for any exception, select Exception Breakpoints in
the list of breakpoints.
In the Debugger window, the Frames pane lets you inspect the stack frame that
caused the current breakpoint to be hit. This enables you to navigate and
examine the stack frame and also inspect the list of threads in your Android app.
To select a thread, use the thread selector menu and view its stack frame. Click the
elements in the frame to open the source in the editor. You can also customize the
thread presentation and export the stack frame as discussed in the Examine
Frames guide.
Inspect variables
In the Debugger window, the Variables pane lets you inspect variables when the
system stops your app on a breakpoint and you select a frame from the Frames
pane. The Variables pane also lets you evaluate ad hoc expressions using
static methods and/or variables available within the selected frame.
To add an expression to the object tree (while the application is being debugged):
Alternatively, if the object tree contains the expression you want to watch, you can
drag it to the top of the tree to add it as a watched expression.
Watched expressions will update when breakpoints are hit or you step through
your code.
Evaluated expressions will remain displayed at the top of the object tree until you
manually evaluate another expression or step through your code.
To remove a watched expression from the object tree, right-click the expression and
then click Remove Watch.
Add watchpoints
While debugging C/C++ code, you can set special types of breakpoints,
called watchpoints, that can suspend your app process when your app interacts
with a particular block of memory. For example, if you set two pointers to a block of
memory and assign a watchpoint to it, using either pointer to access that block of
memory triggers the watchpoint.
• Your target physical device or emulator uses an x86 or x86_64 CPU. If your device uses an
ARM CPU, then you must align the boundary of your variable's address in memory to either
4 bytes, for 32-bit processors, or 8 bytes, for 64-bit processors. To align a variable in your
native code, specify __attribute__((aligned(num_bytes))) in the variable deceleration, as shown
below:
• You have assigned three or fewer watchpoints already. Android Studio only supports up
to four watchpoints on x86 or x86_64 target devices. Other devices may support fewer
watchpoints.
Note: When debugging your app with 32-bit ARM ABIs, adding a watchpoint or hovering over
variables inside the code to investigate their values may cause a crash. As a workaround, debug
using 64-bit ARM, x86, or x86_64 binaries. This issue will be fixed in an upcoming Android
Studio release.
1. While your app is suspended on a breakpoint, navigate to the Variables pane in your LLDB
session view.
2. Right-click a variable that occupies the block of memory you want to track
and select Add Watchpoint.
To view all your watchpoints and configure watchpoint settings, click View
Breakpoints in the Debug window. The Breakpoints dialog appears, as shown
in figure 10.
After you add your watchpoint, click Resume Program in the Debug window to
resume your app process.
.
EXPERIMENT-9
First are the debug APK files that are generated solely for testing purposes. They
will run on your Android mobile. However, they cannot be uploaded to the Play
Store or made available to the public.
Secondly, you can generate signed APK files. Signed APK files come in handy
when you've tested your application and it is ready to be uploaded on the Play Store
and released to the general [Link] tutorial will show you how to create an
Android app by generating APK files using Android [Link] things first: open up
a project file in Android Studio. If you don’t have a project file yet, simply create
a New Project.
First, open up your project or application that you want to import into an APK file.
Then, select Build > Build Bundle(s)/APK(s) > Build APK(s) from the toolbar
menu.
If you miss the notification, you can still locate the APK file in the following path
within your project folder: app/build/outputs/apk/debug. The file is named app-
[Link] by default.
In the next window, you will be shown the module (your application) for which the
APK file is being generated. You’ll be asked about your Key store path, Key store
password, Key alias, and the Key password.
Keys are used by the developer to access their application once it has been
uploaded to the Play Store. The need for the keys usually arises when you have
to update your application. All of the keys are stored in the key store.
Both the key store and the keys are protected by passwords of their own. The
passwords should be at least six characters in length. Also, it is a good practice to
keep multiple copies of your keys since they are your only gateway to your
application. If the key is lost, you will not be able to access your application or update
it.
Creating your own app requires you to create a new key store. To do so,
select Create new. You will find it underneath the input field where you enter the key
store path.
In the new window, enter the path for your new key store, and then enter a
password to protect it.
In the same window, you will also be setting a new key for your application. Enter an
identity for your key in the key alias field and then enter a password for it.
You can keep the same password as that of your key store, but it's a good practice to
give a new password to each of your keys. The same goes for the key alias.
The next field defines the validity of your application. This is the duration after which
the key to your application will expire, leaving your application inaccessible.
The default validity for a key is 25 years.
For each key that you generate, you’re given a certificate that contains all the
information about you and your company. You don't necessarily have to fill in all
the details—just choose the ones you think should go on your certificate. A key will
still be generated, even without filling in each field of the certificate.
Finishing Up
Once you have filled in the details for the certificate, select OK. You will then
be directed back to the Generate Signed Bundle or APK screen.
Here, all of the fields will now be pre-filled for you. Go through all the details to stay
on the safe side. Then, select Next.
On the last screen, you will now be able to see the destination of your Signed
APK file. Below that, you will see two more options: Debug and [Link]
is used when the application is still in the testing phase. Since your application has
passed the testing phase and is ready for deployment, select Release.
You will be notified by Android Studio once the APK build is finished