Android Mpesa Integration using Daraja Library (Part 2)
This is a continuation from the last part. Today we are going to download and install Node, Firebase CLI and implement Mpesa Callback.
First things first head to Node Website and download the latest version.
After install to make sure that it was installed perfectly open terminal or command prompt and run this
npm
if you get a message that npm isn't recognized(for windows) then you didn't install properly, try again.
If everything is okay run this command to install firebase CLI
npm install -g firebase tools
It will take some time, after installation we can now login to our firebase by running, it doesn't matter any directory for now.
firebase login
After that now let's connect our project to firebase. I hope you all know how to connect to Firebase if you don't pause right there and have a look, continue after connecting your app to firebase because next part depends on it.
After successfully connecting the app to the Firebase, go back to Android studio add paste the following in your buid.gradle
implementation 'com.google.firebase:firebase-functions:19.0.2'
implementation 'com.google.firebase:firebase-messaging:20.2.0'
implementation 'com.google.firebase:firebase-database:19.3.0'
implementation 'com.google.firebase:firebase-core:17.4.3'
implementation 'com.google.code.gson:gson:2.8.6'
Sync the Gradle then navigate at the bottom and open the terminal and run
firebase init functions
Type ‘Y’ if you are asked if you are ready to proceed, then click on ‘Choose an existing project’ and choose the project you just connected your app with.
Next, select Javascript if you are prompted to choose language, then if you see this, “Do you want to use ESLint to catch probable bugs and enforce style?” type a big N. It will complicate things. The last one type ‘Y’ if asked about dependencies. Wait for it to initialize. If everything went well you should see “Initialization Complete”.
Now lets open project View in our project
Expand then navigate to functions then package.json file. Read through it and check where its written “Engine” change it from 8 to 10
Go back to Functions folder, right-click and select open in the terminal and run
npm install express body-parser -S
Now we are set just two more steps. Go back to functions folder and open index.js, delete everything and paste the following.
let functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const express = require('express');
const bodyParser = require('body-parser');
//Initialize our web App
const app = express();
app.use(bodyParser.json());
app.disable('x-powered-by');
//This is our actual callback url `Format will be www.example.com/api/myCallbackUrl`
app.post('/myCallbackUrl', (req, res) => {
let response = {
"ResultCode": 0,
"ResultDesc": "Success"
}
//Send response back to safaricom that payload has been received successfully
res.status(200).json(response);
//Then handle data through above received payload as per your app logic.
let body = req.body;
let payload = JSON.stringify(body)
console.log(payload)
let id = body.Body.stkCallback.CheckoutRequestID
const payloadSend = {
data: {
payload,
},
topic: id
};
return admin.messaging().send(payloadSend).catch(error=>{
console.error(error)
})
})
exports.api = functions.https.onRequest(app);
Clear everything on Terminal and open terminal again, this time we are going to deploy our function by running
firebase deploy --only functions
If everything goes as planned you should see “Deploy Complete”
Now let's go to firebase and open Functions. Copy the function URL. That will our callback URL
Go back to Android studio, paste the URL in the callback URL place and append “/myCallbackUrl” like this
Now that we have added the Callback URL we need to add Firebase Cloud messaging. This will receive the data sent from the function. In MainActivity scroll down to
And add this
FirebaseMessaging.getInstance()
.subscribeToTopic(lnmResult.CheckoutRequestID.toString())
This will allow the firebase to subscribe to the topic which the function will send data to.
Now I want you to add the following class like this
Body
data class Body(
val stkCallback: StkCallback
)
Item
data class Item(
val Name: String,
val Value: String
)
CallBackMetaData
data class CallbackMetadata(
val Item: List<Item>
)
MpesaResponse
data class MpesaResponse(
val Body: Body
)
StkCallBack
data class StkCallback(
val CallbackMetadata: CallbackMetadata,
val CheckoutRequestID: String,
val MerchantRequestID: String,
val ResultCode: Int,
val ResultDesc: String
)
MpesaListener
interface MpesaListener {
fun sendSuccesfull(amount: String, phone: String, date: String, receipt: String)
fun sendFailed(reason: String)
}
Now, let MainActivity Implements Mpesalistener
Add-in MainActivity
companion object {
lateinit var mpesaListener: MpesaListener
}
and its On create method have this,
mpesaListener = this
Inside sendSuccesfull override function have this,
runOnUiThread {
Toast.makeText(
this, "Payment Succesfull\n" +
"Receipt: $receipt\n" +
"Date: $date\n" +
"Phone: $phone\n" +
"Amount: $amount", Toast.LENGTH_LONG
).show()
}
Inside sendFail override function have have this
runOnUiThread {
Toast.makeText(
this, "Payment Failed\n" +
"Reason: $reason"
, Toast.LENGTH_LONG
).show()
}
Now lets Implement FirebaseMessaging by having this class
import android.util.Log
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.google.gson.Gson
class FirebaseMessagingService :
FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
Log.d("MessagingService", remoteMessage.data.toString())
val payload = remoteMessage.data["payload"]
val gson = Gson()
val mpesaResponse = gson.fromJson(payload, MpesaResponse::class.java)
Log.d("MessagingServiceSecond", mpesaResponse.toString())
var id = mpesaResponse.Body.stkCallback.CheckoutRequestID
if (mpesaResponse.Body.stkCallback.ResultCode != 0) {
var reason = mpesaResponse.Body.stkCallback.ResultDesc
MainActivity.mpesaListener.sendFailed(reason)
Log.d("MessagingServiceThird", "Operation Failed")
} else {
Log.d("MessagingServiceThird", "Operation Success")
val list = mpesaResponse.Body.stkCallback.CallbackMetadata.Item
var receipt = ""
var date = ""
var phone = ""
var amount = ""
for (item in list) {
if (item.Name == "MpesaReceiptNumber") {
receipt = item.Value
}
if (item.Name == "TransactionDate") {
date = item.Value
}
if (item.Name == "PhoneNumber") {
phone = item.Value
}
if (item.Name == "Amount") {
amount = item.Value
}
}
MainActivity.mpesaListener.sendSuccesfull(amount, phone, date, receipt)
Log.d("MetaData", "\nReceipt: $receipt\nDate: $date\nPhone: $phone\nAmount: $amount")
//Log.d("NewDate", getDate(date.toLong()))
}
FirebaseMessaging.getInstance()
.unsubscribeFromTopic(id)
}
override fun onNewToken(token: String) {
super.onNewToken(token)
}
}
Before running your app go to Manifest inside application and register service
<service
android:name=".FirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Run your app and try sending, you should be able to see the following.
Thanks all, if you have any question you can get me on Twitter @Ronnieonly. Stay tuned for next Part on how to apply for production credentials. Thanks!
Entire Repo https://github.com/ronnieotieno/Lipa-na-Mpesa-Express-using-Daraja-Library-for-Android