0% found this document useful (0 votes)
178 views15 pages

Telebirr Payment Integration Guide

Uploaded by

hirpha02
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
178 views15 pages

Telebirr Payment Integration Guide

Uploaded by

hirpha02
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Telebirr Payment Integration Guide

Base URL for Telebirr API

Base URL:​
[Link]

Implementation Overview
1. Backend Implementation

Ensure that the backend API endpoints are set up to initialize Telebirr payments and validate
transactions.

2. Mobile App Implementation(Andriod)


2.1 Download the SDK
●​ Test SDK:
[Link]
=sharing
●​ Production SDK:
[Link]
sharing

2.2 Add SDK to the Project


●​ Place the downloaded SDK file ([Link]) inside the
libs folder at the app level in the Android project.
2.3 Add ProGuard Rules
●​ Create a file named [Link] under the app directory and add the following content:

# Keep all classes within the package for Huawei Ethiopia Pay SDK
-keep class [Link].** { *; }

2.4 Update Dependencies


●​ Add the SDK dependency to the [Link] file (app level):
implementation files('libs/[Link]')

2.5 Implement Native Code in [Link]

package your_app_package_id

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

import [Link];
import [Link];

class MainActivity : FlutterFragmentActivity() { // Changed to FlutterFragmentActivity


private val CHANNEL = "telebirr"

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {


[Link](flutterEngine)

// MethodChannel setup for communication with Flutter


MethodChannel([Link], CHANNEL).setMethodCallHandler { call, result ->
if ([Link] == "nativeFunction") {
val appid = [Link]<String>("appid")
val merchCode = [Link]<String>("merch_code")
val prepayId = [Link]<String>("prepay_id")
val timestamp = [Link]<String>("timestamp")
val amount = [Link]<String>("amount")
Log.d("merchCode", merchCode ?: "merchCode is null")
initiateTelebirrPayment(result, appid, merchCode, prepayId, timestamp, amount)
}
else {
[Link]()

}
}
}

private fun initiateTelebirrPayment(result: [Link], appid: String?, merchCode: String?, prepayId: String?,
timestamp: String?, amount: String?) {
val BUYGOODS = "Virtual Equb"
val shortCode = merchCode // Replace with your actual short code
val amount = amount // Replace with the amount
// val amount = "1" // Replace with the amount
val prepayId = prepayId // Replace with your prepay_id
val timestamp = timestamp // Replace with the actual timestamp

val receiveCode = "TELEBIRR$$BUYGOODS$$shortCode$$amount$$prepayId$$timestamp"


Log.d("Telebirr", receiveCode)
val payInfo = [Link]()
.setAppId(appid)
.setShortCode(shortCode)
.setReceiveCode(receiveCode)
// .setReturnApp("[Link]")
.build();
[Link]().pay(this, payInfo)
Log.d("Telebirr","...........")

// Set the callback to handle payment results


[Link]().setPayCallback { code, errMsg ->
Log.d("Telebirr from call back", "onPayCallback: code $code errMsg $errMsg")
[Link](this@MainActivity, "$code $errMsg", Toast.LENGTH_SHORT).show()} }
}
2.6 Invoke Native Code from Flutter
1.​ Define a MethodChannel:
static const platform = MethodChannel('telebirr');

2.​ Create a Function to Invoke the Native Method:


Future<String> invokeNativeMethod(Map<String, dynamic> responseMap) async {
try {
final String result =
await [Link]('nativeFunction', responseMap);
return result;
} on PlatformException catch (e) {
return "Failed to invoke native code: ${[Link]}";
}
}

3.​ Backend Integration in Flutter

Create a function to initialize the payment by hitting the backend:

Future<Result> paymentInitializes(String workOrderId, String amount) async {


return _handlePaymentInitialization(
workOrderId,
amount,
[Link](workOrderId),
);
}

Future<Result> _handlePaymentInitialization(
String workOrderId, String amount, Uri endpoint) async {
try {
final response = await httpClient
.post(
endpoint,
headers: [Link](),
body: jsonEncode({"title": "Telebirr Payment", "amount": amount}),
)
.timeout(_timeoutDuration);

if ([Link] == 200) {
final responseData = [Link]([Link]);
if (responseData['code'] == 500) {
throw Exception(responseData['message']);
}
final telebirrResponse =
[Link](responseData['data']);
final responseMap = {
...[Link](),
"amount": amount,
};
SharedPreferences prefs = await [Link]();
[Link]("merchOrderId", [Link]);
// [Link]("transactionNo", [Link]);
await invokeNativeMethod(responseMap);

return Result(responseData['code'].toString(), true,


responseData['message'] ?? "Success");
}

_handleErrorResponse(response);
throw Exception("Unknown error occurred");
} on SocketException catch (error) {
_handleSocketException(error);
rethrow;
}
}

4.​ Verify Payment Status


Future<bool> checkStatus(String transactionNo) async {
try {
final url = [Link](transactionNo);
final response = await httpClient
.get(
url,
headers: [Link](),
)
.timeout(_timeoutDuration);
if ([Link] == 200) {
TransactionResponse transactionResponse =
[Link]([Link]([Link]));
final isPaid = [Link]?.status == "paid";

if (!isPaid && _retryCount < _maxRetries) {


_retryCount++;
await [Link](const Duration(seconds: 2));
return checkStatus(transactionNo);
}
_retryCount = 0;
return isPaid;
}

_handleErrorResponse(response);
return false;
} catch (e) {
_retryCount = 0;
rethrow;
}
}

5.​ Handle App Lifecycle Changes

Use AppLifecycleState to check transaction status when the app resumes:


@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
[Link](state);
if (state == [Link]) {
SharedPreferences prefs = await [Link]();
if ([Link]("merchOrderId") != null) {
[Link]<PaymentBloc>(context).add(PaymentCheckStatus(
transactionNo: [Link]("merchOrderId") ?? "",
));
}
}
}

6.​ Listen to bloc and show message

BlocConsumer<PaymentBloc, PaymentState>(
listener: (context, state) async {
if (state is PaymentPaidSuccess) {
[Link]("Payment Successfully Paid");
SharedPreferences prefs =
await [Link]();
[Link]("merchOrderId");
[Link](context);
}
3. Mobile App Implementation(Ios with Flutter)

Quick Steps:

1.​ Download and Add the SDK


○​ Download the [Link] file from this link:
[Link]
○​ Copy it into your project's ios folder as shown in the diagram.

2.​ Import the SDK


●​ Open the Runner-Bridging-Header.h file under the Runner folder.
●​ Add the following line to import the SDK:​
#import "EthiopiaPaySDK/EthiopiaPayManager.h"​
3.​ Modify [Link]
1.​ Open the [Link] file and update it as follows:
○​ Import necessary modules:

import UIKit

import Flutter

○​ Make the AppDelegate class conform to the EthiopiaPayManagerDelegate protocol:

@main

@objc class AppDelegate: FlutterAppDelegate, EthiopiaPayManagerDelegate {

2.​ Handle Flutter Native Method Calls

Add a FlutterMethodChannel in didFinishLaunchingWithOptions:


let controller = window?.rootViewController as! FlutterViewController

let telebirrChannel = FlutterMethodChannel(name: "telebirr", binaryMessenger: [Link])

[Link] { [weak self] (call: FlutterMethodCall, result: @escaping


FlutterResult) in

if [Link] == "nativeFunction" {

guard let arguments = [Link] as? [String: Any],

let appId = arguments["appid"] as? String,

let shortCode = arguments["merch_code"] as? String,

let prepayId = arguments["prepay_id"] as? String,

let amount = arguments["amount"] as? String else {

print("Received call from flutter: \([Link] )")

result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing or invalid arguments",


details: nil))

return

print("Received arguments: appId=\(appId), shortCode=\(shortCode), prepayId=\(prepayId),


amount=\(amount)")

self?.initiatePayment(appId: appId, shortCode: shortCode, prepayId: prepayId, amount: amount)

result("Payment initiated")

} else {

result(FlutterMethodNotImplemented)
}

3. Open URL Handling

Add the following method to handle URL responses:

override func application(

_ app: UIApplication,

open url: URL,

options: [[Link] : Any] = [:]

) -> Bool {

[Link]().handleOpen(url)

return true

4. Initiate Payment Function

Add a function to process payments:

func initiatePayment(appId: String, shortCode: String, prepayId: String, amount: String) {

do {

print("initiatePayment: \(appId) \(shortCode) \(prepayId) \(amount)")

let timestamp = getCurrentTimestampString()

let receiveCode = "TELEBIRR$BUYGOOD$\(shortCode)$\(amount)$\(prepayId)$\(timestamp)"

let manager = [Link]()

[Link] = self

[Link](withAppId: appId, shortCode: shortCode, receiveCode: receiveCode, returnAppScheme: "PSTS")


print("Payment initiated")

} catch {

print("Error: \(error)")

5. Helper Function for Timestamp

Add a helper method to generate the current timestamp:

func getCurrentTimestampString() -> String {

let currentDate = Date()

let formatter = DateFormatter()

[Link] = "yyyyMMddHHmmss"

return [Link](from: currentDate)

6. Handle Payment Results

Implement the delegate method to handle the payment response:

// EthiopiaPayManagerDelegate method

func payResultCallback(withCode code: Int, msg: String) {

// Handle the payment result

The full code of [Link] is here


import UIKit
import Flutter

@main
@objc class AppDelegate: FlutterAppDelegate, EthiopiaPayManagerDelegate {

override func application(


_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [[Link]: Any]?
) -> Bool {
[Link](with: self)

let controller = window?.rootViewController as! FlutterViewController


let telebirrChannel = FlutterMethodChannel(name: "telebirr", binaryMessenger: [Link])

[Link] { [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) in


if [Link] == "nativeFunction" {

guard let arguments = [Link] as? [String: Any],

let appId = arguments["appid"] as? String,


let shortCode = arguments["merch_code"] as? String,
let prepayId = arguments["prepay_id"] as? String,
let amount = arguments["amount"] as? String else {
print("Received call from flutter: \([Link] )")
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing or invalid arguments", details: nil))
return
}

print("Received arguments: appId=\(appId), shortCode=\(shortCode), prepayId=\(prepayId), amount=\(amount)")

self?.initiatePayment(appId: appId, shortCode: shortCode, prepayId: prepayId, amount: amount)


result("Payment initiated")
} else {
result(FlutterMethodNotImplemented)
}
}

return [Link](application, didFinishLaunchingWithOptions: launchOptions)


}
override func application(
_ app: UIApplication,
open url: URL,
options: [[Link] : Any] = [:]
) -> Bool {
[Link]().handleOpen(url)
return true
}

func initiatePayment(appId: String, shortCode: String, prepayId: String, amount: String) {


do {
print("initiatePayment: \(appId) \(shortCode) \(prepayId) \(amount)")
let timestamp = getCurrentTimestampString()
let receiveCode = "TELEBIRR$BUYGOOD$\(shortCode)$\(amount)$\(prepayId)$\(timestamp)"

let manager = [Link]()


[Link] = self

[Link](withAppId: appId, shortCode: shortCode, receiveCode: receiveCode, returnAppScheme: "PSTS")


print("Payment initiated")
} catch {
print("Error: \(error)")
}

func getCurrentTimestampString() -> String {


let currentDate = Date()
let formatter = DateFormatter()
[Link] = "yyyyMMddHHmmss"
return [Link](from: currentDate)
}

// EthiopiaPayManagerDelegate method
func payResultCallback(withCode code: Int, msg: String) {
// Handle the payment result
}
}

Then configure Xcode


Configure URL Schemes in Xcode
1.​ Queried URL Schemes
●​ Go to Targets > Info tab.
●​ Add a Queried URL Schemes entry with values like telebirrcustomerApp.
2.​ Define URL Schemes
●​ Add the URL Types in the Info tab:
○​ Set the URL scheme to your desired string (e.g., vims).
●​ Alternatively, update the [Link]:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>vims</string>
</array>
</dict>
</array>

3.​ Application Query Schemes


●​ Add supported schemes to LSApplicationQueriesSchemes in [Link]:

<key>LSApplicationQueriesSchemes</key>
<array>
<string>telebirrcustomerApp</string>
</array>
Final Step

You can now call the native code from Flutter using the telebirr channel as implemented in the
[Link]. This approach integrates the EthiopiaPaySDK and allows the app to handle
payment flows seamlessly.

You might also like