Build a cryptocurrency alert app using Kotlin and Go: Part 1 — The frontend
Tags: cryptocurrency, kotlin, go, pusher
Published: 2018-09-05 06:25:21

---
title: Build a cryptocurrency alert app using Kotlin and Go: Part 1 — The frontend
published: true
description: Ever wondered how to build a cryptocurrency app with push notification support, here's how.
tags: cryptocurrency, kotlin, golang, pusher
---

> You will need Android Studio 3+ and Go 1.10.2+ installed on your machine. You should have some familiarity with Android development and the Kotlin language.

Cryptocurrency is one of the hot topics today and as a result of this, many people have purchased many cryptocurrencies. However, the market is unpredictable and changes very often, so people tend to keep an eye on the changes in the price of their asset.

In this post, we will create an app that watches for changes in the value of cryptocurrencies in realtime and notifies the user when the changes occur. We will focus on two very popular cryptocurrencies — Bitcoin and Ethereum. When we are done, your phone will receive a push notification when the value of Bitcoin and Ethereum either exceeds or goes below a value you specify in the settings of the app.

Here is a screen recording of what we will build:

![](https://cdn-images-1.medium.com/max/800/0*9g0iD4TbKe_gBYrI.gif)

### Prerequisites

To follow along, you need the following installed:

* Android Studio installed on your machine (v3.x or later). [Download
here](https://developer.android.com/studio/index.html).
* Go version 1.10.2 or later [installed](https://golang.org/doc/install#install).
* [SQLite installed](http://www.sqlitetutorial.net/download-install-sqlite/) on
your machine.
* Basic knowledge on using the Android Studio IDE.
* Basic knowledge of Kotlin programming language. See the [official
docs](https://kotlinlang.org/docs/reference/).
* Basic knowledge of Go and the [Echo framework](https://echo.labstack.com/).

### Building our Android application

First, launch Android Studio and create a new application. Enter the name of your application, for example, **CryptoAlert** and then enter the package name.Make sure the **Enable Kotlin Support** checkbox is selected. Choose the minimum SDK, click **Next,** choose an **Empty Activity** template, stick with the MainActivity naming scheme and then click **Finish**.

#### Creating a Pusher Beams application

Since Pusher Beams relies on Firebase, we need an FCM key and a `google-services.json` file. Go to your [Firebase console](https://console.firebase.google.com/u/0/) and click the **Add project** card to initialize the app creation wizard.

Add the name of the project, for example, `crypto-``alert`, read and accept the terms of conditions. After this, you will be directed to the project overview screen. Choose the **Add Firebase to your Android app** option.

The next screen will require the package name of your app. You can find your app’s package name in your app-module `build.gradle` file. Look out for the `applicationId` value. Enter the package name and click **Next**. You will be prompted to download a `google-services.json` file. Download the file and skip the rest of the process. Add the downloaded file to the app folder of your project - `name-of-project/app`.

To get the FCM key, go to your project settings on Firebase, under the Cloud messaging tab you should see the server key.

Next, login to the new [Pusher dashboard](https://dash.pusher.com/). You should sign up if you don’t have an account yet.

Open your Pusher Beams dashboard and create a new Pusher Beams application.

After creating your instance, you will be presented with a quick-start guide. Select the **Android quick-start**. After you add the FCM key, you can exit the quick-start guide.

#### Adding functionalities to our application

For our app to work, we need to pull in a couple of dependencies. To do this,
add the following to the project `build-gradle` file:

```
// File: ./build.gradle
buildscript {
    // [...]
    dependencies {
        // [...]
        classpath 'com.google.gms:google-services:4.0.0'
    }
}
// [...]
```

Next, add the following to the app module `build.gradle` file:

```
// File: ./app/build.gradle
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
    implementation 'com.google.firebase:firebase-messaging:17.1.0'
    implementation 'com.pusher:push-notifications-android:0.10.0'
    [...]
}
// Add this line to the end of the file
apply plugin: 'com.google.gms.google-services'
```

Above we included [Retrofit](https://github.com/square/retrofit) — a package for making network calls, and then the Pusher Beams package for sending push notifications. The additional Google services are dependencies for the Pusher Beams package. Sync your gradle files to make the libraries available for use.

Next, create a new interface named `ApiService` and paste the code below:

```
// File: ./app/src/main/java/{package-name}/ApiService.kt
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST

interface ApiService {
    @POST("/btc-pref")
    fun saveBTCLimit(@Body body: RequestBody): Call<String>

    @POST("/eth-pref")
    fun saveETHLimit(@Body body: RequestBody): Call<String>

    @GET("/fetch-values")
    fun getValues():Call<String>
}
```

This file is used to by Retrofit to know the endpoints to be accessed. The first endpoint `/btc-pref` is used to set the Bitcoin limits. The next endpoint `/eth-pref` is used to save the Ethereum limits. The last endpoint `/fetch-values` is used to get the current values of the cryptocurrencies.

To make use of network services in your application, add the internet permission in your `AndroidManifest.xml`file like so:

```
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cryptoalat">
    <uses-permission android:name="android.permission.INTERNET"/>
    
    [...]

</manifest>
```

Next, we will manage notifications in our app. Create a new service named
`NotificationsMessagingService`and paste this:

```
// File: ./app/src/main/java/{package-name}/NotificationsMessagingService.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import android.support.v4.app.NotificationCompat
import android.support.v4.app.NotificationManagerCompat
import com.google.firebase.messaging.RemoteMessage
import com.pusher.pushnotifications.fcm.MessagingService

class NotificationsMessagingService : MessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        val notificationId = 10
        val channelId  = "crypto_channel"
        lateinit var channel: NotificationChannel
        val intent = Intent(this, MainActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
        val mBuilder = NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(remoteMessage.notification!!.title!!)
                .setContentText(remoteMessage.notification!!.body!!)
                .setContentIntent(pendingIntent)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager = applicationContext.getSystemService(NotificationManager::class.java)
            val name = getString(R.string.channel_name)
            val description = getString(R.string.channel_description)
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            channel = NotificationChannel("crypto_channel", name, importance)
            channel.description = description
            notificationManager!!.createNotificationChannel(channel)
            notificationManager.notify(notificationId, mBuilder.build())
        } else {
            val notificationManager =  NotificationManagerCompat.from(this)
            notificationManager.notify(notificationId, mBuilder.build())
        }
    }
}
```

Because there are major changes to push notifications in Android O, we checked for the Android version before handling the notification. If we are using Android O or newer, we have to create a notification channel that will be used to categorize the type of notification we are sending. This is particularly useful for apps that send different types of notifications.

We also made use of some files stored in the `strings.xml` file to describe the notifications channel description and channel name. Add these to the `strings.xml` file:

```
<!-- File: /app/src/main/res/values/strings.xml -->
<string name="channel_name">Crypto</string>
<string name="channel_description">To receive updates about changes in cryptocurrency value</string>
```

Register the service in the `AndroidManifest.xml` file:

```
<application
    >
    [...]
    <service android:name=".NotificationsMessagingService">
        <intent-filter android:priority="1">
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
</application>
```

Now, let’s prepare our layouts. First, we will design the activity’s layout. When creating your app, the `activity_main.xml` file should already be present in the layout folder. Open it and replace with this:

```
<!-- File: ./app/src/main/res/layout/activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/bitcoinValue"
        android:padding="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="1 BTC"
        android:textSize="16sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/etherumValue"
        android:padding="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginStart="8dp"
        android:text="1 ETH"
        android:textSize="16sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/bitcoinValue"/>
</android.support.constraint.ConstraintLayout>
```

The layout contains two `TextView`s to show prices for Bitcoin and Ethereum. We also made these `TextView`s clickable so we can set limits to get notifications when the limits are surpassed.

Next, we will design the layout of our alert dialog. Create a new layout file named `alert_layout` and paste this:

```
<!-- File: ./app/src/main/res/layout/alert_layout.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:padding="20dp"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/minimumValue"
        android:background="@drawable/text_background"
        android:hint="Minimum value"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:inputType="number"
        android:layout_width="match_parent"
        android:layout_height="60dp" />
    <EditText
        android:layout_marginTop="10dp"
        android:background="@drawable/text_background"
        android:hint="Maximum value"
        android:inputType="number"
        android:id="@+id/maximumValue"
        android:layout_width="match_parent"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:layout_height="60dp" />
    <Button
        android:id="@+id/save"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"
        android:text="SAVE"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
```

This will be the layout showed by the dialog. It contains two text fields and a **save** button and we used a custom designed background for the `TextView`s. Create a new drawable file named `text_background` and paste this:

```
<!-- File: /app/src/main/res/drawable/text_background.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <solid android:color="@android:color/white" />
    <stroke android:width="1dip" android:color="@android:color/darker_gray"/>
</shape>
```

We will move to the `MainActivity` to finish up our app’s functionalities. Open your `MainActivity` and replace the contents with the following:

    // File: ./app/src/main/java/{package-name}/MainActivity.Kt
    import android.os.Bundle
    import okhttp3.MediaType
    import okhttp3.RequestBody
    import org.json.JSONObject
    import retrofit2.Call
    import retrofit2.Callback
    import retrofit2.Response
    import android.support.v7.app.AlertDialog
    import android.support.v7.app.AppCompatActivity
    import android.util.Log
    import android.view.LayoutInflater
    import android.widget.Button
    import android.widget.EditText
    import com.pusher.pushnotifications.PushNotifications
    import kotlinx.android.synthetic.main.activity_main.*
    import okhttp3.OkHttpClient
    import retrofit2.Retrofit
    import retrofit2.converter.scalars.ScalarsConverterFactory

    class MainActivity : AppCompatActivity() {

        private var prefs: Prefs? = null
        private val retrofit: ApiService by lazy {
            val httpClient = OkHttpClient.Builder()
            val builder = Retrofit.Builder()
                    .baseUrl("http://10.0.2.2:9000/")
                    .addConverterFactory(ScalarsConverterFactory.create())
            val retrofit = builder
                    .client(httpClient.build())
                    .build()

            retrofit.create(ApiService::class.java)
        }

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            fetchCurrentPrice()
            setupPushNotifications()
            setupClickListeners()
        }
    }

> The `URL` used above, `http://10.0.2.2:9000/`, is the URL the Android emulator recognizes as localhost.

Above, we created a `retrofit` object to be used for network calls. After setting up the `retrofit` object, we add the layout in the `onCreate` method and call three other functions:

1.  `fetchCurrentPrice` - This function will get the current price of Bitcoin and Ethereum from our server. Create a new function within the class and set it up like so:

    // File: /app/src/main/java/{package-name}/MainActivity.kt
    private fun fetchCurrentPrice() {
        retrofit.getValues().enqueue(object: Callback<String> {
            override fun onResponse(call: Call<String>?, response: Response<String>?) {
                val jsonObject = JSONObject(response!!.body())
                bitcoinValue.text = "1 BTC = $"+ jsonObject.getJSONObject("BTC").getString("USD")
                etherumValue.text = "1 ETH = $"+ jsonObject.getJSONObject("ETH").getString("USD")
            }

            override fun onFailure(call: Call<String>?, t: Throwable?) {
                Log.e("MainActivity",t!!.localizedMessage)
            }
        })
    }

Above, a network call is made to get the current Bitcoin and Ethereum prices in USD. When the response is received, we parse the JSON data and display it on the screen by setting the texts of the text views in the layout. 

2.  `setupPushNotifications` - This function is where we start listening to the interest of our choice to receive notifications. The interest name is in this format **{device_uuid}_{currency}_changed**. We register two interests, one for each currency. Open the `MainActivity` class and add the following method:

    // File: /app/src/main/java/{package-name}/MainActivity.Kt
    private fun setupPushNotifications() {
        PushNotifications.start(applicationContext, "PUSHER_BEAMS_INSTANCE_ID")
        val fmt = "%s_%s_changed"
        PushNotifications.subscribe(java.lang.String.format(fmt, deviceUuid(), "BTC"))
        PushNotifications.subscribe(java.lang.String.format(fmt, deviceUuid(), "ETH"))
    }

> Replace `PUSHER_BEAMS_INSTANCE_ID` with the instance ID found on your Pusher Beams dashboard.

3.  `setupClickListeners` - In this function, we will set up click listeners to the text views in our layout. In the same `MainActivity` class, add the following method:

    // File: /app/src/main/java/{package-name}/MainActivity.Kt
    private fun setupClickListeners() {
        bitcoinValue.setOnClickListener {
            createDialog("BTC")
        }

        etherumValue.setOnClickListener {
            createDialog("ETH")
        }
    }

When any of the text views is clicked, we call the `createDialog` method which then opens up a layout for the user to input the limit.

In the `MainActivity` class, add the method `createDialog` and as seen below:

    // File: /app/src/main/java/{package-name}/MainActivity.Kt
    private fun createDialog(source:String){
      val builder: AlertDialog.Builder = AlertDialog.Builder(this)
      val view = LayoutInflater.from(this).inflate(R.layout.alert_layout,null)

      builder.setTitle("Set limits")
          .setMessage("")
          .setView(view)

      val dialog = builder.create()
      val minEditText: EditText = view.findViewById(R.id.minimumValue)
      val maxEditText: EditText = view.findViewById(R.id.maximumValue)

      view.findViewById<Button>(R.id.save).setOnClickListener {
        if (source == "BTC"){
          saveBTCPref(minEditText.text.toString(), maxEditText.text.toString())
        } else {
          saveETHPref(minEditText.text.toString(), maxEditText.text.toString())
        }

        dialog.dismiss()
      }
      dialog.show()
    }

This dialog gets the minimum and maximum values and sends it to the backend server. This is done so that when the cryptocurrency’s price changes, we’ll get a push notification if it is within the limits set. 

In the function above, we called two new methods. Add the two methods in the `MainActivity` class as seen below:

    // File: /app/src/main/java/{package-name}/MainActivity.Kt
    private fun saveBTCPref(min:String, max:String){
        val jsonObject = JSONObject()
        jsonObject.put("minBTC", min)
        jsonObject.put("maxBTC", max)
        jsonObject.put("uuid", deviceUuid())

        val body = RequestBody.create(
                MediaType.parse("application/json"),
                jsonObject.toString()
        )

        retrofit.saveBTCLimit(body).enqueue(object: Callback<String> {
            override fun onResponse(call: Call<String>?, response: Response<String>?) {}
            override fun onFailure(call: Call<String>?, t: Throwable?) {}
        })
    }

    private fun saveETHPref(min:String, max:String){
        val jsonObject = JSONObject()
        jsonObject.put("minETH",min)
        jsonObject.put("maxETH",max)
        jsonObject.put("uuid", deviceUuid())

        val body = RequestBody.create(
                MediaType.parse("application/json"),
                jsonObject.toString()
        )

        retrofit.saveETHLimit(body).enqueue(object: Callback<String> {
            override fun onResponse(call: Call<String>?, response: Response<String>?) {}
            override fun onFailure(call: Call<String>?, t: Throwable?) {}
        })
    }

In the `saveBTCPref` and `saveETHPref` we attempt to send the limits set by the user to the API so it can be saved for that user.

While sending, we also send the `uuid` which is the devices’ unique identifier. Let’s create the `deviceUuid()`method that will generate and save this UUID per device. In the `MainActivity` class, add the following code:

    // File: /app/src/main/java/{package-name}/MainActivity.Kt
    private fun deviceUuid() : String {
        prefs = Prefs(this)
        var uuid: String = prefs!!.deviceUuid

        if (uuid == "") {
            uuid = java.util.UUID.randomUUID().toString().replace("-", "_")
            prefs!!.deviceUuid = uuid
        }

        return uuid
    }


Now in this function, we reference a `Prefs` class. Create a new `Prefs` class and paste the following code into it:

    // File: /app/src/main/java/{package-name}/Prefs.Kt
    import android.content.Context
    import android.content.SharedPreferences

    class Prefs (context: Context) {
        val PREFS_FILENAME = "com.example.coinalert.prefs"
        val DEVICE_UUID = "device_uuid"
        val prefs: SharedPreferences = context.getSharedPreferences(PREFS_FILENAME, 0);
        var deviceUuid: String
            get() = prefs.getString(DEVICE_UUID, "")
            set(value) = prefs.edit().putString(DEVICE_UUID, value).apply()
    }


That’s all for the application. At this point, the application should build successfully, but, not function as intended. In [the next part](https://pusher.com/tutorials/cryptocurrency-kotlin-go-part-2), we will build the backend of the application so it can work as intended.

### Conclusion

In this article, we have learned how to use Pusher Beams to notify users of changes to a cryptocurrency. You can find the repository for the application built in this article [here](https://github.com/neoighodaro/kotlin-cryptocurrency-watcher-with-push-notification).

This post first appeared on the [Pusher Blog](https://pusher.com/tutorials/cryptocurrency-kotlin-go-part-1).