firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.71k stars 3.97k forks source link

[📚] App Check - Missing MainActivity.kt code sample #7968

Closed al4nnw closed 1 year ago

al4nnw commented 2 years ago

I've been trying to implement App Check for my project following the documentation found on this page, but I'm facing some issues in implementing it for my Android Emulator.

My Flutter project was created with Kotlin as android language, but the documentation doesn't provide any code sample to MainActivity.kt.

When I try to get a token with await FirebaseAppCheck.instance.getToken();, I successfully get one but when I use a Firebase service, a message like this appears on my console.

W/StorageUtil( 7558): Error getting App Check token; using placeholder token instead. Error: com.google.firebase.FirebaseException: Too many attempts.

What I've already done:

  • Added implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0-beta04' to my android/app/build.gradle.

  • Added implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0-beta01' to my android/app/build.gradle.

  • Initialized FirebaseAppCheck on my main.dart file with await FirebaseAppCheck.instance.activate();.

What I've tried:

What I expected:

  • Getting a local debug token logged.
al4nnw commented 2 years ago

Tested on my real iOS device debug mode, it works fine. Haven't tried on real Android device yet.

PaulRudin commented 2 years ago

I can't get the debug provider to work either. That code sample defines a method channel, but presumably something needs to invoke it?

al4nnw commented 2 years ago

Yes. [As stated in the documentation ](https://firebase.flutter.dev/docs/app-check/usage/#:~:text=DebugAppCheckProviderFactory.getInstance()), this line should log a debug token. But the documentation isn't clear on how to do it with a Kotlin created project.

PaulRudin commented 2 years ago

I got this to work by initializing the firebase app in flutter code and then:

if (kDebugMode) {
  const platform = MethodChannel('samples.flutter.dev/appcheck');
  final int r = await platform.invokeMethod("installDebug");
}

and in android/app/src/main/kotlin/com/foo/bar/MainActivity.kt:

class MainActivity: FlutterActivity() {
    private val CHANNEL = "samples.flutter.dev/appcheck"
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {

        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
            .setMethodCallHandler {
                call, result ->
                    if (call.method == "installDebug") {
                        val firebaseAppCheck = FirebaseAppCheck.getInstance()
                        firebaseAppCheck.installAppCheckProviderFactory(
                            DebugAppCheckProviderFactory.getInstance()
                        )
                        result.success(1)
                    } else {
                        result.notImplemented()
                    }
            }
       }
}

This seems to work - although I don't really know what I'm doing when it comes to the kotlin/native side - if there's anything bad about leaving this code in my app please say something...

This is quite a departure from what's described in the documentation - but I couldn't get that to work.

yevgeniaronov commented 2 years ago

I can't get the debug provider to work either. That code sample defines a method channel, but presumably something needs to invoke it?

run: adb -s DEVICE_ID logcat > logcat.txt and search for it in the txt file.

al4nnw commented 2 years ago

Tested it on my debug device, it worked!

The documentation still needs to be fixed.

PaulRudin commented 2 years ago

In passing - I couldn't get things to work on ios either (no token printed), so I tried the same approach (in AppDelegate.swift instead), and whilst the provider apparently gets installed OK, I still can't see a debug token anywhere.

al4nnw commented 2 years ago

Mine looks like this and it works. I was using debug mode with real ios device.

import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let providerFactory = AppCheckDebugProviderFactory()
    AppCheck.setAppCheckProviderFactory(providerFactory)
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
cedvdb commented 2 years ago

It would be nice if the kotlin swift code included the whole file instead of just what to add, some of us are not familiar with kotlin / swift

PaulRudin commented 2 years ago

It would be nice if the kotlin swift code included the whole file instead of just what to add, some of us are not familiar with kotlin / swift

... and also concrete examples of how to structure different builds for both iOS and Android, so that it's clear how to get the debug provider configured in debug builds, but not in release builds.

sgenou commented 2 years ago

I got this to work by initializing the firebase app in flutter code and then:

if (kDebugMode) {
  const platform = MethodChannel('samples.flutter.dev/appcheck');
  final int r = await platform.invokeMethod("installDebug");
}

and in android/app/src/main/kotlin/com/foo/bar/MainActivity.kt:

class MainActivity: FlutterActivity() {
    private val CHANNEL = "samples.flutter.dev/appcheck"
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {

        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
            .setMethodCallHandler {
                call, result ->
                    if (call.method == "installDebug") {
                        val firebaseAppCheck = FirebaseAppCheck.getInstance()
                        firebaseAppCheck.installAppCheckProviderFactory(
                            DebugAppCheckProviderFactory.getInstance()
                        )
                        result.success(1)
                    } else {
                        result.notImplemented()
                    }
            }
       }
}

This seems to work - although I don't really know what I'm doing when it comes to the kotlin/native side - if there's anything bad about leaving this code in my app please say something...

This is quite a departure from what's described in the documentation - but I couldn't get that to work.

Man, you saved my life! Almost three days on this, just because the documentation is not clear enough...

cedvdb commented 2 years ago

The new firebase/flutter documentation does not contain anything really, maybe clicking send feedback could prove to be useful here: https://firebase.google.com/docs/app-check/flutter/default-providers

There is no mention of adding such snippet, so maybe it's not needed anymore ?

gOzaru commented 2 years ago

I got this to work by initializing the firebase app in flutter code and then:

if (kDebugMode) {
  const platform = MethodChannel('samples.flutter.dev/appcheck');
  final int r = await platform.invokeMethod("installDebug");
}

@PaulRudin May I know the full code for this lines above? Should I input them inside FirebaseApp()? Thank you for the help.

gOzaru commented 2 years ago

No need. I know already. We need to add it inside the codes before
runApp(const MyApp());

cedvdb commented 2 years ago

This all seems very hacky, I doubt it's how it's supposed to work and won't break in the future.

gOzaru commented 2 years ago

This all seems very hacky, I doubt it's how it's supposed to work and won't break in the future.

I think the best solution is to not apply App Check before production. I meant, just remove the current app in Firebase Console and resign the app without any of Safety Enforce. Then remove this code in Cloud Function:

if (context.app == undefined) {
       throw new functions.https.HttpsError(
        'failed-precondition',
        'The function must be called from an App Check verified app.');
}

Period. Problem is now solved.

[Update] It seems we need to remove the SHA-256 in order to remove the Safety-Net enforce. That's all.

suhailbilalo commented 2 years ago

I got this to work by initializing the firebase app in flutter code and then:

if (kDebugMode) {
  const platform = MethodChannel('samples.flutter.dev/appcheck');
  final int r = await platform.invokeMethod("installDebug");
}

and in android/app/src/main/kotlin/com/foo/bar/MainActivity.kt:

class MainActivity: FlutterActivity() {
    private val CHANNEL = "samples.flutter.dev/appcheck"
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {

        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
            .setMethodCallHandler {
                call, result ->
                    if (call.method == "installDebug") {
                        val firebaseAppCheck = FirebaseAppCheck.getInstance()
                        firebaseAppCheck.installAppCheckProviderFactory(
                            DebugAppCheckProviderFactory.getInstance()
                        )
                        result.success(1)
                    } else {
                        result.notImplemented()
                    }
            }
       }
}

This seems to work - although I don't really know what I'm doing when it comes to the kotlin/native side - if there's anything bad about leaving this code in my app please say something...

This is quite a departure from what's described in the documentation - but I couldn't get that to work.

Above Lines need to write in main method with the following imports on top

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

and for the MainActivity.kt following imports

import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel;
import com.google.firebase.appcheck.FirebaseAppCheck
import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory
import androidx.annotation.NonNull
russellwheatley commented 1 year ago

You can now pass a debug provider enum to App Check activate() API which will activate the debug provider.