Arquitectura de desarrollo híbrida | La ingeniería de Android integra React Native, Flutter, ReactJs
- Arquitectura Diseño Descripción
-
- Crear proyecto nativo de Android
- Crear aleteo
- Crear reaccionar nativo
- Diseño de arquitectura de la barra de navegación inferior
- Dirección de origen del proyecto
Arquitectura Diseño Descripción
Este artículo presenta y registra detalles y procesos importantes en el desarrollo de la gran arquitectura híbrida front-end. Al integrar los dos frameworks híbridos convencionales React Native, Flutter y ReactJs[Vue] en el proyecto nativo de Android, se integra el diseño híbrido de la arquitectura de los tres tipos de módulos. Y en la creación de negocios de estas pilas de tecnología convencional, construyen sus propias ruedas, utilizan un diseño de arquitectura novedoso y tecnologías centrales para lograrlo. Y en el proceso de codificación, también creará herramientas comunes, barra de estado inmersiva , barra de navegación inferior , actualización en caliente de Flutter, entrada múltiple de Flutter,
tabla 1 | tab2 | tab3 | tab4 | tab5 |
---|---|---|---|---|
Imitación de la página de inicio de China Merchants Bank | imitacion de mensajeria instantanea | Imitación de la página de inicio de ICBC | imitacion vibrato mi pagina | Clasificación Imitación Vipshop |
Cree una página de inicio en el proyecto nativo y utilícela en la página de inicio 五个TAB
.
TAB1
, utilizando codificación nativa Java+Kotlin, imitando la página de inicio de China Merchants Bank, utilizando un excelente diseño de arquitectura y completando el desacoplamiento independiente de cada módulo de la lista.TAB2
, usando codificación Java+Kotlin nativa, imitando WeChat y realizando mensajería instantánea IM a través de Android Socket.TAB3
, utilizando la codificación React Native, imitando la página de inicio de ICBC.TAB4
, usando la codificación de Flutter, imitando a Douyin en mi página.TAB5
, codificado con ReactJs, imitando la página de clasificación de Vipshop.
Crear proyecto nativo de Android
Versión de estudio de Android | versión del complemento gradle | versión gradle | versión kotlin | versión JDK | otro |
---|---|---|---|---|---|
3.6 | 3.6.0 | gradle-6.7.1-all.zip (anteriormente 5.6.4) | 1.5.31 | JDK11 | compileSdkVersion 31, buildToolsVersion “30.0.0” , minSdkVersion 21, targetSdkVersion 30 |
Crear aleteo
Versión de estudio de Android | versión del complemento gradle | versión gradle | versión JDK | otro |
---|---|---|---|---|
3.6 | 3.6.0 | gradle-5.6.4-all.zip | JDK11 | compileSdkVersion 31, buildToolsVersion “30.0.0” , minSdkVersion 21, targetSdkVersion 30 |
Integre e incorpore ingeniería nativa
Introducción detallada de integración, muévase para ver
Crear reaccionar nativo
En comparación con la creación de Flutter, la creación de proyectos React Native es mucho más complicada. Al crear, encontrará el problema de la falla de creación. Después de la creación exitosa, también encontrará el problema del informe de error cuando inicia el servicio de Metro . Y todas estas preguntas están relacionadas con nodejs版本
. Lea la documentación oficial del entorno de compilación en detalle ,React Naitve版本
Instrucciones de creación de React Native:
npx react-native init hibrid_rn --version 0.67.0
Instrucciones de inicio del servicio Metro:npx react-native start
Instrucciones de instalación y compilación de apk de Android:yarn android
versión de nodo | Reaccionar versión nativa | versión JDK | ilustrar |
---|---|---|---|
v16.17.0 | 0.67.0 | JDK11 | Para obtener un número de versión detallado, muévase para ver el código |
Resolver el problema del error RN
Si hay un error, lo siguiente
如下报错信息,则是node版本号使用不当导致~
/node_modules/@react-native-community/cli/build/commands/doctor/healthchecks/index.js:48
} catch {}
^
SyntaxError: token inesperado { en createScript (vm.js:80:10) en Object.runInThisContext (vm.js:139:10) en Module._compile (module.js:617:28) en Object.Module._extensions…js (module.js:664:10) … … …
Si hay un error, lo siguiente
Could not find react-native-0.71.0-rc.0-debug.aar (com.facebook.react:react-native:0.71.0-rc.0).
Could not determine the dependencies of task ':app:lintVitalRelease'.
> Could not resolve all artifacts for configuration ':app:debugCompileClasspath'.
> Could not find react-native-0.71.0-rc.0-debug.aar (com.facebook.react:react-native:0.71.0-rc.0).
Solución, especifique ReactNative para determinar el número de versión Modifique ReactNative aapp/build.gradle
implementation "com.facebook.react:react-native:+"
implementation "com.facebook.react:react-native:0.67.0"
Si hay un error, lo siguiente
Execution failed for task ':app:mergeDebugNativeLibs'.
More than one file was found with OS independent path 'lib/x86_64/libfbjni.so'
La solución es agregar el error informado en la captura de pantalla en android app/build.gradle
{}, comolib/x86_64/libfbjni.so
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/x86/libfbjni.so'
pickFirst 'lib/x86_64/libfbjni.so' // 截图中有这个报错,这里添加该so修复
pickFirst 'lib/armeabi-v7a/libfbjni.so'
pickFirst 'lib/arm64-v8a/libfbjni.so'
}
Integre e incorpore ingeniería nativa
// 【app/build.gradle】下进行配置
// 【配置共三步】rn第一步配置:start
project.ext.react = [
entryFile : "index.android.js",
enableHermes: false,
bundleInDebug:true,
bundleInBeta:true
]
def enableHermes = project.ext.react.get("enableHermes", false);
def jscFlavor = 'org.webkit:android-jsc:+'
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
// 【配置共三步】rn第一步配置:end
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
......
// 【配置共三步】rn第二步配置:start
if (enableHermes) {
def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
// 【配置共三步】rn第二步配置:end
}
// 【project/build.gradle】下进行配置
allprojects {
repositories {
......
// 【配置共三步】rn第三步配置:start
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../hibrid_rn/node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url("$rootDir/../hibrid_rn/node_modules/jsc-android/dist")
}
//【配置共三步】rn第三步配置:end
}
}
Descripción del campo de parámetro:
entryFile : "index.android.js"
, que indica el nombre de la configuración que carga el archivo de entrada de recursos de Android.def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/"
, indicando queenableHermes==true
en ese momento se introdujo el motor de ejecución Hermes. De lo contrario, se utiliza el motor de ejecución JavaScriptCore.
Hermes es una característica opcional de React Native. Si desea habilitar Hermes, debe asegurarse de que la versión del proyecto React Native esté
0.60.2版本
arriba, y también debeandroid/app/build.gradle
realizar los siguientes cambios en . Configuramos aquíenableHermes: false
project.ext.react = [
entryFile: "index.js",
enableHermes: true // 配置开启Hermes引擎
]
Después de que se integre el RN, inicie un error
Después de integrar RN en el proyecto nativo, use React Native como parte de LayoutView en la actividad del proyecto nativo para probar el estado de integración. Descubrí que iniciar React Native desde Native informó el siguiente error ~
ReactNative: Exception in native call java.lang.RuntimeException: Unable to load script. Make sure you're either running Metro (run 'npx react-native start') or that your bundle 'rn/index.android.bundle' is packaged correctly for release.
El mensaje de error decía que el servicio Metro no se inició o que no se pudo encontrar el paquete de recursos del paquete. El hecho es que el servicio actual de Metro se ha iniciado y está bien iniciar directamente el proyecto React Native. Hay dos soluciones para esto:
- Empaquete el código del proyecto actual
React Native
y copie el empaquetadobundle资源
en el directorio del proyecto nativo/main/assets/rn
. Entonces no hay problema para ejecutarse en Native. - El terminal VSCode ejecuta las instrucciones de empaquetado:
react-native bundle --platform android --dev false --entry-file index.js --bundle-output ../HybridArcPro/app/src/main/assets/rn/index.android.bundle --assets-dest ../HybridArcPro/app/src/main/res/
- Sin empaquetar Tanto Native como React Native deben configurarse. ① Configure la IP del servicio y el número de puerto para la aplicación del paquete de depuración instalado. ②Configure los permisos de red,
application标签
configure en mediotools:targetApi="28" android:allowBackup="true"
. ③ Iniciar el servicio de Metro.
Diseño de arquitectura de la barra de navegación inferior
Use el lenguaje Java para personalizar el control de diseño de la barra de navegación en la parte inferior de la página de inicio (el efecto + código fuente de navegación en la figura a continuación ) e introduzca el UML personalizado ~
TabBtnLayoutBottomNav
Vista personalizada del diseño de la barra de navegación inferior. Heredado de FrameLayout, implementado desde la interfaz ITabLayout. Diseño de la barra de navegación inferior, ubicación internaTabBtnBottom
,TabBtnBottom
Una sola pestaña en un diseño de barra de navegación inferior. Heredado de RelativeLayout, implementado desde la interfaz I ITab (ITab hereda la interfaz de escucha de eventos de clic OnTabSelectedListener).TabBtnLayoutBottomNav
Encapsula internamente una sola colección de pestañasList<OnTabSelectedListener>
(incluido todo el monitoreo OnTabSelectedListener agregado por TabBtnBottom y TabBtnLayoutBottomNav). Cuando el usuario hace clic en la pestaña, el evento de clicTabBtnBottom.setOnClickListener
desencadena el recorrido de la lista de colección. En este momento, el evento de clic se pasa a cada TabBtnBottomz y la devolución de llamada de monitoreo agregada por TabBtnLayoutBottomNav. Como resultado, una sola pestaña y TabBtnLayoutBottomNav están asociados con eventos de clic y pueden allanar el camino para la visualización de cambio de clic de fragmento integrado.
TabBtnFragmentLayout
, para mostrar el ** control de diseño personalizado ** de la página del fragmento y colocarlo en el archivo de diseño TabBtnLayoutBottomNav. El índice de devolución de llamada de monitoreo agregado por TabBtnLayoutBottomNav, el métodosetCurrentItem
obtiene instrucciones y muestra la página de fragmento correspondiente.TabBtnFragmentAdapter
, para mostrar la clase de adaptador para la página del fragmento. Las instrucciones específicas muestran la lógica de la página del fragmento, que se implementa en el métodoinstantiateItem
.
Imitación original de la página de inicio de China Merchants Bank
Mensajería instantánea nativa de Android Socket
React Native imita la página de inicio de ICBC
Use RN para imitar la página de inicio del Banco Industrial y Comercial de China (encontré el ícono con dificultad) y luego realice StatusBar和TitleBar
el **滑动渐变**
efecto aleatorio. Aquí, inicie y abra RN de forma nativa, el efecto es el siguiente ~
Pase de forma nativa el objeto inicial de los accesorios, los usos de RN
// React Native中配置bundle
val bundle = Bundle()
rnBundle.putCharSequence("device-info","设备信息对象")
rnBundle.putCharSequence("state","用户登录状态")
mReactRootView!!.startReactApplication(mReactInstanceManager, "hibrid_rn", bundle)
// 在对应的ReactNative的Coponent中获取,则可通过this.props得到!
Nativo para comunicarse con RN
Introducción al efecto logrado
Se define un método para llamar a Android ToastJRNBridge.kt
en la clase de puente del lado nativo para que llame el lado ReactNative. El efecto es el siguiente
Notas durante el desarrollo
Aquí tomamos este proyecto como ejemplo para presentar la lógica de los pasos de desarrollo al realizar la comunicación entre RN y C-side.
1. Defina la herramienta de puente en el lado C del código fuente lógicoJRNBridge.kt
. La clase de puente hereda de ReactContextBaseJavaModule.java, el método de implementación getName
: el nombre obtenido se usará en el lado de ReactNative,
// bridge/index.js
import {
NativeModules} from 'react-native'
module.exports = NativeModules.RNBridge // 这里的 RNBridge 就是getName得到。
2. El método de comunicación entre ReactNative y C-side Native debe anotarse@ReactMethod
.
3. Cree JReactPackage.kt para heredarReactPackage.kt
y reescribir el métodocreateNativeModules和createViewManagers
. El método de reescrituracreateNativeModules
es agregar JReactPackage a la lista NativeModule para el registro posterior.
crear módulos nativos | crearViewManagers |
---|---|
Vuelva a escribir y agregue NativeModule cuando ReactNative llame al método nativo | Interfaz de usuario nativa, ya que la interfaz de usuario de ReactNative se reescribió y se agregó ViewManager |
4. Agregue y registre MainReactPackage() y JReactPackage() en ReactInstanceManager.
Entre ellos, se requieren MainReactPackage() y JReactPackage(), de lo contrario se informará un error'StatusBarManager' could not be found. Verify that a module by this name is registered in the native binary.
De lo contrario, JReactPackage() informa un error y no puede encontrarlo RNBridge.toast({toast:'正在取号中,请稍后...'})
.
5. Exportar el JRNBridge registrado en NativeModulesen ReactNativeLuego introdúzcalo y utilícelo en varios lugares en ReactNative.
import RNBridge from '@bridge/index'
<TouchableOpacity onPress={
()=>{
RNBridge.toast({
toast:'正在取号中,请稍后...'})}} >
Flutter imita vibrato mi pagina
Actualización en caliente de Flutter
Flutter热更新,通过动态.so文件的加载实现。
La idea de la carga dinámica de archivos .so es
reflejar el valor que se está modificandoFlutterLoader.java类
,valorFlutterApplicationInfo.aotSharedLibraryName
original. Después de eso,copie el reemplazo en eldirectorio original. La forma de copiar, como empaquetar primero una nueva versión-apk, luego descomprimir y extraer el archivo libapp.so en este momento (renombrado como libapp**.so), y colocarlo en el directorio assets/. Luego, cuando se copia el código, el paquete so en el directorio assets/ se copiará en el directorio recién especificado donde se cargará, y luego la actualización en caliente se completará lógicamente.libapp.so
libapp**.so
libapp**.so
libapp.so
libapp.so
Cree múltiples motores FlutterEngine e implemente múltiples entradas de dardos
Una página de inversión y gestión financiera de flutter , como la segunda entrada de dart. Y abierto por el motor correspondiente definido a continuación.
Crear múltiples motores FlutterEngine
Mediante FlutterEngine
la creación de un objeto de instancia de motor. Se pasa durante la creación JFlutterLoader
y redefine dart代码包
la forma en que el FlutterLoader original lo obtiene. Después de eso, comience a ejecutar el código Dart de acuerdo con el DartEntrypoint dado. Y almacene en caché la Flutter引擎
instancia creada. que se pasa DartEntrypoint
a moduleName是dart入口名称
,findAppBundlePath是flutter资产目录flutterAssetsDir
// 初始化,根据moduleName(dart入口名称)创建多个Flutter引擎
private fun initFlutterEngine(context: Context, moduleName: String): FlutterEngine? {
var flutterEngine:FlutterEngine = FlutterEngine(context, JFlutterLoader.get(), FlutterJNI())
flutterEngine.dartExecutor
.executeDartEntrypoint(DartExecutor.DartEntrypoint(JFlutterLoader.get().findAppBundlePath(), moduleName))
FlutterEngineCache.getInstance().put(moduleName, flutterEngine) // 缓存起来
return flutterEngine
}
Crear múltiples entradas de dardos
// 在flutter的dart代码中main.dart
// 至少有一个默认入口,如 'main'
void main() {
runApp(const MyApp());
init();
}
// 此时,可仿照默认入口,通过注解,创建多个不同的dart入口 - 工行的'投资理财'详情页面
@pragma('vm:entry-point')
void finance() {
runApp(FinanceEntryApp());
}
Combinado con el código fuente de Flutter, analice el inicio de Flutter desde el extremo nativo
Comunicación nativa con Flutter
tipo | ilustrar |
---|---|
MétodoChannel | Comunicación única utilizada para transferir invokeMethod llamadas de método: como llamar a la función de punto enterrado de Flutter. |
Aquí presentaremos MethodChannel , cómo comunicarse entre Native y Flutter ~ El lado de Flutter envía , y el lado nativo recibe y procesa.
Flutter侧发送
, combinado con el código fuente, creando uno MethodChannel实例
y especificando el nombre del canal name
. Y ambos lados name
deben ser iguales. Luego use la instancia de MethodChannel para llamar y ejecutar 方法invokeMethod
, y se llamará al método pasado al lado nativo 方法名称method
y el contenido del mensaje de comunicación arguments
. Después de eso, se inicia la llamada de transferencia de Flutter al lado nativo.
Native侧接收处理
, crea un canal con name
el mismo nombre que el canal lateral de Flutter MethodChannel实例
. Use la instancia de MethodChannel para llamar y ejecutar 方法setMethodCallHandler
para que coincida con Flutter侧方法名称method
la información de recepción y procesamiento enviada desde el lado de Flutter. Diseño detallado e implementación, mueva para ver
Página de categoría Vipshop de imitación de ReactJs
Introducción detallada al desarrollo, muévase para ver
Dirección de origen del proyecto
Haga clic para ingresar al almacén para ver el código fuente del proyecto