Módulos nativos de Android en React Native
Este artículo está escrito en base a la charla que dí en el MDevConf el 3 de Diciembre de 2022. Puedes encontrar las diapositivas de esta charla aquí.
Como ya debes saber React Native es un framework basado en React para crear aplicaciones nativas para iOS y Android utilizando Javascript, React Native tiene la capacidad de transpilar el codigo Javascript en código nativo de cada plataforma (Swift o Objective C para dispositivos iOS, Kotlin o Java para dispositivos Android), pero además en caso de necesitar escribir código nativo React Native expone la API NativeModule
para facilitar este trabajo.
La manera como React Native "transforma" el código Javascript / React a código nativo es usando el denominado Bridge que básicamente es una conexión entre el código Javascript y el código nativo.
Esto es lo que hace que los componentes de React Native sea convertido a componentes de las plataformas nativas. Por ejemplo un componente View
de React Native es transformado a ViewGroup
de Android y UIView
de iOS.
¿Cómo crear el primer Modulo Nativo de Android?
Puedes seguir esta explicación en este repositorio navegando los branches para ver el progreso.
1. Crear un archivo de Módulo Nativo (branch)
Inicialmente necesitas crear un archivo java dentro de android/app/src/main/java/com/{NOMBRE_DE_LA_APP}/MyNativeModule.java
con este contenido inicial:
// MyNativeModule.javapackage com.mdevconf;import android.util.Log;import androidx.annotation.NonNull;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;public class MyNativeModule extends ReactContextBaseJavaModule {MyNativeModule(ReactApplicationContext context) {super(context);}@NonNull@Overridepublic String getName() {return "MyNativeModule";}}
Un detalle importante del código anterior en que la nueva clase Java tiene que extender de ReactContextBaseJavaModule
que es base para construir el Módulo Nativo. También hay que notar el método getName
que da el nombre al Módulo Nativo para que pueda ser accedido desde Javascript con ese mismo nombre, por ejemplo se podrá acceder a este en un componente React Native mediante:
const {MyNativeModule} = ReactNative.NativeModules;
2. Exportar un método nativo Javascript (branch)
Se debe crear un metodo que eventualmente podrá ser usado desde Javascript, en este caso será un Logger simple que nos permita mostrar un mensaje el Logcat.
Este método esta anotado con el decorador @ReactMethod
para indicar que será utilizado dentro del código Javascript.
// MyNativeModule.javapublic class MyNativeModule extends ReactContextBaseJavaModule {...@ReactMethodpublic void simpleLogger() {Log.d("MyNativeModule", "Log desde la el modulo nativo!");}}
3. Registrar el módulo dentro de un package (branch)
El siguiente paso es registrar este modulo dentro de un package, para lo que se crea un nuevo archivo Java dentro de android/app/src/main/java/com/{NOMBRE_DE_LA_APP}/MyNativePackage.java
con el siguiente contenido:
// MyNativePackage.javapackage com.mdevconf;import androidx.annotation.NonNull;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 MyNativePackage implements ReactPackage {@NonNull@Overridepublic List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {return Collections.emptyList();}@NonNull@Overridepublic List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {List<NativeModule> modules = new ArrayList<>();modules.add(new MyNativeModule(reactContext));return modules;}}
Con este archivo lo que se hace es registrar el Modulo Nativo dentro de un package para que pueda ser usado utilizado en MainApplication.java
4. Registrar el package (branch)
Para esto se debe modificar el archivo MainApplication.java
como sigue:
// MainApplication.javapublic class MainApplication extends Application implements ReactApplication {private final ReactNativeHost mReactNativeHost =new ReactNativeHost(this) {.......@Overrideprotected List<ReactPackage> getPackages() {@SuppressWarnings("UnnecessaryLocalVariable")List<ReactPackage> packages = new PackageList(this).getPackages();// Packages that cannot be autolinked yet can be added manually here, for example:// packages.add(new MyReactNativePackage());packages.add(new MyNativePackage());return packages;}.......};.....}
Con estos cambios el Modulo Nativo esta listo para ser usado desde Javascript, en este punto es importante hacer correr la aplicacion desde cero con el comando
npx react-native run-android
5. Import y utilizar en React Native! (branch)
En este punto ya podemos utilizar nuestro módulo nativo desde la aplicación en Javascript, para esto se debe modificar el archivo App.js
:
// App.jsimport {...NativeModules,...} from 'react-native';const {MyNativeModule} = NativeModules;const App = () => {const onPressButton = () => {console.log('Este es un log desde javascript');MyNativeModule.simpleLogger();};return (<SafeAreaView><StatusBar barStyle={'light-content'} /><View style={styles.container}><Text style={styles.text}>Hello MDevConf!</Text><Button title="Click me" onPress={onPressButton} /></View></SafeAreaView>);};
Este es un ejemplo muy simple, lo que se hace es importar NativeModules
del paquete react-native
, destructurar el nombre de nuestro modulo nativo, en este caso lo llamamos MyNativeModule
, una vez tenemos acceso al modulo nativo podemos invocar el metodo que exportamos para registrar un log en el logcat del dispositivo al activar un boton:
MyNativeModule.simpleLogger();
Una vez que la aplicación este corriendo en el emulador y el usuario haga click en el boton se podrá ver el mensaje en la ventana de Logcat, como en la imagen: