如何在Flutter应用中调用Android原生BenefitInAppButtonListener
问题背景
我需要在Flutter应用中集成一款自定义Android SDK,该SDK包含BenefitInAppButtonListener监听器及相关支付功能,但在Flutter环境下遇到了监听器回调失效的问题。
常规Android原生用法
在Android原生项目中,通常通过给BenefitInAppButton设置监听器来触发支付流程,点击按钮后会自动调用onButtonClicked(),并在该方法中初始化BenefitInAppCheckout,交易结果通过传入的CheckoutListener回调:
checkoutBtn.setListener(object : BenefitInAppButtonListener { override fun onButtonClicked() { val benefitInAppCheckout = BenefitInAppCheckout.newInstance( this@MainActivity, ...., ...., ...., (object : CheckoutListener{ override fun onTransactionSuccess(p0: Transaction?) { Toast.makeText(applicationContext, "Success", Toast.LENGTH_LONG).show() } override fun onTransactionFail(p0: Transaction?) { Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() } }) ) } override fun onFail(p0: Int) { TODO("Not yet implemented") } })
Flutter集成遇到的问题
在Flutter中没有对应的原生按钮视图可以绑定BenefitInAppButtonListener,我尝试直接调用监听器的onButtonClicked()方法,虽然方法内的日志能正常打印,但内部传入的CheckoutListener完全没有触发回调。看起来必须通过SDK原生的BenefitInAppButtonListener触发完整流程,才能让CheckoutListener生效。
测试代码片段:
var myListener = object : BenefitInAppButtonListener { override fun onButtonClicked() { Log.i("hamad2", paymentAmount) // 该日志可正常输出 val benefitInAppCheckout = BenefitInAppCheckout.newInstance( this@MainActivity, ..., ..., ..., (object : CheckoutListener { override fun onTransactionSuccess(p0: Transaction?) { Toast.makeText(applicationContext, "Succ", Toast.LENGTH_LONG).show() } override fun onTransactionFail(p0: Transaction?) { Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() } }) ) } override fun onFail(p0: Int) { Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() } } myListener.onButtonClicked();
完整的MainActivity.kt代码
package com.example.benefit_test import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import android.widget.Toast import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import mobi.foo.benefitinapp.data.Transaction import mobi.foo.benefitinapp.listener.BenefitInAppButtonListener import mobi.foo.benefitinapp.listener.CheckoutListener import mobi.foo.benefitinapp.utils.BenefitInAppButton import mobi.foo.benefitinapp.utils.BenefitInAppCheckout class MainActivity: FlutterActivity() { private val channel = "ummatisoftwares.benefitpay" override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { call, result -> if (call.method == "BenefitPay"){ val amount = call.argument<String>("amount") val status = payBenefitApp(amount.toString()) if (status == "Success") result.success("Success") else result.error("Error", status, null) } else { result.notImplemented() } } } private fun payBenefitApp(paymentAmount: String): String { var status = "fail" var myListener = object : BenefitInAppButtonListener { override fun onButtonClicked() { Log.i("hamad2", paymentAmount) val benefitInAppCheckout = BenefitInAppCheckout.newInstance( this@MainActivity, ..., ..., ..., // 传入必要的字符串参数 (object : CheckoutListener { override fun onTransactionSuccess(p0: Transaction?) { Toast.makeText(applicationContext, "Suc", Toast.LENGTH_LONG).show() status = "Success" } override fun onTransactionFail(p0: Transaction?) { status = " "+p0.toString() Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() } }) ) } override fun onFail(p0: Int) { Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() } } myListener.onButtonClicked(); return status } }
解决方案建议
1. 模拟原生按钮触发流程
直接调用onButtonClicked()会跳过SDK内部的绑定逻辑,建议创建一个隐藏的BenefitInAppButton实例,绑定监听器后模拟点击,触发完整流程:
import android.view.View import android.view.ViewGroup private fun payBenefitApp(paymentAmount: String) { // 创建隐藏按钮并添加到视图树 val checkoutBtn = BenefitInAppButton(this) checkoutBtn.visibility = View.GONE val rootView = window.decorView.findViewById(android.R.id.content) as ViewGroup rootView.addView(checkoutBtn) checkoutBtn.setListener(object : BenefitInAppButtonListener { override fun onButtonClicked() { Log.i("hamad2", paymentAmount) val benefitInAppCheckout = BenefitInAppCheckout.newInstance( this@MainActivity, ..., ..., ..., object : CheckoutListener { override fun onTransactionSuccess(p0: Transaction?) { Toast.makeText(applicationContext, "Success", Toast.LENGTH_LONG).show() // 异步回调给Flutter flutterEngine?.let { MethodChannel(it.dartExecutor.binaryMessenger, channel) .invokeMethod("onPaymentResult", "Success") } rootView.removeView(checkoutBtn) } override fun onTransactionFail(p0: Transaction?) { val errorMsg = p0?.toString() ?: "Unknown error" Toast.makeText(applicationContext, "Fail", Toast.LENGTH_LONG).show() flutterEngine?.let { MethodChannel(it.dartExecutor.binaryMessenger, channel) .invokeMethod("onPaymentResult", errorMsg) } rootView.removeView(checkoutBtn) } } ) } override fun onFail(p0: Int) { val errorMsg = "Button init fail: $p0" Toast.makeText(applicationContext, errorMsg, Toast.LENGTH_LONG).show() flutterEngine?.let { MethodChannel(it.dartExecutor.binaryMessenger, channel) .invokeMethod("onPaymentResult", errorMsg) } rootView.removeView(checkoutBtn) } }) // 模拟按钮点击 checkoutBtn.performClick() }
2. 修改Flutter端回调逻辑
支付是异步流程,不能同步返回结果,需要在Flutter端监听MethodChannel回调:
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; class _PaymentPageState extends State<PaymentPage> { static const platform = MethodChannel('ummatisoftwares.benefitpay'); String _paymentResult = "等待支付..."; @override void initState() { super.initState(); // 监听Android端的回调 platform.setMethodCallHandler((call) async { if (call.method == "onPaymentResult") { setState(() { _paymentResult = call.arguments.toString(); }); } }); } Future<void> startPayment() async { try { await platform.invokeMethod("BenefitPay", {"amount": "100"}); } on PlatformException catch (e) { setState(() { _paymentResult = "支付错误: ${e.message}"; }); } } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_paymentResult), const SizedBox(height: 20), ElevatedButton( onPressed: startPayment, child: const Text("发起Benefit支付"), ), ], ), ), ); } }
3. 检查SDK初始化要求
确认SDK是否需要提前初始化全局配置、权限申请,或者必须在特定Activity生命周期中执行操作,可参考SDK官方文档补充必要步骤。
内容的提问来源于stack exchange,提问作者Ummati Softwares
相关产品推荐
相关产品推荐

