SSLCOMMERZ 在 debug apk 正常但 release apk 无法使用
结论
既然 flutter run --release 和 flutter run --profile 都能正常完成支付,SSLCOMMERZ 的基本集成通常没有问题,也不太可能只是缺少 INTERNET 权限。更值得检查的是,最终安装的 APK 与运行测试时使用的构建环境是否一致。
建议先检查以下几项:
- 安装的 APK 是否确实是刚生成的 release 包。
- release 签名、product flavor、环境变量和支付配置是否正确。
- R8/ProGuard 是否删除了 SDK 依赖的类。
- 支付回调涉及的 Activity、深链或网络安全配置是否只存在于 debug 配置中。
- 使用
adb logcat查看已安装 APK 的 Android 日志,不要只看 Flutter 控制台。
先确认测试的是同一个 APK
flutter run --release 会构建并安装 release 版本。手动创建、复制或分发 APK 时,则可能误装旧文件、其他 flavor 的文件,或者 ABI 不匹配的文件。
先清理项目并重新构建:
flutter clean
flutter pub get
flutter build apk --release
默认产物通常位于:
build/app/outputs/flutter-apk/app-release.apk
卸载旧应用,再安装刚生成的 APK:
adb uninstall com.example.your_app
adb install build/app/outputs/flutter-apk/app-release.apk
将 com.example.your_app 替换为实际的 applicationId。卸载操作会清除应用数据。如果需要保留数据,可以先尝试:
adb install -r build/app/outputs/flutter-apk/app-release.apk
如果项目使用 flavor,构建和运行必须使用同一组参数,例如:
flutter run --release --flavor production -t lib/main_production.dart
flutter build apk --release --flavor production -t lib/main_production.dart
查看手动安装 APK 的日志
无论 APK 是否由 Flutter 命令启动,都可以通过 adb logcat 获取日志。连接手机并开启 USB 调试后,先确认设备已被识别:
adb devices
清空旧日志,然后启动应用并复现问题:
adb logcat -c
adb logcat
如果日志太多,可以按常见异常关键字过滤:
adb logcat | grep -iE "flutter|androidruntime|ssl|exception|fatal|chromium"
也可以只查看目标应用的进程日志。在 macOS 或 Linux 上执行:
adb logcat --pid=$(adb shell pidof -s com.example.your_app)
如果应用启动后立即退出,可能来不及获取进程 ID,此时可以使用:
adb logcat -b crash
重点查找以下内容:
FATAL EXCEPTIONClassNotFoundExceptionNoClassDefFoundErrorActivityNotFoundExceptionSecurityExceptionNetworkSecurityPolicy- TLS、证书或域名校验错误
- WebView、Chrome 或支付回调相关错误
如果系统中没有 adb,需要先安装 Android SDK Platform-Tools。
检查 AndroidManifest 配置
网络权限应写在能够合并到 release 构建的主清单中:
<!-- android/app/src/main/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="${applicationName}"
android:label="your_app"
android:icon="@mipmap/ic_launcher">
<!-- Activities and other declarations -->
</application>
</manifest>
不要只把权限写在以下文件中:
android/app/src/debug/AndroidManifest.xml
android/app/src/profile/AndroidManifest.xml
不过,Flutter 项目通常已经包含联网所需的配置。既然 flutter run --release 可以正常使用,单纯缺少 INTERNET 权限的可能性不高。
还可以检查最终 release 清单的合并结果。在 Android Studio 中打开 AndroidManifest.xml,切换到 Merged Manifest,确认 release 变体中包含所需的权限、Activity、intent filter 和 meta-data。
检查支付环境和构建参数
支付 SDK 的问题常常来自配置差异,而不是代码本身。例如,debug 运行时读取了测试配置,手动构建 APK 时却没有传入对应参数:
const storeId = String.fromEnvironment('STORE_ID');
const isSandbox = bool.fromEnvironment(
'SSL_SANDBOX',
defaultValue: true,
);
如果代码使用这种方式读取配置,运行和构建时必须传入相同的 --dart-define:
flutter build apk --release \
--dart-define=STORE_ID=your_store_id \
--dart-define=SSL_SANDBOX=true
对应的运行命令也要保持一致:
flutter run --release \
--dart-define=STORE_ID=your_store_id \
--dart-define=SSL_SANDBOX=true
同时核对以下内容:
- sandbox 与 production 的凭据是否混用。
- release APK 的
applicationId是否发生变化。 - 不同 flavor 是否使用了不同的配置文件。
- 支付后台是否限制了包名、签名证书、回调地址或域名。
- 构建脚本是否从本机环境变量读取密钥,而生成 APK 时该变量为空。
不要把正式商户密钥直接打印到日志中。
检查 release 签名差异
手动生成的 APK 可能使用 release keystore,而 flutter run 使用了不同的签名配置。如果支付服务、深链验证或相关平台通过证书指纹识别应用,签名不一致就可能导致支付失败。
查看 APK 的签名信息:
apksigner verify --print-certs build/app/outputs/flutter-apk/app-release.apk
也可以检查 keystore 的证书指纹:
keytool -list -v -keystore /path/to/your-release-key.jks
不要在日志、截图或仓库中公开 keystore 密码和私钥文件。
排除 R8 或 ProGuard 优化问题
如果 release 构建启用了代码压缩,SDK 中通过反射、注解或字符串加载的类可能被 R8 删除。日志中通常会出现:
ClassNotFoundException
NoClassDefFoundError
检查 android/app/build.gradle 或 android/app/build.gradle.kts,确认 release 配置是否启用了:
minifyEnabled true
shrinkResources true
定位问题时,可以临时关闭这两项:
buildTypes {
release {
minifyEnabled false
shrinkResources false
}
}
如果关闭后恢复正常,就需要添加 keep rule,不建议长期关闭压缩。规则必须按照 SSLCOMMERZ Flutter 插件及其 Android SDK 实际使用的包名编写,例如:
-keep class actual.sdk.package.** { *; }
-dontwarn actual.sdk.package.**
actual.sdk.package 只是占位符,不能直接使用。应从插件源码、依赖列表或 SDK 文档中确认真实包名,不要根据名称猜测 keep rule。
检查网络安全与 TLS
如果日志中出现以下错误:
Cleartext HTTP traffic not permitted
说明某个请求仍在使用 http://。优先将接口和回调地址改为 https://。
只有当对方服务确实不支持 HTTPS,并且已经评估相关风险时,才考虑配置 networkSecurityConfig。不要为了排查问题,直接允许所有域名使用明文流量。
如果出现证书或 TLS 错误,应检查:
- 手机的日期和时间是否正确。
- 支付域名的证书链是否完整。
- 旧 Android 设备是否支持服务端要求的 TLS 和证书。
- 项目是否配置了证书固定,并且 release 使用了不同的证书。
- WebView 或 Chrome 是否过旧。
给支付流程增加可观测日志
不要只记录“支付失败”,应分别记录支付初始化、页面打开、回调和异常阶段:
import 'dart:developer' as developer;
Future<void> startPayment() async {
developer.log(
'Starting SSLCOMMERZ payment',
name: 'payment',
);
try {
// 调用实际的 SSLCOMMERZ 支付 API。
final result = await startSslCommerzPayment();
developer.log(
'Payment returned: $result',
name: 'payment',
);
} catch (error, stackTrace) {
developer.log(
'SSLCOMMERZ payment failed',
name: 'payment',
error: error,
stackTrace: stackTrace,
);
}
}
其中,startSslCommerzPayment() 需要替换为项目实际使用的 API。
日志中不要输出银行卡信息、交易密钥、完整 token、用户密码或其他敏感数据。正式发布时,更适合接入经过脱敏处理的崩溃和错误采集服务。
建议的排查顺序
按以下顺序处理通常更快:
- 执行
flutter clean,然后重新生成 APK。 - 卸载旧版本,直接安装刚生成的
app-release.apk。 - 使用
adb logcat复现问题,找到第一条真实异常。 - 对比
flutter run --release和flutter build apk --release使用的 flavor、入口文件及--dart-define。 - 核对最终合并后的 Manifest。
- 检查 APK 签名,以及支付后台对包名和证书的限制。
- 如果日志中出现类缺失错误,再检查 R8/ProGuard。
- 如果出现 TLS、HTTP 或 WebView 错误,再处理网络安全配置。
首先要拿到 adb logcat 中的具体异常。由于 release 模式直接运行时支付正常,仅凭当前现象无法判断是 SSLCOMMERZ 插件缺陷。构建参数、安装包来源、签名或 flavor 不一致,更值得先查。
备注:内容仅供参考。
