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
- WebView: Componente que permite exibir conteúdo web dentro do aplicativo
- Token de Autenticação: Chave única para identificar e autenticar sua aplicação
- API Programática: Conjunto de funções para controlar a Rybená via código
- Comunicação Bidirecional: O aplicativo pode enviar comandos e receber respostas da Rybená
Passos Básicos
- Criar um objeto WebView (grande disponibilidade desse tipo de componente em diversas linguagens mobile)
- Carregar o conteúdo da Rybená na WebView
- Manipular o tamanho da Rybená
- Abrir o player da Rybená quando for conveniente
- 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-webviewImplementaçã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.0Implementaçã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
- Entre em contato com a equipe da Rybená
- Forneça informações sobre seu aplicativo
- Receba seu token de acesso único
- 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