我正在开发一个 Flutter 应用程序,我需要将 PhonePe 支付网关集成到其中。不幸的是,PhonePe 没有可用的官方 Flutter 插件。但是,PhonePe 确实提供了 Android SDK 用于集成其支付网关。
我已经阅读了 PhonePe 文档(下面提供的链接),并且正在寻找有关如何将 PhonePe 支付网关 Android SDK 集成到我的 Flutter 应用程序中的指导。*** 我对涉及编写本机的两种解决方案持开放态度Android 代码和那些不需要本机代码的代码。***
PhonePe 文档:[https://developer.phonepe.com/v1/docs/android-pg-sdk-integration]
理想情况下,我希望找到一个教程或分步说明,以易于遵循的方式解释集成过程。如果现有的 Flutter 插件或包可以简化此集成,请告诉我。
任何帮助、代码片段或对现有资源的引用将不胜感激。谢谢!
我已经使用 WebView 和 Node.js 后端成功实现了 PhonePe 结帐流程来创建结帐链接。但是,我现在需要一个更强大的 UI 来在我的 Flutter 应用程序中显示结帐过程。为了实现这一点,我需要集成PhonePe支付网关Android SDK。
在原生端实现PhonePe支付网关,并从flutter端调用。您将需要方法通道和事件通道,以便它在本机端和 flutter 端之间进行通信。在这里阅读更多内容https://docs.flutter.dev/platform-integration/platform-channels
import 'dart:developer';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});`enter code here`
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _incrementCounter() async {
final data = {
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MU933037302229373",
"amount": 100,
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"deviceContext": {"deviceOS": "ANDROID"},
"paymentInstrument": {
"type": "UPI_INTENT",
"targetApp": "com.phonepe.app",
"accountConstraints": [
{
//Optional. Required only for TPV Flow.
"accountNumber": "420200001892",
"ifsc": "ICIC0000041"
}
]
}
};
final b64 = jsonEncode(data).toBase64;
print(b64);
const saltKey = "099eb0cd-02cf-4e2a-8aca-3e6c6aff0399";
final sha = '$b64/pg/v1/pay$saltKey'.toSha256;
print(sha);
try {
final res = await http.post(
Uri.parse('https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay'),
headers: {
'Content-Type': 'application/json',
'X-VERIFY': '$sha###1',
},
);
print(res.body.toString());
} catch (e) {
log(e.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a specific color (to
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
// change color while the other colors stay the same.
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: test,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void test() async {
const saltKey = "099eb0cd-02cf-4e2a-8aca-3e6c6aff0399";
const saltIndex = 1;
const apiEndpoint = "/pg/v1/pay";
final jsonData = {
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MUID123",
"amount": '100',
"redirectUrl": "https://webhook.site/redirect-url",
"redirectMode": "POST",
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"paymentInstrument": {"type": "PAY_PAGE"}
};
String jsonString = jsonEncode(jsonData);
String base64Data = jsonString.toBase64;
String dataToHash = base64Data + apiEndpoint + saltKey;
String sHA256 = generateSha256Hash(dataToHash);
print(base64Data);
print('#' * 10);
print("$sHA256###$saltIndex");
final response = await http.post(
Uri.parse('https://api-preprod.phonepe.com/apis/pg-sandbox/pg/v1/pay'),
headers: {
"accept": "application/json",
'X-VERIFY': '$sHA256###$saltIndex',
'Content-Type': 'application/json',
},
body: jsonEncode({'request': base64Data}),
);
log(response.body.toString());
}
String generateSha256Hash(String input) {
var bytes = utf8.encode(input);
var digest = sha256.convert(bytes);
return digest.toString();
}
}
/// EncodingExtensions
extension EncodingExtensions on String {
/// To Base64
/// This is used to convert the string to base64
String get toBase64 {
return base64.encode(toUtf8);
}
/// To Utf8
/// This is used to convert the string to utf8
List<int> get toUtf8 {
return utf8.encode(this);
}
/// To Sha256
/// This is used to convert the string to sha256
String get toSha256 {
return sha256.convert(toUtf8).toString();
}
}
https://webhook.site/callback-url 此请求负载中的回调 url 是什么?