支付宝、微信支付是开发中经常需要用到的功能,那么如何集成支付功能到应用中呢?支付结果亦是异步的,又如何传递结果呢?带着这些疑问让我们一步步走进这学习探索之路。
在这探索之前,想问下看客朋友是否查看过官方的电池状态监控示例。如果还没有的朋友建议先看一下官方的源码!
当你对官方源码都有所了解后,那下面的内容就容易理解多了。一般情况下,原生与Flutter通讯,我们经常使用MethodChannel处理方法调用,有时候需要事件监控,那就需要EventChannel来处理。说到这里,头脑里是否有一个大致流程构思了?!
首先,集成支付SDK,这个就不多说了。
其次,把支付方法封装起来。
最后,把支付方法提供给Flutter调用,事件响应给Flutter。
1.支付宝支付辅助类代码
class AliPayPlugin private constructor() {
companion object {
private var alipay: AliPayPlugin? = null
@JvmStatic
fun getInstance(): AliPayPlugin? {
if (alipay == null) {
synchronized(AliPayPlugin::class.java) {
alipay = AliPayPlugin()
}
}
return alipay
}
}
@Suppress("unchecked_cast")
@SuppressLint("HandlerLeak")
private val mHandler = object : Handler() {
override fun handleMessage(msg: Message) {
with(LocalBroadcastManager.getInstance(GenydfApplication.instance)) {
val intent = Intent().apply {
action = OnlinePayPlugin.ACTION_ONLINE_PAY_RESULT_NOTIFIER
putExtra("payType", "ALIPAY")
}
when (msg.what) {
0x0000A -> with(PayResult(msg.obj as Map)) {
/** 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。 **/
val resultInfo = if (!TextUtils.isEmpty(result)) result else memo// 同步返回需要验证的信息
// 判断resultStatus 为9000则代表支付成功
when {
TextUtils.equals(resultStatus, "9000") -> intent.apply {
putExtra("message", "支付宝支付成功")
putExtra("state", 1)
}
TextUtils.equals(resultStatus, "6001") -> intent.apply {
putExtra("message", "您取消了支付宝支付")
putExtra("state", 0)
}
else -> intent.apply {
putExtra("message", "支付失败,原因:$resultInfo")
putExtra("state", -1)
}
}
}
}
sendBroadcast(intent)
}
}
}
/**
* 支付宝支付业务示例
* @param activity 上下文对象
* @param orderInfo 订单信息,来自服务器
*/
fun startPay(activity: Activity, orderInfo: String): Unit = Thread {
val result = PayTask(activity).payV2(orderInfo, true)
val msg = Message()
msg.what = 0x0000A
msg.obj = result
mHandler.sendMessage(msg)
}.start()
}
/**
* 支付结果实体类
* @param rawResult 支付Map数据结果
*/
class PayResult(rawResult: Map?) {
/**
* @return the resultStatus
*/
var resultStatus: String? = null
private set
/**
* @return the result
*/
var result: String? = null
private set
/**
* @return the memo
*/
var memo: String? = null
private set
init {
rawResult?.let {
for (key in rawResult.keys) {
when {
TextUtils.equals(key, "resultStatus") -> resultStatus = rawResult[key]
TextUtils.equals(key, "result") -> result = rawResult[key]
TextUtils.equals(key, "memo") -> memo = rawResult[key]
}
}
}
}
override fun toString(): String = "resultStatus={$resultStatus};memo={$memo};result={$result}"
}
2.微信支付辅助类代码
/**
* 微信插件
*/
class WechatPlugin private constructor() {
companion object {
private var wechatPlugin: WechatPlugin? = null
@JvmStatic
fun getInstance(): WechatPlugin? {
if (wechatPlugin == null) {
synchronized(WechatPlugin::class.java) {
wechatPlugin = WechatPlugin()
}
}
return wechatPlugin
}
}
private val wxApi: IWXAPI? by lazy {
val api = WXAPIFactory.createWXAPI(GenydfApplication.instance, BuildConfig.WX_APPID, false)
api.registerApp(BuildConfig.WX_APPID)
api
}
/** 微信APP是否已经安装 **/
val isWXAppInstalled: Boolean by lazy { wxApi?.isWXAppInstalled ?: false }
/**
* 发送请求
* @param req 要请求的对象数据
*/
fun sendRequest(req: BaseReq?) = wxApi?.sendReq(req)
/**
* 微信登录
* @param activity 上下文对象
*/
fun login(activity: Activity) {
if (wxApi?.isWXAppInstalled != true) {
Toast.makeText(activity, "您的设备未安装微信,请安装后再登录!", Toast.LENGTH_SHORT).show()
return
}
with(SendAuth.Req()) {
scope = "snsapi_userinfo"
state = "${System.currentTimeMillis()}"
wxApi?.sendReq(this)
}
}
/**
* 回调,需要在WxEntryActivity中调用
* @param intent
* @param handler
*/
fun handleIntent(intent: Intent?, handler: IWXAPIEventHandler) {
wxApi?.handleIntent(intent, handler)
}
}
/** 微信支付 **/
class WechatPayPlugin private constructor() {
companion object {
private var wechatPay: WechatPayPlugin? = null
@JvmStatic
fun getInstance(): WechatPayPlugin? {
if (wechatPay == null) {
synchronized(WechatPayPlugin::class.java) {
wechatPay = WechatPayPlugin()
}
}
return wechatPay
}
}
/**
* 发送支付请求
* @param params 支付请求参数
*/
fun startPay(params: WechatPayParams): Unit = with(PayReq()) {
appId = params.appId
partnerId = params.partnerId
prepayId = params.prepayId
packageValue = params.packageValue
nonceStr = params.nonceStr
timeStamp = params.timeStamp
sign = params.sign
WechatPlugin.getInstance()?.sendRequest(this)
}
}
/**
* 微信支付参数实体类
* @param appId APP-ID
* @param packageValue 包名
* @param partnerId 合作者ID
* @param prepayId 准备的订单ID
* @param sign 签名字符串
* @param nonceStr 随机字符串
* @param timeStamp 时间戳
*/
data class WechatPayParams(
@JvmField
var appId: String? = BuildConfig.WX_APPID,
@JvmField
var packageValue: String? = "Sign=WXPay",
@JvmField
var partnerId: String?,
@JvmField
var prepayId: String?,
@JvmField
var sign: String? = null,
@JvmField
var nonceStr: String? = null,
@JvmField
var timeStamp: String? = null
)
3. 在线支付插件,按照V2版本插件编写的。
下面代码中利用MethodChannel为Flutter提供调用方法,使用EventChannel为支付结果响应事件,其中这里用的是LocalBroadcastManager进行支付结果通知,我们可以把通知的优先级提高一点,防止收到通知太慢的情况发生。
class OnlinePayPlugin : FlutterPlugin, ActivityAware, EventChannel.StreamHandler, MethodChannel.MethodCallHandler {
companion object {
private const val M_NAME = "com.test.trade/online-pay-plugin"
private const val E_NAME = "com.test.trade/online-pay-plugin/pay-result"
/** 在线支付结果通知 **/
const val ACTION_ONLINE_PAY_RESULT_NOTIFIER = "com.test.trade.online_pay.result"
}
private var applicationContext: Context? = null
private var activity: Activity? = null
private var payResultNotifierReceiver: BroadcastReceiver? = null
private var methodChannel: MethodChannel? = null
private var eventChannel: EventChannel? = null
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
onAttachedToEngine(binding.applicationContext, binding.binaryMessenger)
}
private fun onAttachedToEngine(applicationContext: Context, messenger: BinaryMessenger) {
this.applicationContext = applicationContext
methodChannel = MethodChannel(messenger, M_NAME).apply {
setMethodCallHandler(this@OnlinePayPlugin)
}
eventChannel = EventChannel(messenger, E_NAME).apply {
setStreamHandler(this@OnlinePayPlugin)
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
methodChannel?.setMethodCallHandler(null)
methodChannel = null
eventChannel?.setStreamHandler(null)
eventChannel = null
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
onAttachedToActivity(binding.activity)
}
private fun onAttachedToActivity(activity: Activity) {
this.activity = activity
}
override fun onDetachedFromActivity() {}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}
override fun onDetachedFromActivityForConfigChanges() {}
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
payResultNotifierReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == ACTION_ONLINE_PAY_RESULT_NOTIFIER) {
val payType = intent.getStringExtra("payType")
val message = intent.getStringExtra("message")
val state = intent.getIntExtra("state", -1)
events?.success(mapOf(
"type" to payType,
"state" to state,
"description" to message))
}
}
}
if (applicationContext != null && payResultNotifierReceiver != null)
LocalBroadcastManager.getInstance(applicationContext!!).registerReceiver(payResultNotifierReceiver!!,
IntentFilter(ACTION_ONLINE_PAY_RESULT_NOTIFIER))
}
override fun onCancel(arguments: Any?) {
if (applicationContext != null && payResultNotifierReceiver != null)
LocalBroadcastManager.getInstance(applicationContext!!).unregisterReceiver(payResultNotifierReceiver!!)
payResultNotifierReceiver = null
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"startPay" -> startOnlinePay(call, result)
else -> result.notImplemented()
}
}
/**
* 启动在线支付
* @param call 方法Call
*/
private fun startOnlinePay(call: MethodCall, result: MethodChannel.Result) {
when (call.argument("type")) {
"ALIPAY" -> { //支付宝支付
val payOrderInfo = call.argument("payInfo")
if (payOrderInfo.isNullOrEmpty()) {
result.error("ONLINE_PAY_ARGUMENTS_ERROR", "错误:支付参数不能为空", null)
return
}
this.activity?.let { AliPayPlugin.getInstance()?.startPay(it, payOrderInfo) }
result.success(null)
}
"WECHAT_PAY" -> WechatPayPlugin.getInstance()?.startPay( //微信支付
Gson().fromJson(call.argument("payInfo"), WechatPayParams::class.java))
else -> result.error("ONLINE_PAY_TYPE_ERROR", "错误:未知支付类型", null)
}
}
}
微信WXPayEntryActivity .java的处理
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private WechatPlugin wechatPlugin;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wechatPlugin = WechatPlugin.getInstance();
if (wechatPlugin != null)
wechatPlugin.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
if (wechatPlugin == null)
wechatPlugin = WechatPlugin.getInstance();
if (wechatPlugin != null)
wechatPlugin.handleIntent(getIntent(), this);
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
Intent intent = new Intent();
intent.setAction(OnlinePayPlugin.ACTION_ONLINE_PAY_RESULT_NOTIFIER);
intent.putExtra("payType", "WECHAT_PAY");
switch (resp.errCode) {
case 0: //支付成功
intent.putExtra("message", "微信支付成功");
intent.putExtra("state", 1);
break;
case -1: //支付错误
intent.putExtra("message", "微信支付失败, 错误:" + resp.errStr);
intent.putExtra("state", -1);
break;
case -2: //用户取消
intent.putExtra("message", "您已取消微信支付");
intent.putExtra("state", 0);
break;
}
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
finish();
}
}
4.Flutter部分实现,对接MethodChannel和EventChannel,类使用单例模式。
/// 在线支付插件, 单例类
class OnlinePayPlugin {
static const MethodChannel _methodChannel =
const MethodChannel('com.test.trade/online-pay-plugin');
static const EventChannel _eventChannel =
const EventChannel('com.test.trade/online-pay-plugin/pay-result');
static OnlinePayPlugin _instance;
factory OnlinePayPlugin() {
if (_instance == null) _instance = OnlinePayPlugin();
return _instance;
}
Stream _onOnlinePayResultEvent;
/// 开始支付
/// + `info` 支付信息
void startPay(OnlinePayInfo info) => _methodChannel.invokeMethod('startPay', {
'type': info.type == PayType.AliPay ? 'ALIPAY' : 'WECHAT_PAY',
'payInfo': info.payArguments is String
? info.payArguments
: json.encode(info.payArguments)
});
/// 接收支付结果的事件
Stream get onOnlinePayResultEvent {
if (_onOnlinePayResultEvent == null) {
_onOnlinePayResultEvent = _eventChannel
.receiveBroadcastStream()
.map((dynamic data) => OnlinePayResultInfo.fromJson(data));
}
return _onOnlinePayResultEvent;
}
}
/// 支付类型
enum PayType {
///支付宝支付
AliPay,
/// 微信支付
WechatPay
}
///支付信息
class OnlinePayInfo {
/// 支付类型
PayType type;
/// 支付参数
dynamic payArguments;
OnlinePayInfo({@required this.type, @required this.payArguments});
Map toJson() => {
'type': type.toString(),
'payArguments':
payArguments is String ? payArguments : json.encode(payArguments)
};
}
/// 微信支付参数
class WechatPayArgumentsInfo {
/// 应用ID
String appId;
/// 常量值:Sign=WXPay
String packageValue;
/// 合作者ID
String partnerId;
/// 预付订单ID
String prepayId;
/// 签名字符串
String sign;
/// 随机字符串
String nonceStr;
/// 时间戳
String timeStamp;
WechatPayArgumentsInfo();
factory WechatPayArgumentsInfo.fromJson(Map json) =>
WechatPayArgumentsInfo()
..appId = json['appId'] as String
..packageValue = json['packageValue'] as String
..partnerId = json['partnerId'] as String
..prepayId = json['prepayId'] as String
..sign = json['sign'] as String
..nonceStr = json['nonceStr'] as String
..timeStamp = json['timeStamp'] as String;
Map toJson() => {
'appId': appId,
'packageVakue': packageValue,
'partnerId': partnerId,
'prepayId': prepayId,
'sign': sign,
'nonceStr': nonceStr,
'timeStamp': timeStamp
};
}
/// 支付结果状态
enum OnlinePayResultState {
/// 支付成功
Success,
/// 支付失败
Fail,
/// 支付被取消
Cancel
}
/// 在线支付结果信息
class OnlinePayResultInfo {
/// 支付类型
PayType type;
/// 支付状态
OnlinePayResultState state;
/// 支付结果描述
String description;
OnlinePayResultInfo();
factory OnlinePayResultInfo.fromJson(Map json) =>
OnlinePayResultInfo()
..type = json['type'] == 'ALIPAY' ? PayType.AliPay : PayType.WechatPay
..state = json['state'] == 1
? OnlinePayResultState.Success
: (json['state'] == -1
? OnlinePayResultState.Fail
: OnlinePayResultState.Cancel)
..description = json['description'] as String;
Map toJson() => {
'type': type.toString(),
'state': state.toString(),
'description': description
};
}
5.调用测试
void test() async {
await OnlinePayPlugin().startPay(.....);
var result = await OnlinePayPlugin().onOnlinePayResultEvent.single;
debugPrint(result);
}
作者:Cosecant
链接:https://www.jianshu.com/p/d5dc410954e7
来源: