Pitch: como eu executei um código da linguagem Python em um aplicativo feito em React Native
Bom, recentemente um tive um problema que eu não conseguia enviar uma requisição via axios para um site, pois ele era rejeitado devido ao certificado inválido do site. E como um programador que não desiste eu cheguei na seguinte solução: executar um script em Python para fazer essa requisição usando o módulo requests com a flag verify
setada como false
para ignorar a validação do certificado. E aqui irei mostrar o passo a passo de como fazer isso, para caso, assim como eu, você tenha uma ideia no mínimo mirabolante.
Antes de mais nada o que usaremos nesse tutorial é o SDK Chaquo, que é um SDK do Python para Android. E temos algumas configurações a serem feitas para conseguirmos usar ela:
-
Caso você esteja usando o Expo você deverá ejetar o seu aplicativo com o seguinte comando:
npx expo prebuild
Caso contrário você pode ignorar esse passo, mas terá que certificar que o diretórioandroid
esteja criado. -
Feito isso, no arquivo
android/build.gradle
adicione a seguinte dependência:
buildscript {
...
dependencies {
// Ela tem que ser adicionada depois das dependências do gradle
classpath "com.chaquo.python:gradle:14.0.2"
}
}
- No arquivo
android/app/build.gradle
adicione as seguintes linhas:
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
apply plugin: "com.chaquo.python" // Essa linha
import com.android.build.OutputFile
...
android {
...
defaultConfig {
...
// E as linhas abaixo
python {
buildPython "C:\\Python311\\python.exe"
pip {
install "requests"
}
}
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
sourceSets {
main {
python.srcDir "src/main/python"
}
}
}
}
Explicação:
- python.buildPython: Caminho do executável python que está no seu computador.
- python.pip: módulos que usaremos no nosso script, caso o módulo seja nativo do Python não é necessário colocar ele nesse passo. Os módulos colocados aqui serão baixados.
- ndk.abiFilters: Segundo a documentação do SDK é opcional, e serve para especificar quais ABIs você deseja que o aplicativo ofereça suporte.
- sourceSets.main.python.srcDir: caminho de onde ficará o script python.
- Após ter feito isso você deverá fazer o Sync do projeto via Android Studio para ele baixar as dependências que faltam
Feito isso agora iremos colocar a mão na massa:
- Depois que terminar o Sync, dentro da pasta
android/src/main/
crie uma pasta chamadapython
e dentro dessa pasta crie um arquivo chamadoapp.py
(pode ser qualquer nome), e cole o seguinte código nele:
import json
import requests
def post(url, data):
response = requests.post(url=url, data=json.loads(data), verify=False)
return response.text
Explicação:
- Criamos uma função para fazer uma requisição POST e retornar o conteúdo da requisição.
- A partir de agora iremos fazer esse script ser chamado pelo React Native, e primeiramente iremos criar uma classe java chamada
PythonModule
, com o seguinte código:
import android.content.Context;
import androidx.annotation.NonNull;
import com.chaquo.python.PyObject;
import com.chaquo.python.Python;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class PythonModule extends ReactContextBaseJavaModule {
Context context;
Python py = Python.getInstance();
PyObject pyobj = py.getModule("app");
PythonModule(ReactApplicationContext context) {
super(context);
this.context = context.getApplicationContext();
}
@NonNull
@Override
public String getName() {
return "PythonModule";
}
@ReactMethod
public void post(String url, String data, Promise promise) {
new Thread(() -> {
PyObject obj = pyobj.callAttr("post", url, data);
String result = obj.toString();
try {
promise.resolve(result);
} catch (Exception e) {
promise.reject("Error ", e);
}
}).start();
}
}
Explicação:
- Para o Android, os módulos nativos Java/Kotlin são escritos como classes que estendem ReactContextBaseJavaModule e implementam a funcionalidade exigida pelo JavaScript.
- Todos os módulos nativos Java/Kotlin no Android precisam implementar o método getName(). Este método retorna uma string, que representa o nome do módulo nativo. O módulo nativo pode então ser acessado em JavaScript usando seu nome.
- A função
post
é onde será chamado o métodopost
que a gente criou no script python, ele deve ter a anotação@ReactMethod
para poder ser chamado pelo JavaScript e ele recebe como parâmetro a URL e o conteúdo que será enviado na requisição. O parâmetropromise
é para conseguirmos retornar para o aplicativo o conteúdo da requisição. Reparem que foi criado uma nova Thread, pois sem ela o aplicativo ficaria travado nesse código, atrapalhando assim o fluxo dele.
- Depois teremos que criar uma nova classe chamada
PythonPackage
, ela serve para registrar o módulo criado anteriormente. Ela vai possuir o seguinte código:
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PythonPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new PythonModule(reactContext));
return modules;
}
}
Explicação:
- Essa classe importa o módulo nativo que criamos, PythonModule. Em seguida, ele instancia ele dentro da função createNativeModules() e o retorna como uma lista de NativeModules a serem registrados. Se você adicionar mais módulos nativos posteriormente, também poderá instanciá-los e adicioná-los à lista igual está no código acima.
- Agora que criamos o nosso módulo e o seu pacote registrador, precisaremos que o pacote seja registrado na classe
MainApplication
. Então localize essa classe e no métodogetPackages
adicione a seguinte linha antes doreturn
:
packages.add(new PythonPackage());
- Agora iremos fazer a nossa última configuração para posteriormente conseguirmos executar o nosso script Python. Abra a classe
MainActivity
e localize o métodoonCreate
e antes da chave de fechamento da função cole o seguinte código:
if (!Python.isStarted()) {
Python.start(new AndroidPlatform(this));
}
Os imports a serem adicionados são esses:
import com.chaquo.python.Python;
import com.chaquo.python.android.AndroidPlatform;
Explicação:
- Esse código serve para iniciar o SDK para que a gente consiga executar o nosso script.
- Agora chegou a hora de testar o nosso script. No arquivo
App.tsx
ouApp.js
, adicione os seguintes códigos:
import {NativeModules, Button} from 'react-native';
...
const onPress = async () => {
const url = "https://www.tabnews.com.br/api/v1/sessions"
const payload = {
"email": "[email protected]",
"password": "senha"
}
const response = await NativeModules.PythonModule.post(url, JSON.stringify(payload));
console.log(response);
};
return (
...
<Button
title="Clique aqui para invocar o script!"
color="#841584"
onPress={onPress}
/>
...
);
Após isso é só executar o comando npx expo android
ou npx react-native start
(dependendo de como você criou o projeto) e testar.
Como esse é o meu primeiro pitch em forma de tutorial, espero que ele tenha agregado alguns conhecimentos a mais para vocês que trabalham ou não com React Native.
Até a próxima!