Midtrans
memungkinkan menerima pembayaran online secara asli di aplikasi mobile, midtrans dapat digunakan di berbagai platform, sistem midtrans kopatible dengan berbagai API
dan plug-in
untuk proses integrasi yang mudah, jadi dengan menggunakan midtrans anda tidak perlu lagi cek pembayaran dan buat laporan keuangan secara manual, dengan midtrans tersedia 20 metode pebayaran, anda bisa melayani kebutuhan pelanggan diseluruh daerah indonesia.
Transaksi flow
- Checkout: Pelanggan mengklik tombol Checkout pada aplikasi Host dan aplikasi membuat permintaan ke Merchant Server
- Token request: Merchant Server membuat permintaan ke server Midtrans dengan Informasi Pemesanan.
- Token response: Midtrans merespons dengan token transaksi yang valid ke server Merchant
- Token response: Server pedagang meneruskan token ke Mobile SDK
- Get transaction options: SDK Seluler meminta informasi pembayaran / pedagang berdasarkan token
- Transaction options response: SDK Seluler membuat opsi pembayaran dan informasi pembayaran untuk melakukan pembayaran
- Pay: Pelanggan memilih metode pembayaran dan rincian pembayaran dan mengklik “Bayar”
- Charge: SDK Seluler mengirimkan permintaan Tagihan ke Midtrans Backend untuk Pemrosesan pembayaran.
- Charge response: SDK Seluler menerima respons dari Midtrans Backend dan memicu pengendali pada Aplikasi Seluler dengan status berhasil / gagal / tertunda
- Charge notification: Midtrans Backend mengirimkan pemberitahuan ke Merchant backend yang mengkonfirmasi penyelesaian transaksi.
Server Side
Bagian variable server_key
anda masukan server key yang anda dapat dari Midtrans
<?php
$server_key = "YOUR_SERVER_KEY";
$is_production = false;
$api_url = $is_production ?
'https://app.midtrans.com/snap/v1/transactions' :
'https://app.sandbox.midtrans.com/snap/v1/transactions';
if( !strpos($_SERVER['REQUEST_URI'], '/charge') ) {
http_response_code(404);
echo "wrong path, make sure it's `/charge`"; exit();
}
if( $_SERVER['REQUEST_METHOD'] !== 'POST'){
http_response_code(404);
echo "Page not found or wrong HTTP request method is used"; exit();
}
$request_body = file_get_contents('php://input');
header('Content-Type: application/json');
$charge_result = chargeAPI($api_url, $server_key, $request_body);
http_response_code($charge_result['http_code']);
echo $charge_result['body'];
function chargeAPI($api_url, $server_key, $request_body){
$ch = curl_init();
$curl_options = array(
CURLOPT_URL => $api_url,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => 1,
CURLOPT_HEADER => 0,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Accept: application/json',
'Authorization: Basic ' . base64_encode($server_key . ':')
),
CURLOPT_POSTFIELDS => $request_body
);
curl_setopt_array($ch, $curl_options);
$result = array(
'body' => curl_exec($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
);
return $result;
}
Jalankan code diatas menggunakan Heroku, kemudian anda copy URL
untuk diterapkan pada client side bagian mobile.
Client Side
Bagian gradle
anda masukan repositories
allprojects {
repositories {
...
maven { url "http://dl.bintray.com/pt-midtrans/maven" }
}
}
Buat project baru kemudian bagian dependencies
anda masukan 2 environment, mode sanbox
dan mode production
sandboxImplementation 'com.midtrans:uikit:1.21.2-SANDBOX'
productionImplementation 'com.midtrans:uikit:1.21.2'
Anda buatkan varian dengan productFlavors
productFlavors {
// mode pengembang
sandbox {
dimension = "mode"
applicationId "com.kodetr.kodetr_app.sandbox"
resValue "string", "app_name", "Kiostr SandBox"
buildConfigField "String", "MERCHANT_BASE_URL", "YOUR_URL_SERVER"
buildConfigField "String", "MERCHANT_CLIENT_KEY", "YOUR_CLIENT_KEY"
}
// mode produksi
production {
dimension = "mode"
applicationId "com.kodetr.kodetr_app"
resValue "string", "app_name", "Kiostr Production"
buildConfigField "String", "MERCHANT_BASE_URL", "YOUR_URL_SERVER"
buildConfigField "String", "MERCHANT_CLIENT_KEY", "YOUR_CLIENT_KEY"
}
}
Class Product
Selanjutnya Anda buat class model sebagai penampung dari data product
class Product{
String name, image;
int price;
bool userLiked;
double discount;
Product({
this.name,
this.price,
this.discount,
this.image,
this.userLiked
});
}
Class Items
Menampilkan hasil dari data item yang di tampung pada data list
import 'package:flutter/material.dart';
import './Product.dart';
import '../shared/colors.dart';
import '../shared/styles.dart';
Widget productItem(Product product,
{double imgWidth, onLike, onTapped, bool isProductPage = false}) {
return Container(
width: 180,
height: 200,
margin: EdgeInsets.only(left: 20, bottom: 30),
child: Stack(
children: <Widget>[
Container(
width: 180,
height: 300,
child: RaisedButton(
color: white,
elevation: (isProductPage) ? 20 : 12,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: onTapped,
child: Hero(
transitionOnUserGestures: true,
tag: product.name,
child: Image.asset(product.image,
width: (imgWidth != null) ? imgWidth : 100)))),
Positioned(
bottom: 10,
left: 10,
child: (!isProductPage)
? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(product.name, style: nameText),
Text("Rp "+product.price.toString(), style: priceText),
],
)
: Text(' '),
),
Positioned(
top: 10,
left: 10,
child: (product.discount != null)
? Container(
padding:
EdgeInsets.only(top: 5, left: 10, right: 10, bottom: 5),
decoration: BoxDecoration(
color: Colors.red[600],
borderRadius: BorderRadius.circular(50)),
child: Text(product.discount.toString() + '%',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.w700)),
)
: SizedBox(width: 0))
],
),
);
}
Class HomePage
Merupakan bagian dari menu utama dan sekaligus menampilkan berupa data dari list Computers dan list dari data handphones
import 'package:flutter/material.dart';
import '../shared/styles.dart';
import '../shared/colors.dart';
import '../shared/fryo_icons.dart';
import './ProductPage.dart';
import './Product.dart';
import './Items.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
final _tabs = [
storeTab(context),
Text('Feed'),
Text('Keranjang'),
Text('Akun'),
];
return Scaffold(
backgroundColor: bgColor,
appBar: AppBar(
centerTitle: true,
elevation: 0,
backgroundColor: primaryColor,
title:
Text('KiosTR', style: logoWhiteStyle, textAlign: TextAlign.center),
actions: <Widget>[
IconButton(
padding: EdgeInsets.all(0),
onPressed: () {},
iconSize: 21,
icon: Icon(Fryo.heart_1),
),
IconButton(
padding: EdgeInsets.all(0),
onPressed: () {},
iconSize: 21,
icon: Icon(Fryo.alarm),
)
],
),
body: _tabs[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Fryo.home),
title: Text(
'Home',
style: tabLinkStyle,
)),
BottomNavigationBarItem(
icon: Icon(Fryo.bookmark),
title: Text(
'Feed',
style: tabLinkStyle,
)),
BottomNavigationBarItem(
icon: Icon(Fryo.cart),
title: Text(
'Keranjang',
style: tabLinkStyle,
)),
BottomNavigationBarItem(
icon: Icon(Fryo.smile),
title: Text(
'Akun',
style: tabLinkStyle,
))
],
currentIndex: _selectedIndex,
type: BottomNavigationBarType.fixed,
fixedColor: Color(0xff597de9),
onTap: _onItemTapped,
));
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
Widget storeTab(BuildContext context) {
// will pick it up from here
// am to start another template
List<Product> computers = [
Product(
name: "ASUS Laptop E402WA",
image: "images/5.png",
price: 10000,
userLiked: true,
discount: 30),
Product(
name: "MacBook Pro",
image: "images/6.jpg",
price: 20000,
userLiked: false,
discount: 20),
Product(
name: "Acer Aspire E5575",
image: 'images/7.jpeg',
price: 7000,
userLiked: false,
),
Product(
name: "Alienware",
image: "images/8.jpeg",
price: 20000,
userLiked: true,
discount: 10)
];
List<Product> handphones = [
Product(
name: "SAMSUNG Galaxy A30",
image: "images/1.png",
price: 10000,
userLiked: true,
discount: 5),
Product(
name: "Hp Oppo A39",
image: "images/2.jpeg",
price: 3000,
userLiked: false,
discount: 30),
Product(
name: "Iphone 11 Pro",
image: "images/3.jpeg",
price: 20000,
userLiked: false),
Product(
name: "Vivo Y91C",
image: "images/4.jpeg",
price: 5000,
userLiked: true,
discount: 20)
];
return ListView(children: <Widget>[
deals('Komputer', onViewMore: () {}, items: <Widget>[
productItem(computers[0], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: computers[0],
);
},
),
);
}, onLike: () {}),
productItem(computers[1], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: computers[1],
);
},
),
);
}, imgWidth: 250, onLike: () {
}),
productItem(computers[2], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: computers[2],
);
},
),
);
}, imgWidth: 200, onLike: () {
}),
productItem(computers[3], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: computers[3],
);
},
),
);
}, onLike: () {
}),
]),
deals('Handphone', onViewMore: () {}, items: <Widget>[
productItem(handphones[0], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: handphones[0],
);
},
),
);
}, onLike: () {}, imgWidth: 60),
productItem(handphones[1], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: handphones[1],
);
},
),
);
}, onLike: () {}, imgWidth: 75),
productItem(handphones[2], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: handphones[2],
);
},
),
);
}, imgWidth: 110, onLike: () {}),
productItem(handphones[3], onTapped: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new ProductPage(
productData: handphones[3],
);
},
),
);
}, onLike: () {}),
])
]);
}
Widget sectionHeader(String headerTitle, {onViewMore}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 15, top: 10),
child: Text(headerTitle, style: h4),
),
Container(
margin: EdgeInsets.only(left: 15, top: 2),
child: FlatButton(
onPressed: onViewMore,
child: Text('Lihat Semua ›', style: contrastText),
),
)
],
);
}
Widget headerCategoryItem(String name, IconData icon, {onPressed}) {
return Container(
margin: EdgeInsets.only(left: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 10),
width: 86,
height: 86,
child: FloatingActionButton(
shape: CircleBorder(),
heroTag: name,
onPressed: onPressed,
backgroundColor: white,
child: Icon(icon, size: 35, color: Colors.black87),
)),
Text(name + ' ›', style: categoryText)
],
),
);
}
Widget deals(String dealTitle, {onViewMore, List<Widget> items}) {
return Container(
margin: EdgeInsets.only(top: 5),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
sectionHeader(dealTitle, onViewMore: onViewMore),
SizedBox(
height: 250,
child: ListView(
scrollDirection: Axis.horizontal,
children: (items != null)
? items
: <Widget>[
Container(
margin: EdgeInsets.only(left: 15),
child: Text('Tidak ada item tersedia',
style: taglineText),
)
],
),
)
],
),
);
}
Gambar dibawah menunjukan hasil output dari code dart
diatas
Class ProductPage
Menampilkan hasil detail peritem dari produk yang dipilih dari list data, sekaligus melakukan pembayaran dengan menggunakan payment gateway
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import './Product.dart';
import '../shared/styles.dart';
import '../shared/colors.dart';
import './Items.dart';
import '../shared/buttons.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
const CHANNEL = "com.kodetr.kodetr_app.channel";
const KEY_NATIVE = "showPaymentGateway";
class ProductPage extends StatefulWidget {
final String pageTitle;
final Product productData;
ProductPage({Key key, this.pageTitle, this.productData}) : super(key: key);
@override
_ProductPageState createState() => _ProductPageState();
}
class _ProductPageState extends State<ProductPage> {
static const platform = const MethodChannel(CHANNEL);
double _rating = 4;
int _quantity = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bgColor,
appBar: AppBar(
elevation: 0,
backgroundColor: bgColor,
centerTitle: true,
leading: BackButton(
color: darkText,
),
title: Text(widget.productData.name, style: h4),
),
body: ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20),
child: Center(
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
padding: EdgeInsets.only(top: 100, bottom: 50),
width: MediaQuery.of(context).size.width * 0.85,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(widget.productData.name, style: h5),
Text("Rp "+widget.productData.price.toString(), style: h3),
Container(
margin: EdgeInsets.only(top: 5, bottom: 20),
child: SmoothStarRating(
allowHalfRating: false,
onRatingChanged: (v) {
setState(() {
_rating = v;
});
},
starCount: 5,
rating: _rating,
size: 27.0,
color: Colors.orange,
borderColor: Colors.orange,
),
),
Container(
margin: EdgeInsets.only(top: 10, bottom: 25),
child: Column(
children: <Widget>[
Container(
child: Text('Jumlah', style: h6),
margin: EdgeInsets.only(bottom: 15),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 55,
height: 55,
child: OutlineButton(
onPressed: () {
setState(() {
_quantity += 1;
});
},
child: Icon(Icons.add),
),
),
Container(
margin:
EdgeInsets.only(left: 20, right: 20),
child: Text(_quantity.toString(), style: h3),
),
Container(
width: 55,
height: 55,
child: OutlineButton(
onPressed: () {
setState(() {
if(_quantity == 1) return;
_quantity -= 1;
});
},
child: Icon(Icons.remove),
),
)
],
)
],
),
),
Container(
width: 180,
child: froyoOutlineBtn('Beli', () {
_showNativeView();
}),
)
],
),
decoration: BoxDecoration(
color: white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
blurRadius: 15,
spreadRadius: 5,
color: Color.fromRGBO(0, 0, 0, .05))
]),
),
),
Align(
alignment: Alignment.center,
child: SizedBox(
width: 200,
height: 160,
child: productItem(widget.productData,
isProductPage: true,
onTapped: () {},
imgWidth: 250,
onLike: () {}),
),
)
],
),
),
)
],
));
}
Future<Null> _showNativeView() async {
await platform.invokeMethod(KEY_NATIVE, {
"name": widget.productData.name,
"price": widget.productData.price,
"quantity": _quantity,
});
}
}
Gambar dibawah menunjukan hasil output dari code dart
diatas
Resource
Jika anda sudah mengikuti artikel ini sesuai intruksi dari vidio maka anda berhasil membuat aplikasi payment gateway
menggunakan `midtrans.
Demikian yang dapat saya sampaikan dari artikel ini semoga bermanfaat, jika ada yang ditanyakan silahkan di kolom komentar dibawah, selamat mencoba.