PAYATHON 2026

Flutter 集成 Revolut Payment 出现未解析引用

支付小周

结论

这两个错误通常来自以下问题:

  1. MainActivity.kt 缺少对应的 Kotlin imports。
  2. Revolut SDK 依赖写在了错误的 Gradle 文件中,或者 Gradle 尚未成功解析依赖。

题目中的 SDK API 通常需要导入:

import com.revolut.revolutpayments.RevolutPayments
import com.revolut.revolutpay.api.RevolutPayEnvironment

依赖应添加到 Flutter 项目的 android/app/build.gradle,而不是项目级的 android/build.gradle。

正确配置 Gradle 依赖

打开 Flutter 项目中的模块级 Gradle 文件:

android/app/build.gradle

在 dependencies 中添加:

dependencies {
    implementation "com.revolut:revolutpayments:1.0.0"
    implementation "com.revolut:revolutpay:2.2"
}

不要把 implementation 直接写进项目级的 android/build.gradle。依赖只有添加到 Android 应用模块,才能进入 MainActivity.kt 的编译 classpath。

如果项目使用 Kotlin DSL,对应文件可能是 android/app/build.gradle.kts,语法需要改成:

dependencies {
    implementation("com.revolut:revolutpayments:1.0.0")
    implementation("com.revolut:revolutpay:2.2")
}

同时确认项目已经配置 SDK 所在的 Maven 仓库。通常至少应包含:

repositories {
    google()
    mavenCentral()
}

较新的 Flutter 和 Gradle 项目一般会在 android/settings.gradle 的 dependencyResolutionManagement 中统一配置仓库,不需要在 app/build.gradle 中重复添加。

添加 Kotlin imports

在 MainActivity.kt 顶部加入:

import com.revolut.revolutpayments.RevolutPayments
import com.revolut.revolutpay.api.RevolutPayEnvironment

完整的 import 区域可以写成:

package com.example.foodbourge_mobile_app

import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.annotation.NonNull
import com.revolut.revolutpay.api.RevolutPayEnvironment
import com.revolut.revolutpayments.RevolutPayments
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

如果还需要传递 Customer,请根据当前 SDK 版本中该类型的实际包路径添加 import。Revolut SDK 不同版本的包结构可能会变化,不要直接照搬旧版示例。可以使用 Android Studio 的自动导入功能确认正确路径。

调整后的 MainActivity.kt

下面的代码保留了现有 MethodChannel 结构,并添加了实际调用支付初始化方法的分支:

package com.example.foodbourge_mobile_app

import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.annotation.NonNull
import com.revolut.revolutpay.api.RevolutPayEnvironment
import com.revolut.revolutpayments.RevolutPayments
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {

    private val CHANNEL = "samples.flutter.dev/revolut_pay"

    override fun configureFlutterEngine(
        @NonNull flutterEngine: FlutterEngine
    ) {
        super.configureFlutterEngine(flutterEngine)

        fun getBatteryLevel(): Int {
            return if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                val batteryManager =
                    getSystemService(Context.BATTERY_SERVICE) as BatteryManager

                batteryManager.getIntProperty(
                    BatteryManager.BATTERY_PROPERTY_CAPACITY
                )
            } else {
                val intent = ContextWrapper(applicationContext).registerReceiver(
                    null,
                    IntentFilter(Intent.ACTION_BATTERY_CHANGED)
                )

                if (intent == null) {
                    -1
                } else {
                    val level = intent.getIntExtra(
                        BatteryManager.EXTRA_LEVEL,
                        -1
                    )
                    val scale = intent.getIntExtra(
                        BatteryManager.EXTRA_SCALE,
                        -1
                    )

                    if (level < 0 || scale <= 0) -1 else level * 100 / scale
                }
            }
        }

        fun initializeRevolutPay() {
            RevolutPayments.revolutPay.init(
                environment = RevolutPayEnvironment.SANDBOX,
                merchantPublicKey = "YOUR_MERCHANT_PUBLIC_KEY",
                requestShipping = false
            )
        }

        MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            CHANNEL
        ).setMethodCallHandler { call, result ->
            when (call.method) {
                "getBatteryLevel" -> {
                    val batteryLevel = getBatteryLevel()

                    if (batteryLevel != -1) {
                        result.success(batteryLevel)
                    } else {
                        result.error(
                            "UNAVAILABLE",
                            "Battery level not available.",
                            null
                        )
                    }
                }

                "initializeRevolutPay" -> {
                    try {
                        initializeRevolutPay()
                        result.success(null)
                    } catch (exception: Exception) {
                        result.error(
                            "REVOLUT_INITIALIZATION_FAILED",
                            exception.message,
                            null
                        )
                    }
                }

                else -> result.notImplemented()
            }
        }
    }
}

原代码中的 payByRevolut() 只是局部函数,没有在 MethodChannel 的处理逻辑中调用。即使解决了编译错误,Flutter 端调用其他方法时也不会触发 Revolut 初始化。

重新同步依赖

修改 Gradle 文件后,可以在项目根目录执行:

flutter clean
flutter pub get
cd android
./gradlew clean
cd ..
flutter run

Windows 环境使用:

cd android
gradlew.bat clean
cd ..
flutter run

如果 Android Studio 仍然显示红色的未解析引用,可以执行 Gradle Sync,然后重新打开项目的 android 目录,让 IDE 重建依赖索引。

如何判断是 import 问题还是依赖问题

如果依赖已经成功下载,只是遗漏了 import,Android Studio 通常能在类名上提供自动导入,并显示类似下面的候选项:

com.revolut.revolutpayments.RevolutPayments
com.revolut.revolutpay.api.RevolutPayEnvironment

如果没有任何自动导入候选项,问题通常不只是缺少 import,而是 SDK 没有进入应用模块的 classpath。此时应检查:

  • 依赖是否写在 android/app/build.gradle 中。
  • Gradle Sync 是否成功。
  • 是否已经配置 mavenCentral() 等仓库。
  • Gradle 输出中是否出现 “Could not find” 或 “Could not resolve”。
  • 文档示例与实际使用的 SDK 版本是否一致。
  • 两个 Revolut artifact 的版本是否兼容。

Revolut SDK 的 artifact、版本号和包路径可能随版本升级而变化。上面的 imports 对应题目中 RevolutPayments.revolutPay 和 RevolutPayEnvironment 这套 API。如果 Gradle 已经成功解析依赖,但这些包仍然不存在,说明当前依赖版本与参考文档的版本不一致。此时应以该 SDK 版本实际导出的类和官方版本说明为准。

生产环境注意事项

开发阶段可以使用:

environment = RevolutPayEnvironment.SANDBOX

切换到生产环境时,除了修改枚举值,还需要确认:

  • 使用生产环境对应的 merchant public key。
  • 后端订单和支付接口也已切换到生产环境。
  • Android 应用签名、包名和商户后台配置正确。
  • 初始化操作不会在每次 MethodChannel 调用时重复执行。

题目中展示的 merchant public key 已经公开出现在代码片段中。即使它是公钥,也建议将其替换为商户后台当前有效且与目标环境匹配的配置值,不要继续使用示例值。

备注:内容仅供参考。