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

Flutter应用迁移至Google Play Integrity API后上架失效求助

Flutter从Safety Net迁移至Play Integrity API 卡加载问题解决方案

1. 补全Flutter侧的集成逻辑

仅在build.gradle中添加原生依赖无法让Flutter调用Integrity API,必须通过平台通道实现跨端交互,或使用现成的Flutter插件:

平台通道实现方式

  • Android原生侧(Kotlin示例):在MainActivity中实现Integrity API调用,并通过通道将结果传回Flutter
    import com.google.android.play.core.integrity.IntegrityManagerFactory
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    
    class MainActivity : FlutterActivity() {
        private val CHANNEL = "integrity_channel"
    
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            super.configureFlutterEngine(flutterEngine)
            MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
                if (call.method == "requestIntegrityToken") {
                    val nonce = call.argument<String>("nonce") ?: ""
                    requestIntegrityToken(nonce, result)
                } else {
                    result.notImplemented()
                }
            }
        }
    
        private fun requestIntegrityToken(nonce: String, result: MethodChannel.Result) {
            val integrityManager = IntegrityManagerFactory.create(this)
            val tokenRequest = com.google.android.play.core.integrity.IntegrityTokenRequest.builder()
                .setNonce(nonce)
                .build()
    
            integrityManager.requestIntegrityToken(tokenRequest)
                .addOnSuccessListener { tokenResponse ->
                    result.success(tokenResponse.token())
                }
                .addOnFailureListener { exception ->
                    result.error("INTEGRITY_ERROR", exception.message, null)
                }
        }
    }
    
  • Flutter侧:注册通道并调用原生方法
    import 'package:flutter/services.dart';
    import 'dart:convert';
    
    class IntegrityApi {
      static const MethodChannel _channel = MethodChannel('integrity_channel');
    
      static Future<String?> getIntegrityToken(String nonce) async {
        try {
          // 将Nonce转为Base64编码(符合API要求)
          final base64Nonce = base64Encode(utf8.encode(nonce));
          return await _channel.invokeMethod('requestIntegrityToken', {'nonce': base64Nonce});
        } on PlatformException catch (e) {
          print('Integrity API调用失败: ${e.message}');
          return null;
        }
      }
    }
    

插件替代方案

使用维护活跃的Flutter插件简化集成,比如play_integrity:

  • 在pubspec.yaml添加依赖:
    dependencies:
      play_integrity: ^1.1.0 # 替换为最新版本
    
  • 调用示例:
    import 'package:play_integrity/play_integrity.dart';
    import 'dart:convert';
    
    Future<void> verifyAppIntegrity() async {
      try {
        // 生成符合要求的Nonce(建议从后端获取,避免硬编码)
        final rawNonce = "your_random_nonce_string_至少16字节";
        final base64Nonce = base64Encode(utf8.encode(rawNonce));
        
        final tokenResponse = await PlayIntegrity.requestIntegrityToken(nonce: base64Nonce);
        // 将token发送到后端进行验证
      } catch (e) {
        print('Integrity检查失败: $e');
        // 处理错误,避免应用一直卡在加载状态
      }
    }
    

2. 验证Play Console配置细节

  • 确认已在Play Console的应用完整性页面启用Play Integrity API,并绑定了正确的Google Cloud项目(Cloud项目需启用Play Integrity API,且服务账号拥有playintegrity.googleapis.com的调用权限)。
  • 检查应用签名:上架后应用使用Play App Signing签名,需确保后端验证时使用的是从Play Console下载的签名证书公钥。
  • Nonce必须满足要求:Base64编码的随机字符串,长度至少16字节,建议从后端动态生成,禁止硬编码在客户端。

3. 排查加载卡顿的核心原因

  • 避免主线程阻塞:原生侧调用Integrity API必须是异步操作,若在主线程同步执行会阻塞UI,导致加载卡顿(上述示例已使用异步回调处理)。
  • 查看错误日志:通过Android Studio的Logcat抓取报错信息,常见问题包括:
    • API_NOT_ENABLED:未在Cloud或Play Console启用API
    • PERMISSION_DENIED:服务账号权限不足
    • INVALID_NONCE:Nonce格式或长度不符合要求
    • APP_NOT_PUBLISHED:应用未上架到Play Console(内部测试需添加测试账号)

4. 修复加载状态问题

应用卡在加载状态通常是因为Integrity API调用未处理错误,导致后续流程中断。需在代码中添加错误捕获逻辑,比如:

Future<void> initApp() async {
  try {
    final token = await IntegrityApi.getIntegrityToken("secure_nonce_from_server");
    if (token != null) {
      // 发送到后端验证,验证通过后进入主页面
    } else {
      // 处理token获取失败的情况,比如提示用户或进入降级流程
    }
  } catch (e) {
    // 捕获所有异常,避免应用一直卡在加载
    print('初始化失败: $e');
    // 跳转错误页面或允许进入基础功能
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 06:45:54