Executando verificação de segurança...
2

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:

  1. 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ório android esteja criado.

  2. 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"
    }
}
  1. 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.
  1. 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:

  1. Depois que terminar o Sync, dentro da pasta android/src/main/ crie uma pasta chamada python e dentro dessa pasta crie um arquivo chamado app.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.
  1. 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étodo post 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âmetro promise é 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.
  1. 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.
  1. 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étodo getPackages adicione a seguinte linha antes do return:
packages.add(new PythonPackage());
  1. Agora iremos fazer a nossa última configuração para posteriormente conseguirmos executar o nosso script Python. Abra a classe MainActivity e localize o método onCreate 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.
  1. Agora chegou a hora de testar o nosso script. No arquivo App.tsx ou App.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!

Carregando publicação patrocinada...