Rybená Logo

Integração com Aplicativos Móveis

A Rybená pode ser integrada em aplicativos móveis através de uma WebView, permitindo controle programático completo através da API. Esta abordagem oferece flexibilidade máxima para integrar a solução de acessibilidade em seu aplicativo.

Visão Geral

O fluxo de integração entre a Rybená e aplicativos é realizado através de incorporação de uma WebView com comandos facilitados para manipular a aplicação.

Nas integrações com aplicativos, entendemos que a forma de interação entre o usuário e o sistema é bastante diversa e dinâmica, muito diferente do cenário web, em que o usuário controla suas ações por seleções e cliques.

Por isso, entendemos que a melhor forma de entregar essa integração é através de maneira programática, para que cada aplicativo diga a Rybená quando traduzir e qual texto seja traduzido. Dessa forma, todas as funções de API estarão disponíveis na WebView da Rybená.

Integração por Incorporação

Na integração por incorporação, o aplicativo de origem incorpora o aplicativo Rybená dentro dele, ou seja, diferentemente da outra solução, não é necessário abrir outro aplicativo ou ter o aplicativo Rybená instalado.

Conceitos Básicos

  1. WebView: Componente que permite exibir conteúdo web dentro do aplicativo
  2. Token de Autenticação: Chave única para identificar e autenticar sua aplicação
  3. API Programática: Conjunto de funções para controlar a Rybená via código
  4. Comunicação Bidirecional: O aplicativo pode enviar comandos e receber respostas da Rybená

Passos Básicos

  1. Criar um objeto WebView (grande disponibilidade desse tipo de componente em diversas linguagens mobile)
  2. Carregar o conteúdo da Rybená na WebView
  3. Manipular o tamanho da Rybená
  4. Abrir o player da Rybená quando for conveniente
  5. Manipular todas as funcionalidades disponíveis através das Funções de API

Integração por Framework

React Native

A integração com React Native é simples e direta, utilizando o componente WebView.

Instalação

Primeiro, instale o pacote react-native-webview:

npm install react-native-webview
# ou
yarn add react-native-webview

Implementação Básica

import React, { useRef } from 'react';
import { View, StyleSheet, Button } from 'react-native';
import { WebView } from 'react-native-webview';

export default function RybenáIntegration() {
  const webViewRef = useRef<WebView>(null);
  
  // URL da WebView da Rybená com seu token de autenticação
  const rybenaUrl = 'https://repository.rybena.com.br/webview/index.html?token=SEU-TOKEN-AQUI';
  
  // Função para manipular o tamanho da Rybená
  const setSize = (size: number) => {
    webViewRef.current?.injectJavaScript(`
      RybenaApi.getInstance().setSize(${size});
      true;
    `);
  };
  
  // Função para abrir o player
  const openPlayer = () => {
    webViewRef.current?.injectJavaScript(`
      RybenaApi.getInstance().openPlayer();
      true;
    `);
  };
  
  // Função para fechar o player
  const closePlayer = () => {
    webViewRef.current?.injectJavaScript(`
      RybenaApi.getInstance().closePlayer();
      true;
    `);
  };
  
  return (
    <View style={styles.container}>
      <WebView
        ref={webViewRef}
        source={{ uri: rybenaUrl }}
        style={styles.webview}
        javaScriptEnabled={true}
        domStorageEnabled={true}
      />
      
      <View style={styles.controls}>
        <Button title="Definir Tamanho (300px)" onPress={() => setSize(300)} />
        <Button title="Abrir Player" onPress={openPlayer} />
        <Button title="Fechar Player" onPress={closePlayer} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  webview: {
    flex: 1,
  },
  controls: {
    padding: 20,
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#f5f5f5',
  },
});

Exemplo Completo

Temos um exemplo de integração da Rybená em um aplicativo mobile utilizando React Native e Expo. Você pode acessar o repositório do exemplo aqui.

Funções da API Disponíveis

// Traduzir texto específico
const translateText = (text: string) => {
  webViewRef.current?.injectJavaScript(`
    RybenaApi.getInstance().translateText('${text}');
    true;
  `);
};

// Traduzir elemento por ID
const translateElement = (elementId: string) => {
  webViewRef.current?.injectJavaScript(`
    RybenaApi.getInstance().translateElement('${elementId}');
    true;
  `);
};

// Definir idioma
const setLanguage = (lang: string) => {
  webViewRef.current?.injectJavaScript(`
    RybenaApi.getInstance().setLanguage('${lang}');
    true;
  `);
};

// Obter estado atual
const getState = () => {
  webViewRef.current?.injectJavaScript(`
    const state = RybenaApi.getInstance().getState();
    window.ReactNativeWebView.postMessage(JSON.stringify(state));
    true;
  `);
};

Flutter

A integração com Flutter utiliza o pacote webview_flutter.

Instalação

Adicione o pacote ao seu pubspec.yaml:

dependencies:
  webview_flutter: ^4.0.0

Implementação Básica

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

class RybenáIntegration extends StatefulWidget {
  @override
  _RybenáIntegrationState createState() => _RybenáIntegrationState();
}

class _RybenáIntegrationState extends State<RybenáIntegration> {
  late WebViewController _controller;
  
  // URL da WebView da Rybená com seu token de autenticação
  final String rybenaUrl = 'https://repository.rybena.com.br/webview/index.html?token=SEU-TOKEN-AQUI';
  
  @override
  void initState() {
    super.initState();
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageFinished: (String url) {
            // WebView carregada com sucesso
          },
        ),
      )
      ..loadRequest(Uri.parse(rybenaUrl));
  }
  
  // Função para manipular o tamanho da Rybená
  Future<void> setSize(int size) async {
    await _controller.runJavaScript(
      'RybenaApi.getInstance().setSize($size);'
    );
  }
  
  // Função para abrir o player
  Future<void> openPlayer() async {
    await _controller.runJavaScript(
      'RybenaApi.getInstance().openPlayer();'
    );
  }
  
  // Função para fechar o player
  Future<void> closePlayer() async {
    await _controller.runJavaScript(
      'RybenaApi.getInstance().closePlayer();'
    );
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Rybená Integration')),
      body: Column(
        children: [
          Expanded(
            child: WebViewWidget(controller: _controller),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                ElevatedButton(
                  onPressed: () => setSize(300),
                  child: Text('Definir Tamanho'),
                ),
                ElevatedButton(
                  onPressed: openPlayer,
                  child: Text('Abrir Player'),
                ),
                ElevatedButton(
                  onPressed: closePlayer,
                  child: Text('Fechar Player'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Funções da API Disponíveis

// Traduzir texto específico
Future<void> translateText(String text) async {
  await _controller.runJavaScript(
    "RybenaApi.getInstance().translateText('$text');"
  );
}

// Traduzir elemento por ID
Future<void> translateElement(String elementId) async {
  await _controller.runJavaScript(
    "RybenaApi.getInstance().translateElement('$elementId');"
  );
}

// Definir idioma
Future<void> setLanguage(String lang) async {
  await _controller.runJavaScript(
    "RybenaApi.getInstance().setLanguage('$lang');"
  );
}

// Obter estado atual
Future<void> getState() async {
  final result = await _controller.runJavaScriptReturningResult(
    'JSON.stringify(RybenaApi.getInstance().getState());'
  );
  print('Estado: $result');
}

Android Nativo (Kotlin)

A integração com Android nativo utiliza o componente WebView.

Implementação Básica

import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity

class RybenáIntegration : AppCompatActivity() {
    private lateinit var webView: WebView
    
    // URL da WebView da Rybená com seu token de autenticação
    private val rybenaUrl = "https://repository.rybena.com.br/webview/index.html?token=SEU-TOKEN-AQUI"
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rybena)
        
        webView = findViewById(R.id.webview)
        setupWebView()
    }
    
    private fun setupWebView() {
        webView.apply {
            settings.javaScriptEnabled = true
            settings.domStorageEnabled = true
            webViewClient = WebViewClient()
            loadUrl(rybenaUrl)
        }
    }
    
    // Função para manipular o tamanho da Rybená
    fun setSize(size: Int) {
        webView.evaluateJavascript(
            "RybenaApi.getInstance().setSize($size);",
            null
        )
    }
    
    // Função para abrir o player
    fun openPlayer() {
        webView.evaluateJavascript(
            "RybenaApi.getInstance().openPlayer();",
            null
        )
    }
    
    // Função para fechar o player
    fun closePlayer() {
        webView.evaluateJavascript(
            "RybenaApi.getInstance().closePlayer();",
            null
        )
    }
    
    // Traduzir texto específico
    fun translateText(text: String) {
        webView.evaluateJavascript(
            "RybenaApi.getInstance().translateText('$text');",
            null
        )
    }
}

Layout XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp">
        
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Definir Tamanho"
            android:onClick="setSize" />
        
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Abrir Player"
            android:onClick="openPlayer" />
        
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Fechar Player"
            android:onClick="closePlayer" />
    </LinearLayout>
</LinearLayout>

iOS Nativo (Swift)

A integração com iOS nativo utiliza o componente WKWebView.

Implementação Básica

import UIKit
import WebKit

class RybenáIntegration: UIViewController {
    private var webView: WKWebView!
    
    // URL da WebView da Rybená com seu token de autenticação
    private let rybenaUrl = "https://repository.rybena.com.br/webview/index.html?token=SEU-TOKEN-AQUI"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
        setupUI()
    }
    
    private func setupWebView() {
        let contentController = WKUserContentController()
        let configuration = WKWebViewConfiguration()
        configuration.userContentController = contentController
        
        webView = WKWebView(frame: .zero, configuration: configuration)
        webView.navigationDelegate = self
        
        if let url = URL(string: rybenaUrl) {
            webView.load(URLRequest(url: url))
        }
    }
    
    private func setupUI() {
        view.addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            webView.topAnchor.constraint(equalTo: view.topAnchor),
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100)
        ])
        
        // Adicionar botões de controle
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.distribution = .fillEqually
        stackView.spacing = 10
        
        let setSizeButton = UIButton(type: .system)
        setSizeButton.setTitle("Definir Tamanho", for: .normal)
        setSizeButton.addTarget(self, action: #selector(setSize), for: .touchUpInside)
        
        let openPlayerButton = UIButton(type: .system)
        openPlayerButton.setTitle("Abrir Player", for: .normal)
        openPlayerButton.addTarget(self, action: #selector(openPlayer), for: .touchUpInside)
        
        let closePlayerButton = UIButton(type: .system)
        closePlayerButton.setTitle("Fechar Player", for: .normal)
        closePlayerButton.addTarget(self, action: #selector(closePlayer), for: .touchUpInside)
        
        stackView.addArrangedSubview(setSizeButton)
        stackView.addArrangedSubview(openPlayerButton)
        stackView.addArrangedSubview(closePlayerButton)
        
        view.addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
            stackView.heightAnchor.constraint(equalToConstant: 50)
        ])
    }
    
    // Função para manipular o tamanho da Rybená
    @objc func setSize() {
        webView.evaluateJavaScript("RybenaApi.getInstance().setSize(300);")
    }
    
    // Função para abrir o player
    @objc func openPlayer() {
        webView.evaluateJavaScript("RybenaApi.getInstance().openPlayer();")
    }
    
    // Função para fechar o player
    @objc func closePlayer() {
        webView.evaluateJavaScript("RybenaApi.getInstance().closePlayer();")
    }
    
    // Traduzir texto específico
    func translateText(_ text: String) {
        webView.evaluateJavaScript("RybenaApi.getInstance().translateText('\(text)');")
    }
}

extension RybenáIntegration: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // WebView carregada com sucesso
    }
}

Autenticação

Token de Acesso

Para integrar a Rybená em seu aplicativo, você precisa de um token de acesso único. Este token é usado para autenticar sua aplicação e garantir que apenas aplicativos autorizados possam acessar a Rybená.

Como Obter o Token

  1. Entre em contato com a equipe da Rybená
  2. Forneça informações sobre seu aplicativo
  3. Receba seu token de acesso único
  4. Use o token na URL da WebView

Exemplo de Uso do Token

// URL da WebView com token
const rybenaUrl = 'https://repository.rybena.com.br/webview/index.html?token=SEU-TOKEN-AQUI';

Nunca compartilhe seu token de acesso publicamente. Mantenha-o seguro e use apenas em seu aplicativo.

API Programática

Funções Principais

A Rybená oferece diversas funções para controle programático:

Tamanho e Posição

// Definir tamanho do player
RybenaApi.getInstance().setSize(300);

// Definir posição do player
RybenaApi.getInstance().setPosition('right');

Controle do Player

// Abrir o player
RybenaApi.getInstance().openPlayer();

// Fechar o player
RybenaApi.getInstance().closePlayer();

// Alternar o player
RybenaApi.getInstance().togglePlayer();

Tradução

// Traduzir texto específico
RybenaApi.getInstance().translateText('Texto para traduzir');

// Traduzir elemento por ID
RybenaApi.getInstance().translateElement('element-id');

// Traduzir toda a página
RybenaApi.getInstance().translatePage();

Idioma

// Definir idioma
RybenaApi.getInstance().setLanguage('ptBR');

// Obter idioma atual
const currentLang = RybenaApi.getInstance().getLanguage();

Estado

// Obter estado atual
const state = RybenaApi.getInstance().getState();

// Verificar se o player está aberto
const isOpen = RybenaApi.getInstance().isPlayerOpen();

Comunicação Bidirecional

Você pode receber mensagens da Rybená de volta para seu aplicativo:

React Native

<WebView
  ref={webViewRef}
  source={{ uri: rybenaUrl }}
  onMessage={(event) => {
    const data = JSON.parse(event.nativeEvent.data);
    console.log('Mensagem da Rybená:', data);
  }}
/>

Flutter

WebViewWidget(
  controller: WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..addJavaScriptChannel(
      'RybenáChannel',
      onMessageReceived: (JavaScriptMessage message) {
        final data = jsonDecode(message.message);
        print('Mensagem da Rybená: $data');
      },
    )
    ..loadRequest(Uri.parse(rybenaUrl)),
)

Solução de Problemas

Melhores Práticas

Gerenciamento de Estado

  • Mantenha o estado da Rybená sincronizado com o estado do aplicativo
  • Use callbacks para receber atualizações da Rybená
  • Implemente tratamento de erros adequado

Performance

  • Carregue a WebView apenas quando necessário
  • Use lazy loading para conteúdo pesado
  • Implemente cache quando apropriado

Segurança

  • Nunca exponha seu token de acesso
  • Valide todas as mensagens recebidas da Rybená
  • Implemente autenticação adicional quando necessário

Experiência do Usuário

  • Forneça feedback visual para ações do usuário
  • Implemente estados de carregamento
  • Trate erros de forma amigável

Recursos Adicionais

Conteúdo Relacionado

Nesta página