bemall_promotion 1.0.0+1 copy "bemall_promotion: ^1.0.0+1" to clipboard
bemall_promotion: ^1.0.0+1 copied to clipboard

SDK para integração com a plataforma BeMall.

📦 BeMall SDK #

Este pacote Flutter fornece uma interface para integração com o WebApp da plataforma BeMall.


📁 Instalação (via ZIP local) #

  1. Extraia o arquivo .zip que você recebeu do BeMall para dentro do seu projeto.
    Sugerimos a pasta vendor/bemall-sdk/:
seu_app/
  lib/
  pubspec.yaml
  vendor/
      promotion/
  1. Referencie os pacotes por caminho no pubspec.yaml:
dependencies:
  # WebApp de Promoções
  bemall_promotion:
    path: ./vendor/bemall-sdk/promotion

Se preferir manter os pacotes fora do projeto, também funciona:

bemall_promotion:
  path: /caminho/absoluto/para/bemall-sdk/promotion
  1. iOS – Podfile
    No arquivo ios/Podfile, defina a plataforma mínima:
platform :ios, '15.5'
  1. Instale as dependências:
flutter pub get

🛡️ Configuração de Build (Android) #

Para evitar problemas de ofuscação/reflexão, adicione android/app/proguard-rules.pro:

# === ML Kit - Manter opções de reconhecimento ===
-keep class com.google.mlkit.vision.text.** { *; }
-dontwarn com.google.mlkit.vision.text.**

# === JAI ImageIO (usado por image_picker e ML Kit) ===
-keep class javax.imageio.** { *; }
-dontwarn javax.imageio.**
-keep class com.github.jaiimageio.impl.** { *; }
-dontwarn com.github.jaiimageio.impl.**

# === Prevenir remoção de classes acessadas via reflexão ===
-keep class * extends java.util.List
-keep class * extends java.util.Map

# === Evitar remoção de métodos dinâmicos ===
-keepattributes *Annotation*,EnclosingMethod,InnerClasses,Signature

# === Opcional: Manter ML Kit Commons ===
-keep class com.google_mlkit_commons.** { *; }
-dontwarn com.google_mlkit_commons.**
-dontwarn com.github.jaiimageio.**
-dontwarn java.awt.**

Adicione no app/build.gradle

ndkVersion = "27.0.12077973"

buildTypes {
        release {
           proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
        }
    }

🧪 Exemplo de uso — WebApp de Promoções #

import 'package:flutter/material.dart';
import 'package:bemall_promotion/bemall_sdk.dart';

void main() async {
  runApp(const MyApp()
}



class MyApp extends StatelessWidget {
  const MyApp({super.key});

   void _handleWebViewError(dynamic error) {
    switch (error.errorType) {
      case WebResourceErrorType.authentication:
        debugPrint("Falha de autenticação no servidor");
        break;
      case WebResourceErrorType.badUrl:
        debugPrint("URL malformada");
        break;
      case WebResourceErrorType.connect:
        debugPrint("Falha ao conectar ao servidor");
        break;
      case WebResourceErrorType.failedSslHandshake:
        debugPrint("Falha na negociação SSL/TLS");
        break;
      case WebResourceErrorType.file:
        debugPrint("Erro genérico de arquivo");
        break;
      case WebResourceErrorType.fileNotFound:
        debugPrint("Arquivo não encontrado");
        break;
      case WebResourceErrorType.hostLookup:
        debugPrint("DNS não encontrado");
        break;
      case WebResourceErrorType.io:
        debugPrint("Erro de leitura/escrita (I/O)");
        break;
      case WebResourceErrorType.proxyAuthentication:
        debugPrint("Falha de autenticação em proxy");
        break;
      case WebResourceErrorType.redirectLoop:
        debugPrint("Loop de redirecionamento detectado");
        break;
      case WebResourceErrorType.timeout:
        debugPrint("Conexão expirada");
        break;
      case WebResourceErrorType.tooManyRequests:
        debugPrint("Muitas requisições");
        break;
      case WebResourceErrorType.unknown:
        debugPrint("Erro genérico/desconhecido");
        break;
      case WebResourceErrorType.unsafeResource:
        debugPrint("Recurso inseguro bloqueado");
        break;
      case WebResourceErrorType.unsupportedAuthScheme:
        debugPrint("Esquema de autenticação não suportado");
        break;
      case WebResourceErrorType.unsupportedScheme:
        debugPrint("Esquema de URI não suportado");
        break;
      case WebResourceErrorType.webContentProcessTerminated:
        debugPrint("Processo da WebView encerrado");
        break;
      case WebResourceErrorType.webViewInvalidated:
        debugPrint("WebView inválida");
        break;
      case WebResourceErrorType.javaScriptExceptionOccurred:
        debugPrint("Erro em execução de JavaScript");
        break;
      case WebResourceErrorType.javaScriptResultTypeIsUnsupported:
        debugPrint("Resultado JS não suportado");
        break;
      default:
        debugPrint("❌ Erro não tratado: ${error.errorType}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SDK BeMall',
      home: Scaffold(
        body: Center(
          child: Builder(
            builder: (context) => Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  child: const Text('Abrir WebApp'),
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => WebAppViewPromotion(
                      customerId: '<CUSTOMER_ID>',
                      campaignHash: '<CAMPAIGN_HASH>',
                      customerAccessToken:
                          '<CUSTOMER_ACCESS_TOKEN>',
                      onClose: () => Navigator.of(context).pop(),
                      pageErrorNotifier: (error) =>{
                          debugPrint('error: ${error}'),
                          debugPrint('error description: ${error.description}'),
                          debugPrint('error errorCode: ${error.errorCode}'),
                          debugPrint('error errorType: ${error.errorType}')
                      },
                      pageLoadedNotifier: (loading) =>
                          debugPrint('booelan loading: $loading'),
                      showDebugButton: true,
                      ),
                    );
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

WebResourceError – Guia de Erros retornados pelo SDK #

Quando ocorre um erro de carregamento no WebView, o Flutter retorna um objeto WebResourceError.
Esse objeto contém informações sobre o problema, como:

  • errorCode: código cru vindo da plataforma (Android ou iOS).
  • description: texto descritivo do erro.
  • errorType: enum genérico fornecido pelo Flutter para categorizar o erro.
  • url: URL que falhou.

🔹 Propriedades principais #

class WebResourceError {
  final int errorCode;           // Código da plataforma (Android/iOS)
  final String description;      // Descrição do erro
  final WebResourceErrorType? errorType; // Tipo categorizado
  final String? url;             // URL que falhou
}

🔹 Enum WebResourceErrorType #

O Flutter mapeia alguns erros comuns para valores genéricos:

  • authentication → Falha de autenticação no servidor.
  • badUrl → URL malformada.
  • connect → Falha ao conectar ao servidor.
  • failedSslHandshake → Falha na negociação SSL/TLS.
  • file → Erro genérico de arquivo.
  • fileNotFound → Arquivo não encontrado.
  • hostLookup → DNS não encontrado.
  • io → Erro de leitura/escrita.
  • proxyAuthentication → Falha de autenticação em proxy.
  • redirectLoop → Loop de redirecionamento.
  • timeout → Conexão expirada.
  • tooManyRequests → Muitas requisições.
  • unknown → Erro genérico/desconhecido.
  • unsafeResource → Recurso inseguro bloqueado.
  • unsupportedAuthScheme → Esquema de autenticação não suportado.
  • unsupportedScheme → Esquema de URI não suportado.
  • webContentProcessTerminated → Processo da WebView encerrado.
  • webViewInvalidated → WebView inválida.
  • javaScriptExceptionOccurred → Erro em execução JS.
  • javaScriptResultTypeIsUnsupported → Resultado JS não suportado.

🔹 Códigos Android (WebView) #

Os erros seguem as constantes de WebViewClient (ERROR_*):

Código Constante Significado
-1 ERROR_UNKNOWN Erro desconhecido.
-2 ERROR_HOST_LOOKUP DNS/host não encontrado.
-3 ERROR_UNSUPPORTED_AUTH_SCHEME Autenticação não suportada.
-4 ERROR_AUTHENTICATION Falha de autenticação no servidor.
-5 ERROR_PROXY_AUTHENTICATION Falha de autenticação no proxy.
-6 ERROR_CONNECT Não conseguiu conectar.
-7 ERROR_IO Erro de I/O.
-8 ERROR_TIMEOUT Tempo limite esgotado.
-9 ERROR_REDIRECT_LOOP Loop de redirecionamento.
-10 ERROR_UNSUPPORTED_SCHEME Esquema de URI não suportado.
-11 ERROR_FAILED_SSL_HANDSHAKE Falha no handshake SSL/TLS.
-12 ERROR_BAD_URL URL malformada.
-13 ERROR_FILE Erro de arquivo.
-14 ERROR_FILE_NOT_FOUND Arquivo não encontrado.
-15 ERROR_TOO_MANY_REQUESTS Muitas requisições.

🔹 Códigos iOS (WKWebView) #

No iOS os erros seguem os códigos de NSURLErrorDomain:

Código Constante iOS Significado
-1000 NSURLErrorBadURL URL inválida.
-1001 NSURLErrorTimedOut Tempo limite esgotado.
-1002 NSURLErrorUnsupportedURL Esquema não suportado.
-1003 NSURLErrorCannotFindHost Host não encontrado.
-1004 NSURLErrorCannotConnectToHost Falha ao conectar ao host.
-1005 NSURLErrorNetworkConnectionLost Conexão perdida.
-1009 NSURLErrorNotConnectedToInternet Sem internet.
-1012 NSURLErrorUserCancelledAuthentication Autenticação cancelada.
-1013 NSURLErrorUserAuthenticationRequired Autenticação necessária.
-1200 NSURLErrorSecureConnectionFailed Falha SSL/TLS.
-1202 NSURLErrorServerCertificateUntrusted Certificado não confiável.
-1203 NSURLErrorServerCertificateHasBadDate Certificado expirado.
-1204 NSURLErrorServerCertificateNotYetValid Certificado ainda não válido.
-1205 NSURLErrorServerCertificateHasUnknownRoot Root desconhecida.
-1206 NSURLErrorServerCertificateRejected Certificado rejeitado.

🔹 Dicas práticas #

  • Use sempre errorType para lógica genérica entre Android/iOS.
  • Logue errorCode + description para debug detalhado.
  • No Android, espere -1 a -15.
  • No iOS, os erros ficam geralmente entre -1000 e -1200.

📌 Observações #

  • Garanta as permissões de internet e câmera:
    • Android: AndroidManifest.xml + runtime permissions.
    • iOS: adicionar NSCameraUsageDescription no Info.plist.
  • WebAppViewPromotion abre o WebApp BeMall em uma WebView embutida.
  • onClose deve executar o retorno à tela anterior (por exemplo, Navigator.pop()).

🔁 Atualizações do SDK #

Para atualizar:

  1. Substitua o conteúdo da pasta vendor/bemall-sdk/ pelo novo .zip extraído.
  2. Rode:
flutter clean
flutter pub get