设计思路
- 抽象支付接口:在Flutter层创建一个统一的支付接口,定义通用的支付方法,如发起支付、查询支付结果等。这样,Flutter端的业务逻辑无需关心具体平台实现。
- 平台特定实现:
- Android:利用Android的支付SDK(如支付宝SDK、微信支付SDK等),按照其文档要求实现支付流程。处理支付回调并通过MethodChannel将结果返回给Flutter层。
- iOS:使用iOS的支付框架(如Apple Pay或第三方支付SDK),实现支付逻辑。同样通过MethodChannel将支付结果传递给Flutter。
- 用户体验一致性:
- 界面设计:在Flutter层设计统一的支付界面,通过平台适配调整样式,确保在Android和iOS上视觉效果相近。
- 交互流程:保证支付流程的交互逻辑在两个平台上一致,如支付确认、等待支付结果等。
- 安全策略:
- 数据加密:在传输敏感支付信息(如订单金额、用户ID等)时,使用加密算法(如AES)进行加密。
- 签名验证:对支付请求和回调数据进行签名验证,确保数据未被篡改。例如,在Android和iOS端使用平台提供的签名机制结合支付SDK的签名方法。
- 权限管理:在AndroidManifest.xml和Info.plist中配置必要的权限,确保支付功能所需权限正确且最小化。
关键代码实现
- Flutter层:
abstract class PaymentPlugin {
Future<String> startPayment(PaymentRequest request);
}
- **通过MethodChannel调用原生实现**:
class PaymentChannel implements PaymentPlugin {
static const MethodChannel _channel = MethodChannel('payment_channel');
@override
Future<String> startPayment(PaymentRequest request) async {
final Map<String, dynamic> arguments = request.toMap();
return await _channel.invokeMethod('startPayment', arguments);
}
}
- Android层:
public class PaymentPlugin implements FlutterPlugin {
private static final String CHANNEL = "payment_channel";
private MethodChannel methodChannel;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL);
methodChannel.setMethodCallHandler((call, result) -> {
if (call.method.equals("startPayment")) {
handleStartPayment(call, result);
} else {
result.notImplemented();
}
});
}
}
- **实现支付逻辑**:
private void handleStartPayment(MethodCall call, Result result) {
// 解析支付请求参数
Map<String, Object> arguments = call.arguments();
String orderInfo = arguments.get("orderInfo").toString();
// 使用支付宝SDK发起支付
PayTask alipay = new PayTask((Activity) FlutterPluginRegistrar.getRegistrarForPlugin("PaymentPlugin").activity());
String payResult = alipay.payV2(orderInfo, true);
result.success(payResult);
}
- iOS层:
import Flutter
import UIKit
public class PaymentPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "payment_channel", binaryMessenger: registrar.messenger())
let instance = PaymentPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if call.method == "startPayment" {
handleStartPayment(call, result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
}
- **实现支付逻辑**:
private func handleStartPayment(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
guard let arguments = call.arguments as? [String: Any],
let orderInfo = arguments["orderInfo"] as? String else {
result(FlutterError(code: "INVALID_ARGS", message: "Invalid payment arguments", details: nil))
return
}
// 使用第三方支付SDK发起支付
let payResult = PaySDK.pay(orderInfo)
result(payResult)
}
安全策略实现
- 数据加密:
import 'package:encrypt/encrypt.dart';
final key = Key.fromUtf8('your 32 - length encryption key');
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
String encryptData(String data) {
final encrypted = encrypter.encrypt(data, iv: iv);
return encrypted.base64;
}
- **Android层**:使用`javax.crypto`包进行AES加密。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class EncryptionUtil {
private static final String KEY = "your 32 - length encryption key";
private static final String IV = "your 16 - length iv";
public static String encrypt(String data) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES");
IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encrypted = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.encodeToString(encrypted, Base64.DEFAULT);
}
}
- **iOS层**:使用`CryptoSwift`库进行加密。
import CryptoSwift
let key: Array<UInt8> = Array("your 32 - length encryption key".utf8)
let iv: Array<UInt8> = Array("your 16 - length iv".utf8)
func encrypt(data: String) -> String? {
guard let encrypted = try? AES(key: key, blockMode: .cbc, iv: iv).encrypt(data.bytes) else {
return nil
}
return encrypted.toBase64()
}
- 签名验证:
public void handleAliPayCallback(final String payResult) {
Map<String, String> resultMap = AliPaySignature.getResultMap(payResult);
String sign = resultMap.get("sign");
boolean verifyResult = AliPaySignature.rsaCheckV1(resultMap, AlipayConstants.RSA2_PRIVATE, "UTF-8", true);
if (verifyResult) {
// 签名验证成功,处理支付结果
} else {
// 签名验证失败
}
}
- **iOS**:在支付回调中进行签名验证。
func handlePayCallback(_ payResult: String) {
let resultDict = payResult.components(separatedBy: "&").reduce([String: String]()) { (dict, pair) in
let components = pair.components(separatedBy: "=")
var mutableDict = dict
mutableDict[components[0]] = components[1]
return mutableDict
}
let sign = resultDict["sign"]
let verifyResult = PaySDK.verifySignature(resultDict, sign: sign)
if verifyResult {
// 签名验证成功,处理支付结果
} else {
// 签名验证失败
}
}
- 权限管理:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.payment">
<uses - permission android:name="android.permission.INTERNET" />
<!-- 其他必要权限 -->
</manifest>
- **Info.plist**:
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<!-- 其他必要权限 -->
</dict>