Adicionando um componente Beagle Server-driven

Esta seção descreve como adicionar um componente Server Driven a uma tela nativa

É possível que alguns componentes de uma tela que sejam exibidos via server-driven (tela nativa) recebam somente uma seção da página , ou mesmo um único componente do servidor BFF.

No exemplo abaixo, vamos exibir um botão server-driven em uma tela nativa. O resultado que deve aparecer na sua aplicação é esse:

Pré-requisitos

Para que essa configuração funcione corretamente, você precisa de:

  • Um BFF configurado com o Beagle. Caso não o tenha, veja como configurar nesse tutorial.
  • Um frontend configurado com o Beagle para Android ou iOS. Caso não o tenha, siga um dos tutoriais de acordo com sistema operacional:

Passo 1: Criar o componente no backend

Neste exemplo, criaremos um botão como componente server-driven para que possamos exibí-lo em uma tela nativa.

Para isso, siga os passos a seguir:

  1. Crie uma classe Kotlin em seu backend.
  2. Nomeie-o SingleComponentBuilder. Essa será a classe que vai construir o seu componente (objeto) server-driven.
  3. Feito isso, copie e cole o código abaixo.
import br.com.zup.beagle.widget.action.Alert
import br.com.zup.beagle.widget.ui.Button

class SingleComponentBuilder() {

  fun createButton(): Button {
    return Button(
        "I'm a server-based button",
        onPress = listOf(
            Alert(
                "Server-driven Button",
                "I'm a server-based button",
                labelOk = "OoooK"
            )
        )
    )
  }
}

Passo 2: Atualizar a classe Service e Controller no backend

Depois que você criou o componente, será preciso atualizar algumas classes. Veja como fazer essa configuração de acordo com cada uma delas.

Atualizando o Service

O Service é a classe responsável por configurar o serviço que usaremos, que pode ser de vários tipos. No caso desse exemplo, só será listado o que está sendo configurando.

Comece abrindo a classe ScreenBeagleService.kt (nome escolhido para o tutorial de configuração do BFF, mas você pode renomeá-la se quiser).

Feito isso, copie a linha abaixo e cole dentro da classe ScreenBeagleService:

  • fun createServerDrivenComponent() = SingleComponentBuilder().createButton()
import com.example.bff.builder.SingleComponentBuilder
import org.springframework.stereotype.Service

@Service
class ScreenBeagleService {
    fun createServerDrivenComponent() = SingleComponentBuilder().createButton()
}

Atualizando Controller

Se a configuração acima funcionar, você atualizará o controller e o componente e eles estarão prontos para serem enviados ao frontend, caso haja uma requisição.

Agora, na classe controller, você deve chamar o serviço que acabamos de configurar e definir a URL que será o endpoint do componente criado.

Para isso, siga os passos:

  1. Abra a classeScreenController. Esse nome foi dado a essa classe no tutorial, ela que é responsável por expor os componentes via API REST.
  2. Adicione outra função à essa classe (Lembrando que a classe já tem algumas funções implementadas).
  3. Anote a função com o @GetMapping()e listar o endpoint (Path relativo da URL) que identifica esse componente.

Veja como deve ficar a configuração:

@RestController
class ScreenController(
        private val screenBeagleService: BeagleService
) {

  @GetMapping("/serverDrivenComponent")
  fun getServerDrivenComponent() = screenBeagleService.createServerDrivenComponent()
}

Teste o endpoint

Agora que o componente esta criado e configurado, você deve testar o endpoint e verificar a resposta JSON. Para isso, realize essas ações:

  1. Inicie a sua aplicação no backend (Lembre-se que sua aplicação Backend está configurada para apresentar as resposta no localhost).
  2. Abra o um browser e acesse o endpoint: http://localhost:8080/serverDrivenComponent

Você deve receber o JSON abaixo:

{
  "_beagleComponent_" : "beagle:button",
  "text" : "I'm a server-based button",
  "onPress" : [ {
    "_beagleAction_" : "beagle:alert",
    "title" : "Server-driven Button",
    "message" : "I'm a server-based button",
    "labelOk" : "OoooK"
  } ]
}
Button(
    "I'm a server-based button",
    onPress = listOf(
        Alert(
            "Server-driven Button",
            "I'm a server-based button",
            labelOk = "OoooK"
        )
    )
)

Passo 3: Exibir o componente server-driven

Depois dos dois passos anteriores, o seu componente está pronto. Agora, você só precisa exibi-lo em uma tela nativa.

Para essa configuração, siga as orientações específicas para cada plataforma:

Você deve utilizar o frame layout para “receber” o componente do BFF e, assim, exibi-lo em uma tela Android nativa.

Para isso, basta seguir esses passos:

  • Crie o arquivo .XML abaixo que representa uma tela nativa com um título e um frame layout. Nesse exemplo definimos essa pagina como nossa MainActivity
  • Depois, copie e cole a configuração abaixo:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="Sou componente Nativo!"
        android:textSize="30sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:id="@+id/fr_server_driven"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        app:layout_constraintTop_toBottomOf="@id/tv_title"
        android:layout_marginTop="40dp"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

O que é loadView?

O método loadView é responsável carregar seu conteúdo beagle dentro de sua view.

A estrutura do loadView é:

AtributoTipoObrigatórioDefinição
activityAppCompatActivity/FragmentDefine a activity ou fragment que estamos usando o loadview
screenRequestScreenRequestDefine os parâmetros para a chamada da tela remota
listenerOnServerStateChanged = (serverState: ServerDrivenState) -> UnitDefine o o listener que configura os callbacks para os estados da tela


Veja como fazer isso:

  1. Abra a activity onde você deseja exibir a sua tela nativa.
  2. Crie uma variável do tipo FrameLayout que deve receber a FrameLayout View que configuramos.
  3. Agora basta chamar a função .loadView a partir da variável frameLayout
val frameLayout = findViewById<FrameLayout>(R.id.fr_server_driven)
frameLayout.loadView(this, ScreenRequest("/serverDrivenComponent"))

E pronto: basta iniciar sua aplicação e você verá a tela a seguir!

Clique no botão e perceba que a função nesse componente está implementada e funcional, ou seja, o Beagle exibe todos os componentes como se fossem nativos.

Você deve utilizar uma BeagleView para “colocar” esse componente do BFF e, assim, exibí-lo em uma tela iOS nativa.

  1. Crie um UIViewController.
  2. Adicione o componente nativo, nesse caso será um texto utilizando uma UILabel.
  3. Crie uma BeagleView passando a URL pretendida.
  4. Por último, é necessário adicionar algumas constraints para a UILabel e para BeagleView como no código abaixo:
class NativeViewController: UIViewController {

     override func viewDidLoad() {
        super.viewDidLoad()
        setupBeagleViewRemote()
        setupDescriptionText()
    }

    private lazy var beagleViewRemote = BeagleView(
        .remote(.init(url: "http://localhost:8080/serverDrivenComponent"))
    )

    private lazy var descriptionText: UILabel = {
            let label = UILabel()
            label.text = "Sou um componente nativo"
            label.numberOfLines = 0
            label.textAlignment = .center
            label.font = .systemFont(ofSize: 25, weight: .semibold)
            return label
    }()

    private func setupDescriptionText() {
        view.addSubview(descriptionText)
        descriptionText.translatesAutoresizingMaskIntoConstraints = false
        descriptionText.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        descriptionText.topAnchor.constraint(equalTo: view.topAnchor, constant: 150).isActive = true
    }

    private func setupBeagleViewRemote() {
        view.addSubview(beagleViewRemote)
        beagleViewRemote.translatesAutoresizingMaskIntoConstraints = false
        beagleViewRemote.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        beagleViewRemote.topAnchor.constraint(equalTo: descriptionText.bottomAnchor, constant: 50).isActive = true
    }

Ao final do processo, você poderá “chamar” a tela nativa e a imagem abaixo irá aparecer. Lembrando que, para esse exemplo, foram criadas: uma tela composta de uma UILabel e uma BeagleView , onde fica o componente server-driven.

Se você ainda não configurou a biblioteca em seu projeto, veja aqui como fazer isso.

Você deve utilizar o Remote View, fornecido pela biblioteca do Beagle, para criar telas híbridas com alguns componentes server driven na web.

Veja a seguir como funciona para cada framework:

React

No React, você só precisa criar uma função que retorna dois componentes. Um deles é o BeagleRemoteView com o caminho para carregar o componente server-driven.

import React, { FC } from "react";
import { LoadParams } from "@zup-it/beagle-web";
import { BeagleProvider, BeagleRemoteView } from "@zup-it/beagle-react";
import BeagleService from "../../beagle/beagle.service";
import NativeComponent from "../NativeComponent";

const params: LoadParams = {
  path: "/mypath",
};

const Main = () => {
  return (
    <>
      <NativeComponent text="Sou um componente nativo!"></NativeComponent>
      <BeagleProvider value={BeagleService}>
        <BeagleRemoteView {...params} />
      </BeagleProvider>
    </>
  );
};

export default Main;

Angular

No Angular, basta criar um componente nativo normalmente e adicionar o beagle-remote-view junto ao template no local que você quer que os itens server-driven sejam renderizados.

<app-native-component text="Sou um componente nativo"></app-native-component>
<beagle-remote-view [loadParams]="loadParams"></beagle-remote-view>

A sua tela híbrida com elementos nativos e server driven está pronta