You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成Google Tez:如何获取被启动应用的返回数据?

解决Flutter中Google Tez UPI支付无法接收响应的问题

我明白你的困扰——用url_launcher只能启动Tez完成支付,但拿不到交易结果,这确实是因为url_launcher本身只负责启动外部应用,并不处理第三方应用返回的响应数据。你尝试的StreamSubscription监听的只是「是否成功启动应用」的布尔值,不是支付交易的结果,所以自然没用。

下面给你两种可行的解决方案:

方案一:通过Platform Channel自定义实现(Android原生层处理回调)

UPI支付的结果是通过Android的Intent返回的,我们需要在原生Android代码中用ActivityResultContracts(替代旧的startActivityForResult)来接收Tez返回的结果,再通过MethodChannel传递给Flutter。

Flutter端代码修改

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
 runApp(const MaterialApp(
 title: 'UPI Demo',
 home: UpiDemo(),
 ));
}

class UpiDemo extends StatefulWidget {
 const UpiDemo({super.key});

 @override
 _UpiDemoState createState() => _UpiDemoState();
}

class _UpiDemoState extends State<UpiDemo> {
 static const platform = MethodChannel('com.example.upi_demo/upi');
 String? transactionResult;

 Future<void> launchTez() async {
 try {
 final String result = await platform.invokeMethod('launchTez');
 setState(() {
 transactionResult = result;
 print('交易结果:$transactionResult');
 });
 } on PlatformException catch (e) {
 setState(() {
 transactionResult = "调用失败: '${e.message}'.";
 });
 }
 }

 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: const Text('UPI Demo'),
 ),
 body: Center(
 child: Column(
 mainAxisAlignment: MainAxisAlignment.center,
 children: [
 ElevatedButton(
 onPressed: launchTez,
 child: const Text('Click to Pay Rs.1.0/-'),
 ),
 if (transactionResult != null)
 Padding(
 padding: const EdgeInsets.all(16.0),
 child: Text('结果:$transactionResult'),
 )
 ],
 ),
 ),
 );
 }
}

Android原生代码修改(MainActivity.kt)

package com.example.upi_demo

import android.content.Intent
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContracts
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
 private val CHANNEL = "com.example.upi_demo/upi"
 private var resultCallback: MethodChannel.Result? = null

 private val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
 if (result.resultCode == RESULT_OK) {
 val data = result.data
 val response = data?.getStringExtra("response") ?: "无响应数据"
 resultCallback?.success(response)
 } else {
 resultCallback?.error("CANCELLED", "用户取消了交易", null)
 }
 }

 override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
 super.configureFlutterEngine(flutterEngine)
 MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
 if (call.method == "launchTez") {
 resultCallback = result
 val payeeAddress = "mobilenumber@upi"
 val payeeName = "payeename"
 val transactionNote = "Test for Deeplinking"
 val amount = "1"
 val currencyUnit = "INR"
 val uri = Uri.parse("upi://pay?pa=$payeeAddress&pn=$payeeName&tn=$transactionNote&am=$amount&cu=$currencyUnit")
 val intent = Intent(Intent.ACTION_VIEW, uri)
 startForResult.launch(intent)
 } else {
 result.notImplemented()
 }
 }
 }
}

这段代码的核心是用registerForActivityResult监听Tez返回的Intent,从中提取UPI响应字符串(格式一般是txnId=xxx;responseCode=xxx;...),再通过MethodChannel传给Flutter。

方案二:使用现成的UPI支付插件

如果不想写原生代码,可以用社区维护的UPI插件,比如upi_india(注意检查插件的最新版本和兼容性)。这类插件已经封装了UPI支付的启动和结果回调逻辑,使用起来更简单:

  1. 添加依赖到pubspec.yaml:
dependencies:
 upi_india: ^2.1.0 # 请使用最新版本
  1. 示例代码:
import 'package:flutter/material.dart';
import 'package:upi_india/upi_india.dart';

void main() {
 runApp(const MaterialApp(home: UpiDemo()));
}

class UpiDemo extends StatefulWidget {
 const UpiDemo({super.key});

 @override
 _UpiDemoState createState() => _UpiDemoState();
}

class _UpiDemoState extends State<UpiDemo> {
 UpiIndia _upiIndia = UpiIndia();
 List<UpiApp>? apps;

 @override
 void initState() {
 super.initState();
 _upiIndia.getAllUpiApps().then((value) {
 setState(() {
 apps = value;
 });
 });
 }

 Future<void> initiateTransaction(UpiApp app) async {
 UpiResponse response = await _upiIndia.startTransaction(
 app: app,
 pa: "mobilenumber@upi",
 pn: "payeename",
 tn: "Test for Deeplinking",
 am: "1",
 cu: "INR",
 );

 setState(() {
 print(response.transactionId);
 print(response.responseCode);
 // 这里可以处理交易结果
 });
 }

 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(title: const Text('UPI Demo')),
 body: apps == null
 ? const Center(child: CircularProgressIndicator())
 : ListView.builder(
 itemCount: apps!.length,
 itemBuilder: (context, index) {
 return ListTile(
 title: Text(apps![index].name),
 leading: Image.memory(apps![index].icon, height: 40),
 onTap: () => initiateTransaction(apps![index]),
 );
 },
 ),
 );
 }
}

这样插件会帮你处理启动应用和接收结果的逻辑,无需自己写原生代码。

为什么你的原有代码无效?

url_launcher的launch方法返回的Future<bool>仅仅表示「是否成功唤起了目标应用」,和支付交易的结果完全无关。你用asStream().listen监听的只是这个布尔值,自然拿不到Tez返回的交易响应数据。只有通过原生层的Intent结果回调,或者封装好的插件,才能获取到UPI支付的最终结果。

内容的提问来源于stack exchange,提问作者Mahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:12:43