Flutter

O Flutter usa um sistema flexível que permite chamar APIs específicas da plataforma, estejam elas disponíveis em código Kotlin ou Java no Android ou em código Swift ou Objective-C no iOS.

Este guia ensina como integrar o AllowMe SDK ao seu aplicativo Flutter utilizando o mecanismo de Platform Channel.

📘

Importante!

O tutorial abaixo possui simplificações por se tratar do código de um app de exemplo. Os resultados das chamadas são mostrados na tela para facilitar o entendimento. Você deverá fazer as modificações necessárias para a sua implementação real. Além disso, o código completo de exemplo está disponível. Entre em contato com [email protected] para ter acesso.

1. Implementação Nativa Android

Antes de prosseguir nessa seção é recomendado a leitura da integração nativa para Android.

O primeiro passo para integração do AllowMe com o seu aplicativo é verificar se a pasta responsável por conter os módulos nativos já existe em seu projeto:

Caso não exista você pode criá-la usando o seguinte comando na raíz do projeto:

$ flutter create -a kotlin .

1.1 Adicionando o AllowMeSDK como dependência

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Primeiros Passos - Adicionando AllowMeSDK como dependência da documentação nativa.Uma vez criada a pasta responsável por conter os código nativos Android você deve adicionar o SDK e suas dependências nos arquivos build.gradle do projeto.

O AllowMeSDK está hospedado em um repositório privado Maven, acessível via Gradle. Por isso, você deve adicionar ao build.gradle do seu projeto as seguintes linhas, contendo o username, password e URL:

allprojects {
	repositories {
        google()
        jcenter()

		maven {
			authentication {
				basic(BasicAuthentication)
			}
			credentials {
				username 'SEU_USERNAME_AQUI'
				password 'SEU_PASSWORD_AQUI'
			}
			url "SUA_URL_DO_REPOSITORIO_AQUI"
		}
	}
}

Em seguida, você deve adicionar essas dependências ao build.gradle do seu módulo:

dependencies {    
    // Para produção, utilize:
    releaseImplementation "br.com.allowme.android:allowme-sdk:3.4.9"
    // Para homologação, utilize:
    debugImplementation "br.com.allowme.android:allowme-sdk:3.4.9-stage"
}

❗️

Importante - Ofuscação!

O tópico a seguir se faz necessário apenas se a sua aplicação utiliza ofuscação no projeto. Caso não utilize pode passar para o próximo tópico desta integração

1.2 Configuração de Ofuscação

Caso o seu projeto se utilize de alguma feature de ofuscação de código (como Dexguard / Proguard ou outro), será necessário manter algumas classes que o SDK se utiliza. Isto se deve ao fato de que o mecanísmo de build do Flutter não ter a visibilidade completa sobre o grafo de dependências como no Android Nativo e caso esta configuração não seja feita é provável que erros em Runtime, ou seja, que acontecem em tempo de execução irão fazer o aplicativo quebrar.


As configurações necessárias são encontradas abaixo e devem fazer parte da configuração de sua ferramenta de ofuscação. Caso a ferramenta de ofuscação seja Proguard, pode-se adicionar estas configurações no arquivo utilizado pelo projeto.

Configuração no arquivo build.gradle

# modificar o buildType para adicionar o proguard no buildType correto, caso não exista.

buildTypes {
    release {
      # Adicionar as linhas abaixo para configurar o proguard para utilizar o arquivo proguard-rules.pro
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'retrofit2.pro'  
    }
}

Configurações do proguard-rules.pro

# Adicionar as Linhas Abaixo  
-keep @androidx.room.Entity class *

-keep class com.facetec.sdk.** { *; }
-keepresourcefiles assets/cache_uyertuazlkxcjrlwkejr/**

-keep class kotlin.** { *; }
-keep class kotlinx.** { *; }
-keep class kotlinx.coroutines** { *; }
-keep class androidx.** { *; }
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }

-keep class io.jsonwebtoken.** { *; }
-keep class com.google.** { *; }
-keep class com.scottyab.** { *; }
-keep class javax.** { *; }
-keep class androidx.lifecycle.** { *; }

# Work manager
-keep public class androidx.work.** { *; }

1.3 Criando Canal de Comunicação

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Primeiros Passos - Inicializar o SDK da documentação nativa.Para que a aplicação Flutter consiga enviar e receber comandos nativos é necessário criar um canal de comunicação. No exemplo abaixo nós criamos o canal "br.com.samples.allowme/sdk" e sobrescrevemos o método configureFlutterEngine da classe FlutterFragmentActivity.

📘

FlutterActivity vs FlutterFragmentActivity

O AllowMeSDK utiliza algumas features mais recentes do Android como Lifecycle Aware Components. Por este motivo utilizamos a classe FlutterFragmentActivity no lugar da classe FlutterActivity para fazer o processo de comunicação entre a aplicação em Flutter e o código nativo do AllowMeSDK.

Observe que o exemplo mostra um código inicial de implementação que implementa apenas o método setup do AllowMeSDK.

Verifique os produtos contratados para seguir na implementação mostrada nas próximas seções!

import {...}

class MainActivity : FlutterFragmentActivity() {
  private val CHANNEL = "br.com.samples.allowme/sdk"
  lateinit var mAllowMe: AllowMe

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)

      // Criação da instância AllowMe
      mAllowMe = AllowMe.getInstance(
          applicationContext,
          applicationContext.getString(R.string.api_key)
      )
  }

  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
      super.configureFlutterEngine(flutterEngine)
      MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
          when (call.method) {
              "setup" -> setupAllowMe(result)
              else -> result.notImplemented()
          }
      }
  }

  private fun setupAllowMe(result: MethodChannel.Result){
      mAllowMe.setup(object: SetupCallback{
          override fun success(){
              result.success("Setup AllowMe success")
          }
          override fun error(throwable: Throwable){
              result.error("Setup failed: ", throwable.message, null)
          }
      })
  }
}

❗️

Configurações Adicionais

Mesmo sua aplicação se tratando de um projeto Flutter ainda é necessário registrar a activity no AndroidManifest.xml além de adicionar as permissões recomendadas para o funcionamento do AllowMe. Para mais informações você pode consultar a documentação oficial Android (opens new window)ou a documentação AllowMe nativa.

1.4 Implementando o Device Intelligence (Contextual)

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Device Intelligence (Contextual) da documentação nativa.Com base no exemplo mostrado na seção anterior, podemos adicionar o código de exemplo abaixo para adicionar o produto Device Intelligence (Contextual) do AllowMeSDK com uma chamada ao método collect.

{...}
  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
        when (call.method) {
            "setup" -> setupAllowMe(result)
            "collect" -> getContextual(result)
            else -> result.notImplemented()
        }
        
    }
  }

  private fun getContextual(result: MethodChannel.Result){
    mAllowMe.collect(object: CollectCallback{
        override fun success(collect: String){
            result.success("Collect Contextual Success: ", collect)
        }
        
        override fun error(throwable: Throwable){
            result.error("Collect Contextual Failed: ", throwable.message,null)
        }
    })
  }
{...}
'

1.5 Implementando Validação de Endereço

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Validação de Endereço da documentação nativa.Com base no exemplo mostrado na seção anterior, podemos adicionar o código de exemplo abaixo para adicionar a função Validação de Endereço do AllowMeSDK. Observe que o método start tem como objetivo realizar o agendamento das coletas periódicas enquando o addPerson faz o envio das informações do usuário para o backend AllowMe para realização da validação de endereço.

{...}
  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
        when (call.method) {
            {...}
            "start" -> startValidação de Endereço(result)
            "addPerson" -> addPerson(result)
            else -> result.notImplemented()
        }
        
    }
  }

  private fun startOnboarding(result: MethodChannel.Result) {
    mAllowMe.start(object: StartCallback{
        override fun success() {
            result.success("Start Onboarding Success!")
        }
    
        override fun error(throwable: Throwable) {
            result.error("Start Onboarding Failed: ", throwable.message,null)           
        }
    })
  }

  private fun addPerson(result: MethodChannel.Result) {
    // Veja a documentação nativa do Android para ter mais informações sobre 
    // os dados que podem ser enviados para o método addPerson
    val address = Address(
      "Nome da Rua",
      "city",
      "state",
      100,
      "neighbourhood",
      "zipCode",
      "unit",
      "country",
      null
    )

    val person = Person(
      "Nome Completo",
      "00000000000",
      address,
      "email",
      "phone"
    )

    mAllowMe.addPerson(person, object : AddPersonCallback {
        override fun success() {
            result.success("Person added!")
        }

        override fun error(throwable: Throwable) {
            result.error("addPerson failed", throwable.message, null)
        }
    })
  }
{...}

Neste exemplo, o método addPerson que criamos instancia as classes Person e Address com valores pré-definidos. Esses valores, porém, devem ser fornecidos pela sua aplicação Flutter. Mais informações sobre os parâmetros aceitos pelo método podem ser encontradas em Cadastrando uma pessoa.

1.6 Implementando a Biometria Facial

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Biometria Facial da documentação nativa.Como mostrado na documentação nativa, a biometria facial requer uma permissão extra para o uso da câmera do celular. Certifique-se de pedir a permissão necessária antes de continuar.

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)

Após a adição da permissão de acesso à câmera, você está pronto para chamar a tela de captura da Biometria Facial conforme mostrado abaixo:

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
      when (call.method) {
          {...}
          "setup" -> setupAllowMe(result)
          "biometrics" -> startBiometrics()
          else -> result.notImplemented()
      }
    }
  }

  private fun startBiometrics() {
    val intent = Intent(this@MainActivity, AllowMeBiometricsActivity::class.java)

    startActivityForResult(intent, 999)
  }

Observe que para receber o resultado da Biometria Facial você deve inicializar a activiy com o método startActivityForResult. Esse método demanda uma implementação adicional na sua classe da função onActivityResult conforme mostrado abaixo:

  override fun onActivityResult(requestCode: Int, resultCode: Int, data:  Intent?) {
    if (requestCode == 999) {
        val biometricsResult = data?.extras?.getParcelable<BiometricsResult>(AllowMeBiometricsActivity.BIOMETRICS_RESULT_KEY)

        val result = verify(biometricsResult)
        // é necessário checar as fotos e/ou o erro retornados para 
        // enviá-los para o backend conforme detalhado na documentação oficial

        methodChannel?.invokeMethod("didReceiveBiometrics", result)
    }
  }

O resultado acima é transformado em String para ser mostrado na tela a partir do código em dart. Faça as modificações necessárias para a sua implementação!

2.Implementação Nativa iOS

Antes de prosseguir nessa seção é recomendado a leitura da integração nativa para iOS.

O primeiro passo para integração do AllowMe dentro do seu projeto é verificar se a pasta responsável por conter os módulos nativos já existe em seu projeto:

Caso não exista você pode criá-la usando o seguinte comando na raíz do seu projeto:

$ flutter create -i swift .

2.1. Adicionando o AllowMeSDK como dependência

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Primeiros Passos - Adicionando AllowMeSDK como dependência da documentação nativa.Antes de começar, certifique-se de que esteja de posse das credenciais de acesso aos nossos repositórios!

❗️

WARNING

Caso não faça ideia de onde estejam essas credenciais, entre em contato com o nosso suporte em [email protected].


O nosso SDK tem suporte para Swift Package Manager e Cocoapods. Escolha o que for melhor para o seu projeto, acesse o arquivo xcworkspace no Xcode os passos descritos na documentação nativa:

  • Swift Package Manager
  • Cocoapods

2.2. Criando o Canal de Comunicação

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Primeiros Passos - Importar e Inicializar o SDK da documentação nativa.Antes de tudo, importe o AllowMe de acordo com o target usado. Lembre-se que você deve adicionar o AllowMeSDKHomolog ao seu target de debug/homologação e o AllowMeSDK ao target de release/produção.

#if DEBUG
import AllowMeSDKHomolog
let ALLOWE_API_KEY = "your-homolog-api-key-here"
#else
import AllowMeSDK
let ALLOWE_API_KEY = "your-prod-api-key-here"
#endif

Após isso, para que a aplicação flutter consiga enviar e receber comandos nativos é necessário criar um canal de comunicação. No exemplo abaixo nós criamos o canal "br.com.samples.allowme/sdk" e através da sobrescrita do método application da classe FlutterAppDelegate conforme pode ser visto no exemplo abaixo:

import {...}

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate  {
  var allowMe: AllowMe?
  var methodChannel: FlutterMethodChannel?
  
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    methodChannel = FlutterMethodChannel(name: "br.com.samples.allowme/sdk", binaryMessenger: controller.binaryMessenger)

    // Você pode chamar o setup sempre na inicialização do aplicativo iOS (recomendado).
    // Nesse exemplo chamaremos apenas ao clicar no botão setup
    do {
      self.allowMe = try AllowMe.getInstance(withApiKey: "your-api-key-here")
    } catch let error {
      // tratar erro
    }

    methodChannel?.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      if self.allowMe != nil {
        if (call.method == "setup") {          
          self.allowMe?.setup { (error) in
            if error != nil {
              // tratar erro
              result(FlutterError(code: "SetupError", message: error?.localizedDescription, details: error))
            } else {
              // sucesso
              result("Setup Success!!")
            }
          }
        } else {
          result(FlutterMethodNotImplemented)
        }
      } else {
        result(FlutterMethodNotImplemented)
      }
    })
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Note que antes do "methodChannel?.setMethodCallHandler" pode ser chamado o setup do SDK. Conforme falado na documentação nativa, o setup faz a troca de chaves para que a criptografia esteja preparada antes da chamada nos outros métodos, aumentando a velocidade de resposta do SDK. Você pode chamar o setup apenas na entrada do AppDelegate do código nativo para que ele seja chamado sempre que o aplicativo iOS inicializar.

Agora, verifique os produtos contratados para seguir na implementação mostrada nas próximas seções!

2.3. Implementando o Device Intelligence (Contextual)

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Device Intelligence (Contextual) da documentação nativa.Tomando o código acima como base, vamos adicionar ao setMethodCallHandler a chamada ao método collect que retorna uma string criptografada contendo o fingerprint gerado pelo AllowMe. Observe o exemplo com o código abaixo:

{...}
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    

  {...}

  methodChannel?.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
    if self.allowMe != nil {
      {...}

      if (call.method == "collect") {
        self.allowMe?.collect(onSuccess: { (collect) in
          result("Collect Success: \(collect)")
        }, onError: { (error) in
          result("collect error: \(String(describing: error?.localizedDescription))")
        })
      } else {
        result(FlutterMethodNotImplemented)
      }
    } else {

    }

    result(FlutterMethodNotImplemented)
    return
  })
  
{...}
}

2.4. Implementando Validação de Endereço

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Validação de Endereço da documentação nativa.Ao contrário dos métodos mencionados anteriormente, o método start de agendamento de coletas para a função de Validação de Endereço deve apenas ser chamado durante a inicialização do app iOS conforme mostrado abaixo.

{...}
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    
  do {
    self.allowMe = try AllowMe.getInstance(withApiKey: ALLOWME_API_KEY)
    if let error = self.allowme.start() {
      // tratar erro
    } else {
      // sucesso
    }
  } catch let error {
    // tratar erro
  }
  
{...}
}

📘

IMPORTANTE!!!

Verifique a documentação nativa para entender porque o start deve ser chamado sempre durante a inicialização e realizar a configuração necessária de Background Modes. Observe também na documentação nativa a necessidade de sobrescrever, ou não, o método abaixo conforme fizemos com o método application

public override func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)

Após isso, implemente a função addPerson:

{...}
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    

  {...}

  methodChannel?.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
    if self.allowMe != nil {
      {...}

      if (call.method == "addPerson") {
        let adddress = AddressModel(street: "Rua",
                                    number: "000",
                                    neighbourhood: "Bairro",
                                    city: "Cidade",
                                    state: "AA",
                                    zipCode: "00000000")
        
        let person = PersonModel(name: "Nome",
                                  nationalId: "00000000000",
                                  address: adddress)
        
        self.allowMe?.addPerson(person: person, completion: { (error) in
          if error == nil {
            result("AddPerson Success!")
          } else {
            result("addPerson error: \(String(describing: error?.localizedDescription))")
          }
        })
      } else {
        result(FlutterMethodNotImplemented)
      }
    } else {
      result(FlutterMethodNotImplemented)
    }
  })
  
{...}
}

Veja a documentação nativa da Validação de Endereço para ver todos os dados que podem ser passados para o método addPerson a partir de sua aplicação Flutter

2.5. Implementando a Biometria Facial

Essa seção se refere à implementação em Flutter do que é mostrado com mais detalhes em Biometria Facial da documentação nativa. Do mesmo modo visto nas seções anteriores, a biometria facial deverá ser chamada dentro do setMethodCallHandler do canal de comunicação criado.

{...}
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    
  let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
  methodChannel = FlutterMethodChannel(name: "br.com.samples.allowme/sdk", binaryMessenger: controller.binaryMessenger)
  {...}

  methodChannel?.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
    if self.allowMe != nil {
      {...}

      if (call.method == "biometrics") {
        do {
          let config = AllowMeBiometricsConfig()
          try self.allowMe?.startBiometrics(viewController: controller,
                                          delegate: self, config: config)
          
        } catch let initError {
          result("Erro ao inicializar: \(initError.localizedDescription)")
        }
      } else {
        result(FlutterMethodNotImplemented)
      }
    } else {
      result(FlutterMethodNotImplemented)
    }
  })
  
{...}
}

Observe a documentação nativa da Biometria Facial para verificar todas as possibilidades de customização disponíveis com a AllowMeBiometricsConfig.

O método startBiometrics recebe, além da ViewController declarada no início da função, um delegate. Você pode passar a classe que quiser como delegate desde que ela herde o protocolo AllowMeBiometricsDelegate. Nesse exemplo, passamos self, ou seja, a própria classe AppDelegate. Para isso, adicionamos o protocolo e a função biometricsDidFinish na classe conforme mostrado abaixo:

{...}
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, AllowMeBiometricsDelegate {
  {...}

  func biometricsDidFinish(biometricsObject: AllowMeBiometricsResult?, error: Error?) {
    let result = verify(biometricsObject, error)
    // é necessário checar o objeto e o erro retornados para 
    // enviá-los para o backend conforme detalhado na documentação oficial

    methodChannel?.invokeMethod("didReceiveBiometrics", arguments: result)
  }
}

📘

TIP

Para informações de como implementar a Biometria Facial com provider Facetec, veja as seções 4.3. Telas de Captura FaceTec e providerError na seção 5. Implementação do AllowMeBiometricsDelegate.

3. Integrando com o código dart

Agora que criamos os canais de comunicação no Android e iOS precisamos chamá-los através da nossa aplicação Flutter em dart. Você deve fazer isso usando platform.invokeMethod('nome-do-método') para invocar o método correspondente de cada plataforma.

Para cada botão do nosso aplicativo Flutter, vamos chamar cada uma das funções abaixo conforme a necessidade dos produtos contratados e implementados anteriormente

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  {...}
  // AllowMe Geral - Primeiros Passos
  Future<void> _setupSDK() async {
    String setupResult = "Not started yet";

    try {
      setupResult = await platform.invokeMethod('setup');
    } on PlatformException catch (e) {
      setupResult = "Failed to setup AllowMe '${e.message}'.";
    }

    _setAllowMeResult(setupResult);
  }

  // AllowMe Device Intelligence (Contextual)
  Future<void> _collect() async {
    String collect = "Not started yet";

    try {
      collect = await platform.invokeMethod('collect');
    } on PlatformException catch (e) {
      collect = "Failed to get collect '${e.message}'.";
    }

    _setAllowMeResult(collect);
  }

  // AllowMe Validação de Endereço
  Future<void> _startSDK() async {
    String startResult = "Not started yet";

    try {
      startResult = await platform.invokeMethod('start');
    } on PlatformException catch (e) {
      startResult = "Failed to start SDK '${e.message}'.";
    }

    _setAllowMeResult(startResult);
  }

  Future<void> _addPerson() async {
    String addPersonResult = "No result yet";

    try {
      await platform.invokeMethod('addPerson');
      addPersonResult = "Add Person with success";
    } on PlatformException catch (e) {
      addPersonResult = "Failed to addPerson '${e.message}'.";
    }

    _setAllowMeResult(addPersonResult);
  }

3.1 Implementando a Biometria

A chamada da Biometria Facial trabalha de maneira semelhante aos outros métodos mostrados anteriormente.

import {...}

{...}

class _MyHomePageState extends State<MyHomePage> {
  static const platform = const MethodChannel("br.com.samples.allowme/sdk");
  
  {...}
  
  Future<void> _biometrics() async {
    String biometrics = "No Context yet";

    try {
      biometrics = await platform.invokeMethod('biometrics');
    } on PlatformException catch (e) {
      biometrics = "'${e.message}'.";
    }

    _setAllowMeResult(biometrics);
  }

  {...}
}

Para receber o resultado da Biometria Facial, o canal de comunicação seguirá o caminho inverso ao que estamos acostumados. Assim, devemos também implementar a função que será chamada pelas implementações nativas do Android e do iOS. Para isso, adicionaremos um novo callHandler mostrado abaixo:

@override
  Widget build(BuildContext context) {
    platform.setMethodCallHandler(this._didReceiveBiometrics);

    {...}
  }

e implementaremos a função chamada pelas plataformas. No nosso caso, as duas plataformas invocam a função didReceiveBiometrics.

{...}

  Future<void> _didReceiveBiometrics(MethodCall call) async {
    final String result = call.arguments;

    switch (call.method) {
      case "didReceiveBiometrics":
        if (result != null) {
          setState(() {
            _allowMeResult = result;
          });
        }
    }
  }

📘

TIP

Em caso dúvidas ou para ter acesso ao código fonte desse exemplo entre em contato com [email protected].