React Native permite que você crie aplicativos Android com aparência e comportamento nativos usando apenas JavaScript. Nesse caso, o React Native se encarrega de gerenciar o estado da interface do usuário e sincronizá-lo com os modelos. E, para nossa sorte, podemos usar o Couchbase Lite para adicionar sincronização e persistência a um aplicativo React Native. Neste tutorial, você aprenderá a criar um aplicativo simples para salvar documentos e replicá-los para Gateway de sincronização. Aqui estão os principais conceitos que você aprenderá:
- Criar um projeto básico com o Couchbase Lite Android e o Couchbase Lite Java Listener
- Integração do React Native em seu projeto
- Adição de modelos e componentes de interface do usuário com JavaScript
- Configuração do Couchbase Sync Gateway
Aqui está uma prévia do que você vai construir:

Você pode fazer o download do projeto concluído em GitHub.
Pré-requisitos
- Node.js 4.0 ou superior
- Estúdio Android e um emulador
Primeiros passos
Nesta seção, você criará um novo projeto do Android Studio do zero e integrar o React Native a ele.
Novo projeto do Android Studio
Antes de começar a escrever algum JavaScript, você precisa criar um novo projeto no Android Studio com todas as dependências. Abra o Android Studio e, na tela de boas-vindas, selecione Novo projeto. Na janela Novo projeto, digite TodoLite ReactNative Android para o nome do aplicativo e todolite-reactnative-android para o nome da pasta:

Defina o SDK mínimo necessário como API 16: Android 4.1 ou posterior e usar a API do Android recomendada atualmente. Depois de preencher os campos, a janela New Project deverá ter a seguinte aparência:

Clique em Next e escolha a opção Atividade em branco modelo:


Clique em Acabamento e você deverá ver o seguinte no navegador de projetos:

Agrupamento de dependências
Expanda a pasta do aplicativo e abra a pasta build.gradle arquivo. Certifique-se de abrir o arquivo localizado no diretório aplicativo (também chamada de módulo) e adicione o seguinte na pasta androide seção:
|
1 2 3 4 5 6 7 |
// workaround for "duplicate files during packaging of APK" issue // see https://groups.google.com/d/msg/adt-dev/bl5Rc4Szpzg/wC8cylTWuIEJ packagingOptions { exclude 'META-INF/ASL2.0' exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' } |
Em seguida, abra build.gradle na raiz (também chamado de arquivo gradle no nível do projeto) e adicione uma referência ao repositório Maven do Couchbase:
|
1 2 3 4 5 6 7 8 |
allprojects { repositories { jcenter() maven { url "https://files.couchbase.com/maven2/" } } } |
Agora, adicione as seguintes linhas ao nível superior dependências seção:
|
1 2 3 4 5 6 7 8 9 10 |
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.0' compile 'com.couchbase.lite:couchbase-lite-android:1.1.0' compile 'com.couchbase.lite:couchbase-lite-java-listener:1.1.0' compile 'com.couchbase.lite:couchbase-lite-java-javascript:1.1.0' compile 'com.facebook.react:react-native:0.13.0' } |
Na barra de ferramentas do Android Studio, clique em Sync Project with Gradle Files (Sincronizar projeto com arquivos Gradle).
Configuração do Couchbase Lite e do Listener
Aberto AndroidManifest.xml localizado em app/src/main e adicione as permissões:
|
1 2 3 |
A atividade do React Native para Android
Você precisa adicionar algum código nativo para iniciar o tempo de execução do React Native e fazer com que ele renderize algo. Substitua o conteúdo de MainActivity.java com o seguinte e explicaremos o que está acontecendo a seguir:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; private final String TAG = "TodoLite"; private static final int DEFAULT_LISTEN_PORT = 5984; private int listenPort; private Credentials allowedCredentials; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate method called"); // 1 mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication(mReactInstanceManager, "TodoLite-ReactNative-Android", null); setContentView(mReactRootView); initCBLite(); } private void initCBLite() { try { // 2 allowedCredentials = new Credentials("", ""); // 3 View.setCompiler(new JavaScriptViewCompiler()); // 4 AndroidContext context = new AndroidContext(this); Manager.enableLogging(Log.TAG, Log.VERBOSE); Manager.enableLogging(Log.TAG_SYNC, Log.VERBOSE); Manager.enableLogging(Log.TAG_QUERY, Log.VERBOSE); Manager.enableLogging(Log.TAG_VIEW, Log.VERBOSE); Manager.enableLogging(Log.TAG_CHANGE_TRACKER, Log.VERBOSE); Manager.enableLogging(Log.TAG_BLOB_STORE, Log.VERBOSE); Manager.enableLogging(Log.TAG_DATABASE, Log.VERBOSE); Manager.enableLogging(Log.TAG_LISTENER, Log.VERBOSE); Manager.enableLogging(Log.TAG_MULTI_STREAM_WRITER, Log.VERBOSE); Manager.enableLogging(Log.TAG_REMOTE_REQUEST, Log.VERBOSE); Manager.enableLogging(Log.TAG_ROUTER, Log.VERBOSE); Manager manager = new Manager(context, Manager.DEFAULT_OPTIONS); // 5 listenPort = startCBLListener(DEFAULT_LISTEN_PORT, manager, allowedCredentials); Log.i(TAG, "initCBLite() completed successfully with: " + String.format( "https://%s:%s@localhost:%d/", allowedCredentials.getLogin(), allowedCredentials.getPassword(), listenPort)); } catch (final Exception e) { e.printStackTrace(); } } private int startCBLListener(int listenPort, Manager manager, Credentials allowedCredentials) { LiteListener listener = new LiteListener(manager, listenPort, allowedCredentials); int boundPort = listener.getListenPort(); Thread thread = new Thread(listener); thread.start(); return boundPort; } @Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onPause(); } } @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onResume(this); } } @Override public void onBackPressed() { if (mReactInstanceManager != null) { mReactInstanceManager.onBackPressed(); } else { super.onBackPressed(); } } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { mReactInstanceManager.showDevOptionsDialog(); return true; } return super.onKeyUp(keyCode, event); } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } } |
Algumas coisas estão acontecendo aqui:
- Você cria uma atividade que cria um
ReactRootViewinicia um aplicativo React dentro dele e o define como a exibição de conteúdo principal. Em seguida, você está chamando a funçãoinitCBLiteque faz algumas coisas. - Aqui você define um nome e uma senha vazios a serem usados pelo Listener. Isso significa que, em teoria, qualquer pessoa poderia acessar seu banco de dados. Isso é aceitável para este tutorial, mas na produção você substituiria a linha por
novas Credenciais(). - Conecte o componente para compilar as visualizações JavaScript. Ainda não usaremos as visualizações do Couchbase neste tutorial, mas elas podem ser úteis.
- Instanciar o
Gerentee ativar o registro. - Inicie o Couchbase Listener informando a porta de escuta, a instância do gerenciador e as credenciais seguras.
Isso é tudo para a parte do Android, agora você pode voltar sua atenção para o JavaScript!
Terra do JavaScript
Na pasta raiz de seu projeto, execute:
|
1 2 3 |
$ npm init $ npm install --save react-native $ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig |
Isso cria um módulo de nó para seu aplicativo e adiciona a dependência npm react-native. Agora, abra o módulo package.json e adicione esta linha dentro do arquivo roteiros campo:
|
1 |
"start": "node_modules/react-native/packager/packager.sh" |
Olá mundo
Copie e cole o código a seguir em um novo arquivo index.android.js em sua pasta raiz:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/** * Sample React Native App * https://github.com/facebook/react-native */ 'use strict'; var React = require('react-native'); var Home = require('./app/components/Home'); var { AppRegistry, StyleSheet, Text, View, ToolbarAndroid } = React; var styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#111111' }, toolbar: { backgroundColor: '#e9eaed', height: 56, } }); var TodoLite = React.createClass({ render: function() { return ( ); } }); AppRegistry.registerComponent('TodoLite-ReactNative-Android', () => TodoLite); |
Construir e executar!
Para executar seu aplicativo, primeiro você precisa iniciar o servidor de desenvolvimento. Para fazer isso, basta executar o seguinte comando em sua pasta raiz:
|
1 |
npm start |
OBSERVAÇÃO: No momento da redação deste texto, talvez seja necessário executar brew update && brew reinstall watchman para atualizar o watchman se você receber o erro Erro ao construir o DepdendencyGraph: TypeError: Não é possível ler a propriedade 'root' de null.
Agora, crie e execute seu aplicativo Android em uma nova guia do Terminal:
|
1 |
./gradlew installDebug |
Abra-o no simulador do Android e você verá o seguinte:

Parabéns por ter colocado o ambiente de desenvolvimento em funcionamento! O React Native inclui excelentes recursos, como o live reload, que facilitam muito a iteração na interface do usuário do aplicativo, mas primeiro você deve definir os modelos e métodos para persistir os documentos no banco de dados do Couchbase Lite.
Um aplicativo Todo
Uma API simples
Criar um novo arquivo app/utils/api.js e adicione o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
var api = { // 1 localDatabaseUrl: 'https://localhost:5984', // 2 remoteDatabaseUrl: 'https://localhost:4984', // 3 saveTodo(title){ return fetch(this.localDatabaseUrl + '/todos', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'list', title: title }) }).then((res) => res.json()); }, // 4 getTodos(){ return fetch(this.localDatabaseUrl + '/todos/_all_docs?include_docs=true').then((response) => { if (response.status !== 200) { return fetch(this.localDatabaseUrl + '/todos', { method: 'put', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ok: true}) }).then((res) => res.json()); } return response.json(); }) }, // 5 startSync(){ return fetch(this.localDatabaseUrl + '/_replicate', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source: 'todos', target: this.remoteDatabaseUrl + '/todos', continuous: true }) }).then((res) => res.json()); } }; module.exports = api; |
Aqui está o que você está fazendo:
- Você declara o ponto de extremidade no qual o Couchbase Listener está sendo executado.
- Nesse caso, o banco de dados remoto é o Sync Gateway. Ele seria substituído por sua instância de produção do Sync Gateway.
- O método para manter um documento de tarefa.
- Aqui, você está obtendo todos os documentos do Couchbase Lite.
- Inicie uma replicação push do banco de dados do Couchbase Lite para o Sync Gateway. Também pode haver uma replicação pull.
Com uma API básica implementada, agora você pode voltar sua atenção para a criação da interface do usuário.
Criação da interface do usuário
Crie um novo arquivo em app/componentes/Home.js com o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
var React = require('react-native'); var api = require('./../utils/api'); var { Text, View, StyleSheet, ScrollView, TextInput, TouchableOpacity } = React; var styles = StyleSheet.create({ container: { flex: 1 }, buttonText: { fontSize: 18, color: 'white', alignSelf: 'center' }, rowContainer: { padding: 10 }, rowTitle: { color: '#48BBEC', fontSize: 16 }, rowContent: { fontSize: 19 }, mainContainer: { flex: 1, padding: 30, marginTop: 65, flexDirection: 'column', justifyContent: 'center', backgroundColor: '#48BBEC' }, searchInput: { height: 50, padding: 4, marginRight: 5, fontSize: 23, borderWidth: 1, borderColor: 'white', borderRadius: 8, color: 'white', margin: 5 }, buttonText: { fontSize: 18, color: '#111', alignSelf: 'center' }, button: { height: 45, flexDirection: 'row', backgroundColor: 'white', borderColor: 'white', borderWidth: 1, borderRadius: 8, marginBottom: 10, marginTop: 10, alignSelf: 'stretch', justifyContent: 'center' }, }); class Home extends React.Component { constructor(props) { super(props); this.state = { newTodo: '', todos: [] }; } componentWillMount() { api.getTodos() .then((res) => { var todos = res.rows.map(function (row) { return row.doc; }); this.setState({ todos: todos }); }); } handleTodoChange(event) { this.setState({ newTodo: event.nativeEvent.text }); } handleSave() { api.saveTodo(this.state.newTodo) .then((res) => { api.getTodos() .then((res) => { var todos = res.rows.map(function (row) { return row.doc; }); this.refs.inputText.value = ''; this.setState({ todos: todos, newTodo: '' }); }); }); } handleSync() { api.startSync() .then(function(res) { console.log(res); }); } render() { var lists = this.state.todos.map((item, index) => { return ( {item.title} ); }); return ( Save Sync {lists} ); } } Home.propTypes = { lists: React.PropTypes.array.isRequired }; module.exports = Home; |
Não se deixe intimidar pelo tamanho desse trecho de código. Tudo o que estamos fazendo aqui é declarar estilos e usar alguns componentes de IU do React Native incorporados para exibir uma entrada de texto, botões e rótulos de texto. Você pode encontrar a lista de componentes de IU incorporados aqui.
Atualização do componente raiz
A etapa final para que você possa ver seu excelente trabalho em ação é atualizar index.android.js para carregar o Início componente. Abaixo do exigir para importar react-nativoAdicione o seguinte:
|
1 |
var Home = require('./app/components/Home'); |
Em seguida, substitua o valor de retorno do renderizar método com . Use o ⌘ + m no Genymotion para recarregar o JavaScript e você verá uma tela azul brilhante. Essa é uma boa notícia!

Replicações com o Couchbase Sync Gateway
Faça o download do Sync Gateway no link abaixo e descompacte o arquivo:
https://www.couchbase.com/nosql-databases/downloads
Em um novo arquivo chamado sync-gateway-config.json, cole o seguinte:
|
1 2 3 4 5 6 7 8 9 |
{ "log": ["*"], "databases": { "todos": { "server": "walrus:", "users": { "GUEST": { "disabled": false, "admin_channels": ["*"] } } } } } |
E execute o Sync Gateway com esse arquivo de configuração:
|
1 |
~/Downloads/couchbase-sync-gateway/bin/sync_gateway /path/to/project/sync-gateway-config.json |
Para tornar o ponto de extremidade do Sync Gateway acessível dentro do emulador de VM do Android, você precisa ativar uma porta do host para a VM. No Terminal, execute o seguinte:
|
1 |
adb reverse tcp:4984 tcp:4984 |
Abra a interface de usuário do administrador para monitorar os documentos que foram salvos no Sync Gateway:
https://localhost:4985/_admin/
Tente adicionar mais documentos de tarefas e observe como eles são enviados automaticamente para o Sync Gateway.
Para onde ir a partir de agora
Parabéns! Você criou seu primeiro aplicativo React Native Android + Couchbase Lite. Agora você está pronto para adicionar mais componentes, como os seguintes:
- Visualizações do Couchbase Lite para escrever consultas personalizadas
- Autenticação do usuário em uma replicação
- Implementação contínua do arquivo de configuração do Sync Gateway e outros componentes
Fique atento a um tutorial sobre a depuração de seu aplicativo React Native Android + Couchbase Lite usando Charles e Genymotion.
Sinta-se à vontade para compartilhar seus comentários, descobertas ou fazer perguntas nos comentários abaixo ou nos fóruns. Falamos com você em breve!
*Abra o AndroidManifest.xml localizado em app/src/main e adicione as permissões
A linha acima indica as permissões, mas nenhuma foi encontrada na caixa fornecida abaixo dela.