Notes on creating debug and release APKs using Android Studio and running them on phone/device

Last updated on 10 Feb. 2025
My post: Notes on using React Native without Expo framework and Expo Go,  https://raviswdev.blogspot.com/2025/02/notes-on-using-react-native-without.html covers how to create APKs for React Native projects not using Expo framework, and installing and running these APKs on my Samsung M21 Android phone.

That led me to explore creating APKs using Android Studio and installing and running these on my Samsung M21 phone. Notes related to this work are given below. I think the notes are of 5 Feb. 2025 or perhaps from a day or two earlier.


Build your app for release to users, https://developer.android.com/build/build-for-release :

If the build variant you've selected is a debug build type, then the APK is signed with a debug key and it's ready to install. If you've selected a release variant, then, by default, the APK is unsigned and you must manually sign the APK. Alternatively, you can select Build > Generate Signed Bundle / APK from the menu bar.

Android Studio saves the APKs you build in project-name/module-name/build/outputs/apk/.
----
The tutorial Greeting app has C:\Users\{username}\Projects\AndroidStudio\MyApplication\app\build\outputs\apk\debug\app-debug.apk (8467 KB) [Another directory: intermediaries also has app-debug.apk within a subfolder hierarchy with same/similar file size.]

Can I simply copy and install the app-debug.apk onto my Samsung phone? Copying into emulator (when earlier app has been uninstalled) installs the app (debug version) and it later runs as expected. Copied next to phone and ran it. It came up with Google Play Scan option which I chose. Later it was showing 'Installing' message for perhaps 2 to 3 min but this first attempt at install got into confused situ as I had to use some other app on phone after which I could not see the 'Installing' message screen. Opened apk again which prompted me for install and on choosing install, it got done in few seconds! The greeting card app shows its screen as expected on the phone!

Now I want to try creating a release apk for this project ...
Changed build variant to Release
Build > Generate Signed Bundle / APK -> Chose APK 
Now following: Generate an upload key and keystore, https://developer.android.com/studio/publish/app-signing#generate-key
Finished procedure and Release build has started. lot of downloading .. My 4G net is fast now (> 10 Mbps usually) ... build reported success and took 1 min. 58 secs.

C:\Users\{username}\Projects\AndroidStudio\MyApplication\app\release\app-release.apk got created of size: 5754 KB.
Could not run app using run button in Android Studio. But was able to drag-and-drop above apk file onto emulator (where I had uninstalled debug app version), which installed it. Then ran the app. It worked as expected.

On phone, uninstalled debug apk ... copied release apk .. opened it (around 11.41 PM)  ... accepted Google Play Scan option ... seems to have got done quickly ... Now Greeting Card 'Installing' dialog/modal is being shown (from 11.41 or 11.42 to 11.47 PM)... Tried to Cancel but it is not responding. So closed 'My Files' app from which I had opened the apk. Opened the release apk file from 'My Files' app again. Chose Install and this time, it got done in less than a minute! Ran the app and it very quickly (faster than debug apk-app) showed the screen. 'My Files' app shows app-release.apk as 5.62 MB (app-debug.apk is 8.27 MB). But Settings -> Apps -> Greeting Card shows 51.28 MB size.

Hmm. Less than 6 MB APK (release) file for trivial app which installs OK and loads very quickly on Samsung M21 phone is very pleasing to see.
....

Next I explored possibility of modifying the Greeting Card app to show current date & time. Google search gave Java code links but I needed Kotlin code.  The code below did the job:
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val sdf = SimpleDateFormat("dd/M/yyyy hh:mm:ss")
        val currentDate = sdf.format(Date())
        setContent {
            GreetingCardTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
//                    Greeting("Ravi Iyer")
                    Greeting(currentDate)
                }
            }
        }
    }
}
--------------
Now I want to see if I can have a tiny Android app which does what this tiny web app of mine does: Very Simple One-Touch Timestamp (on Launch) Creator/Recorder App,  https://github.com/ravisiyer/onetouchlaunchtimestamp .

==========

Probably 6 Feb. 2025
1.44 PM ... AS wizard started creating LaunchTimestamp project (Empty Activity Template). Importing 'LaunchTimestamp' Gradle Project took some time (downloaded stuff). But it got done in less than 2 minutes, I think (1 min 34 secs as per Sync message). Now time is 1.47 PM. That's great!
Clicked Build and Refresh at 1.50 PM. it was done by 1.51 PM (29 secs as per Build Output message). The preview shows correctly.
Run app starts Gradle build (got done in 25 secs) and also starts emulator and launches app onto it which took more time totally. But it seems the time from Run app to seeing app output on emulator was less than 2 mins. Now intermediaries dir has apk file in some nested subfolder but outputs folder does not have apk file.
...
...
https://developer.android.com/topic/libraries/architecture/datastore#kts [Datastore is recommended instead of SharedPreferences] ... DataStore is just too complex to use ...

...
Was able to show current launch date & time and previous (just one) launch date & time.
Chose build apk in AS .. finished in around 11 secs!
Now outputs directory has app-debug.apk file in a nested subdirectory. It is 8.5 MB.
Copying and installing on Samsung phone. Debug apk does not need going through process of signing key like release needs. So plan to use debug versions until stuff is stable.
It works on the Samsung phone! It takes a little time - perhaps a second - to show the screen with the data. Don't know if a release apk app will do it faster.
...

In Java but helped me explore using getStringSet and putStringSet functions of SharedPreferences, which needed me to use hashSetOf and HashSet: A Nightmare with Shared Preferences and StringSet, https://anupamchugh.medium.com/a-nightmare-with-shared-preferences-and-stringset-c53f39f1ef52 , 2018

Helped me explore using hashSetOf and adding to and traversing a HashSet in Kotlin: Kotlin hashSetOf(), https://www.geeksforgeeks.org/kotlin-hashsetof/ , Mar. 2023

HashSet is an unordered set ... I should replace it with an ordered set.

"The difference is that LinkedHashSet maintains the insertion order of the elements, unlike HashSet which does not guarantee the order of the elements." - Data Structures in Kotlin: Set — [PartIV], https://medium.com/wearejaya/data-structures-in-kotlin-set-partiv-82d0771f3420 , Jul. 2023.

That's what I need.

resizing or having a fixed size LinkedHashSet seems to be a hassle ... How to fix size of LinkedHashSet?,


Looks like the PutStringSet data is not assured to be returned in same order by GetStringSet. While LinkedHashSet is ordered PutStringSet and GetStringSet may be operating on it using its base class of Set and so not assuring order. I debugged the app and confirmed that at least in one case, PutStringSet data was not returned in same order by GetStringSet.

Solution was to use yyyy/MM/dd date format and sort the GetStringSet returned data in descending order.
=======
7 Feb. 2025

Reload activity in Android, https://stackoverflow.com/questions/3053761/reload-activity-in-android .. Based on the above, to redraw (main) screen, I tried:
finish();
startActivity(getIntent());
But that led to warning about "UnsafeIntentLaunch"
I next tried:
this.recreate();
That seems to work without any warning issue.

------------

Only issue that I can see from my limited testing on emulator is that at times, the 'Clear Launch Timestamps' button is shown over the status bar. In this case, clicking in the top part of the button which seems to be in status bar does not seem to have any effect. 
...
Built the debug APK .. got done quickly.
Uninstalled old app in emulator and drag-and-dropped debug-apk onto emulator. It installed it and later ran properly (except above button over status bar issue).
Uninstalled old app from phone, copied debug apk onto it and am installing it.
It seems to work but has the button shown over status bar issue. 
...

Seem to have got the fix for the button over status bar issue. Needed to use modifier.padding as shown below.
@Composable
fun FilledButtonExample(onClick: () -> Unit, modifier: Modifier = Modifier) {
    Button(onClick = { onClick() },
        modifier = modifier.padding()
    ) {
        Text("Clear Launch Timestamps")
    }
}

Works on phone too ... the button is shown below the status bar.
Minor UI issues: Left padding for button has to be added, Current Launch Time could be split into two lines as Samsung phone Portrait display splits it into two lines and so there is a left padding issue. Note that emulator showed the entire line as one line.

As of now, I need to move on to some other work and so I plan to stop/freeze this activity.
----------

9 Feb. 2025
The time is shown as 12 hrs time without AM or PM. So 01:33:00 can be 1.33 AM or 1.33 PM. Surely would be a simple format specifier fix. Plan to explore that when time permits.
---

10 Feb. 2025

Using HH instead of hh changed clock to 24-hrs in date & time output.
...

Used Valeriy Katkov response from above article and changed code to:
@Composable
fun FilledButtonExample(onClick: () -> Unit, modifier: Modifier = Modifier) {
    Button(onClick = { onClick() },
        modifier = modifier.padding(8.dp)
    ) {
        Text("Clear Launch Timestamps")
    }
}
---
That gave the margin! Changed other code as well to use such margin and remove space character padding.

Display content edge-to-edge in your app, https://developer.android.com/develop/ui/views/layout/edge-to-edge explains how using enableEdgeToEdge() results in app using full screen including status bar. 
For this trivial app, I don't need it. So I commented out the enableEdgeToEdge() call. ... That resulted in status bar being shown as blank!!! .. Reverted to using enableEdgeToEdge. Now status bar is shown.
Copied debug apk to phone and installed it. Its working OK.

I put up a separate post on the app with screenshot and apk file download link: Very Simple One-Touch Timestamp (on Launch) Creator/Recorder Android App, https://raviswdev.blogspot.com/2025/02/very-simple-one-touch-timestamp-on.html .
------------

15 Feb. 2025

Create clickable sections of text with LinkAnnotation, https://developer.android.com/develop/ui/compose/text/user-interactions#create-clickable-text has a problem as described in: Compilation help request - kotlin compose "withLink" giving me 'unresolved reference' error, https://www.reddit.com/r/Kotlin/comments/1er1lkf/compilation_help_request_kotlin_compose_withlink/ . I faced a similar/the same issue.

LaunchTimestamp Release Sync (Import) took 7 min. 13 secs. Net was fast (>10 Mbps) and so that was not the issue.

"It's generally not recommended to use the same app signing key for multiple apps, it's more secure to use a unique key for each app. However, if you need to use the same app signing key for multiple apps this is possible. Either, you can upload a copy of the existing app signing key when configuring Play App Signing. ", https://developer.android.com/guide/app-bundle/faq .

I created/generated a key for the app (release variant).
Then the (gradle) build started. It got over in 50 sec, 503 ms!
-----

LaunchTimestamp Release app opens very fast on Samsung M21 mobile. There was no discernible wait time between touch (when recognized) and app screen being shown when I tried it multiple times with few other apps open or no other apps open at that time. This is a significant and very pleasing improvement over the debug app which had a discernible wait time btw touch/tap and opening of main screen.

On my mobile, the older Chrome webpage app is also slightly slow at load time if Chrome is not already running (first Chrome has to be loaded and then this page). Also the opened page is retained as a tab when the webpage app is invoked again. So closing of these tabs becomes an additional activity. This issue is not there in the Android app.

Overall, I am very satisfied and very pleased with the release version of this Android app. As it does not use any library/framework like React Native or Expo, the size of the release file is small (5.7 MB for current version) and it loads very fast (from user point of view, instant load). So now I have a tiny program that I wrote for my handheld computer which my Samsung Android mobile is, and which program has some utility for me, and which opens very fast and runs very fast (adding a timestamp is also user-wise instantaneous). [For clear all timestamps, on confirm, the timestamps get cleared fast but the confirm dialog stays open for a few seconds. As that is not a regular user activity, I don't want to invest time into understanding and then perhaps solving the minor issue.] I had to learn little bit of Android programming without library/framework like React Native/Expo, and which learning, beyond initial barebones tutorial on Jetpack Compose, was based on Google search followed by trial-and-error (as against going through an organized tutorial beyond the barebones tutorial mentioned earlier). I got stuck for some time on some issues but eventually figured them out. But that was worth it. Now I can write small native programs using only Android Jetpack Compose components (without framework components) in Kotlin programming language for my Android mobile (which should most probably work on other Android devices too).

That's a significant, very satisfying and very pleasing achievement for me as a software developer and an Android mobile user. I mean, since early 2018, I have been using Android mobiles (LYF C459 low-priced 4G Android smartphone and its setup, https://ravisiyer.wordpress.com/2018/02/04/lyf-c459-low-priced-4g-android-smartphone-and-its-setup/). Prior to that I was using Nokia Symbian phones. While I was quite amazed at these handheld computers I had and the various apps I used on them including some apps I downloaded, I could not write apps/programs for them, except as web pages which I would access through an Internet browser from these devices. In contrast, I was always able to write programs for my PC even if I was doing only simple scripts stuff for many years when I was focused on social media writing as my main activity. I mean, I knew that if I wanted something very badly for my PC, which was not too difficult or time-consuming, I could program it myself. That was not the case for either the Nokia Symbian phones I had nor the Android phones I had, till now in early 2025. Therefore I am very pleased and very satisfied with this achievement of being able to now write small utility Android apps that use only basic native Android features and so will typically load and run very fast on my Android phone and other similar or more powerful Android phones and other Android devices.

Comments