混合开发架构|Android工程集成React Native、Flutter、ReactJs

article/2025/9/24 11:11:44

混合开发架构|Android工程集成React Native、Flutter、ReactJs

  • 架构设计说明
    • 创建安卓原生工程
    • 创建Flutter
      • 集成嵌入原生工程
    • 创建React Native
      • 解决RN报错问题
      • 集成嵌入原生工程
      • RN集成后,启动报错
    • 底部导航栏架构设计
      • 原生仿招商银行首页
      • 原生Android Socket 即时通讯
      • React Native仿工商银行首页
        • 原生传递props初始对象,RN使用
        • 原生与RN通信
          • 已实现效果介绍
          • 开发中注意事项
      • Flutter仿抖音我的页面
        • Flutter热更新
        • 多FlutterEngine引擎创建,多dart入口实现
        • 结合Flutter源码,分析从原生端启动Flutter
        • 原生与Flutter通信
      • ReactJs仿唯品会分类页面
    • 工程源码地址

架构设计说明

该篇文章,介绍并记录在大前端混合架构开发中的重要细节和流程。通过在安卓原生工程中集成两大主流混合框架React Native、Flutter,以及ReactJs[Vue],集成三类模块module的架构的混合设计。并分别在这些主流技术栈的业务创作中,自己造轮子、使用新颖架构设计及核心技术去实现。并在编码过程中还会创造常用工具,沉浸式状态栏、底部导航栏、Flutter热更新、Flutter多入口、

tab1tab2tab3tab4tab5
仿招商银行首页仿即时通讯仿工商银行首页仿抖音我的页面仿唯品会分类

在原生工程中创建一个首页,在首页中使用五个TAB

  • TAB1,使用原生Java+Kotlin编码,仿招商银行首页,使用优秀架构设计,完成列表各个模块的独立解耦。
  • TAB2,使用原生Java+Kotlin编码,仿微信,通过Android Socket实现IM的即时通讯。
  • TAB3,使用React Native编码,仿工商银行首页。
  • TAB4,使用Flutter编码,仿抖音我的页面。
  • TAB5,使用ReactJs编码,仿唯品会分类页面。

创建安卓原生工程

Android Studio版本gradle 插件版本gradle 版本kotlin版本JDK 版本其他
3.63.6.0gradle-6.7.1-all.zip(原5.6.4)1.5.31JDK11compileSdkVersion 31、buildToolsVersion “30.0.0” 、minSdkVersion 21、targetSdkVersion 30

创建Flutter

Android Studio版本gradle 插件版本gradle 版本JDK 版本其他
3.63.6.0gradle-5.6.4-all.zipJDK11compileSdkVersion 31、buildToolsVersion “30.0.0” 、minSdkVersion 21、targetSdkVersion 30

集成嵌入原生工程

详尽集成介绍,请移步查看

创建React Native

与创建Flutter相比较,React Native工程创建时,复杂很多。创建时候会遇到创建失败问题,成功创建后,启动Metro服务也会遇到报错问题。而这些问题都与nodejs版本React Naitve版本有关。请详细阅读官方搭建环境的文档,

React Native 创建指令:npx react-native init hibrid_rn --version 0.67.0
Metro服务启动指令:npx react-native start
Android apk 编译安装指令:yarn android

node版本React Native版本JDK 版本说明
v16.17.00.67.0JDK11详细版本号,请移步查看代码

解决RN报错问题

若有报错,下面

如下报错信息,则是node版本号使用不当导致~
/node_modules/@react-native-community/cli/build/commands/doctor/healthchecks/index.js:48
} catch {}
^
SyntaxError: Unexpected token {
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:617:28)
at Object.Module._extensions…js (module.js:664:10)
… … …

若有报错,下面
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).

解决方案, 指定ReactNative确定版本号!!修改ReactNativeapp/build.gradle
implementation "com.facebook.react:react-native:+" 改为implementation "com.facebook.react:react-native:0.67.0"

若有报错,下面
Execution failed for task ':app:mergeDebugNativeLibs'.
More than one file was found with OS independent path 'lib/x86_64/libfbjni.so'

在这里插入图片描述
解决方案,app/build.gradle android{} 中添加截图中报错的如lib/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'}

集成嵌入原生工程


// 【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第二步配置:startif (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_modulesimplementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"// 【配置共三步】rn第二步配置:end
}// 【project/build.gradle】下进行配置
allprojects {repositories {......// 【配置共三步】rn第三步配置:startmaven {// All of React Native (JS, Android binaries) is installed from npmurl "$rootDir/../hibrid_rn/node_modules/react-native/android"}maven {// Android JSC is installed from npmurl("$rootDir/../hibrid_rn/node_modules/jsc-android/dist")}//【配置共三步】rn第三步配置:end}
}

参数字段说明:

  • entryFile : "index.android.js",表示配置加载安卓资源入口文件名称。
  • def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/",表示当enableHermes==true时,引入执行引擎Hermes。否则,使用JavaScriptCore执行引擎。

Hermes 是一个可选的 React Native 功能。如果要启用Hermes,需要确保 React Native项目的版本在0.60.2版本 以上,并且还需要对android/app/build.gradle 做以下更改。我们这里配置enableHermes: false

project.ext.react = [entryFile: "index.js",enableHermes: true // 配置开启Hermes引擎
]

RN集成后,启动报错

在原生工程中集成了RN之后,将React Native作为原生工程Activity下LayoutView的一部分,测试集成状态。发现从Native启动React Native报以下错误~

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.

在这里插入图片描述
报错信息说,Metro服务未启动,或者说找不到bundle资源包。而事实是当前Metro服务已启动,且直接启动React Native工程是OK的。对此寻到以下两种解决方案 :

  • 对当前React Native工程代码进行打包,并将打包后的bundle资源拷贝到Native工程的/main/assets/rn目录下。然后在Native运行则无问题。
  • VSCode终端执行打包指令: 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/
  • 非打包处理。需要对Native和React Native端同时进行配置。①对安装的debug包APP配置服务IP和端口号。②配置网络权限,application标签中配置 tools:targetApi="28" android:allowBackup="true"。③启动Metro服务。

在这里插入图片描述

底部导航栏架构设计

使用java语言,自定义首页底部导航栏布局控件(下图实现效果+导航源码),自定义UML介绍~
在这里插入图片描述

  • TabBtnLayoutBottomNav 底部导航栏布局自定义View。继承自FrameLayout,实现自接口ITabLayout。底部导航栏布局,内部摆放TabBtnBottom
  • TabBtnBottom底部导航栏布局中的单个Tab。继承自RelativeLayout,实现自I接口ITab(ITab继承了点击事件的监听接口OnTabSelectedListener)。
  • TabBtnLayoutBottomNav 内部封装单个Tab集合List<OnTabSelectedListener>(包含所有TabBtnBottom和TabBtnLayoutBottomNav添加的监听OnTabSelectedListener),当用户点击Tab时,点击事件通过TabBtnBottom.setOnClickListener触发集合List的遍历,此时将点击事件传递给每个TabBtnBottomz,同时TabBtnLayoutBottomNav添加的监听回调。由此单个Tab和TabBtnLayoutBottomNav产生了点击事件的关联,并能为集成fragment点击切换显示做下伏笔。
    在这里插入图片描述在这里插入图片描述
  • TabBtnFragmentLayout,显示fragment页面的**自定义布局控件**,放在布局文件TabBtnLayoutBottomNav中。由TabBtnLayoutBottomNav添加的监听回调index,方法setCurrentItem获得指示并显示相应fragment页面。
  • TabBtnFragmentAdapter,显示fragment页面的适配器类。具体指示显示fragment页面逻辑,实现在方法instantiateItem中。
    在这里插入图片描述

原生仿招商银行首页

原生Android Socket 即时通讯

React Native仿工商银行首页

使用RN仿工商银行首页(图标自己费劲吧啦找的),然后实现StatusBar和TitleBar**滑动渐变**效果。此处由原生启动并打开RN,效果如下~
在这里插入图片描述

原生传递props初始对象,RN使用

// React Native中配置bundle
val bundle = Bundle()
rnBundle.putCharSequence("device-info","设备信息对象")
rnBundle.putCharSequence("state","用户登录状态")
mReactRootView!!.startReactApplication(mReactInstanceManager, "hibrid_rn", bundle)// 在对应的ReactNative的Coponent中获取,则可通过this.props得到!

原生与RN通信

已实现效果介绍

在Native端桥接类JRNBridge.kt中定义了一个调用安卓Toast的方法,供ReactNative端调用。效果如下
在这里插入图片描述

开发中注意事项

这里以本项目作为示例,介绍下在实现RN和C端通信时,开发步骤逻辑。
1, 逻辑源码C端中定义桥接类工具JRNBridge.kt。桥接类继承自ReactContextBaseJavaModule.java,实现方法getName —— 获取到的name会在ReactNative端使用,

// bridge/index.js
import {NativeModules} from 'react-native'
module.exports = NativeModules.RNBridge  // 这里的 RNBridge 就是getName得到。

2, ReactNative和C端Native进行通信的方法,需要加注解@ReactMethod

3, 创建JReactPackage.kt 继承ReactPackage.kt,重写方法createNativeModules和createViewManagers。重写方法createNativeModules是将JReactPackage添加到NativeModule列表为之后注册。

createNativeModulescreateViewManagers
ReactNative调用Native方法时重写并添加NativeModuleNative UI,作为ReactNative UI是重写并添加ViewManager

4, 将MainReactPackage()和JReactPackage()添加注册到ReactInstanceManager中。
其中MainReactPackage()及JReactPackage()必须, 否则报错'StatusBarManager' could not be found. Verify that a module by this name is registered in the native binary.
在这里插入图片描述

JReactPackage()否则报错, 找不到RNBridge.toast({toast:'正在取号中,请稍后...'})

5, ReactNative中导出在NativeModules中已注册的JRNBridge。然后在ReactNative各个地方引入并使用。
在这里插入图片描述

ReactNative端源码

import RNBridge from '@bridge/index'
<TouchableOpacity onPress={()=>{RNBridge.toast({toast:'正在取号中,请稍后...'})}} >

Flutter仿抖音我的页面

Flutter热更新

Flutter热更新,通过动态.so文件的加载实现。

.so文件动态加载实现思路
以反射修改FlutterLoader.java类FlutterApplicationInfo.aotSharedLibraryName的值,从而修改了FlutterLoader将要加载的原libapp.solibapp**.so。之后,将用来替换的libapp**.so拷贝到原libapp.so所在的目录即可。拷贝的方式,如首先打包一个新的release-apk,然后解压提取出此时的libapp.so文件(修改名称为libapp**.so),放到目录assets/下。之后,当执行代码拷贝时,会将assets/目录下的so包拷贝到新指定的将会加载的libapp.so所在的目录,然后则顺理成章完成热更新。

在这里插入图片描述

在这里插入图片描述

多FlutterEngine引擎创建,多dart入口实现

flutter一个投资理财页,作为第二个dart入口。并通过下面定义的对应引擎启开。
在这里插入图片描述

多FlutterEngine引擎创建

通过FlutterEngine创建引擎实例对象。创建时传入的JFlutterLoader,重新定义了原FlutterLoader获取dart代码包的方式。之后,根据给定的DartEntrypoint开始执行Dart代码。并缓存已创建的Flutter引擎实例。其中传入给DartEntrypointmoduleName是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
}

多dart入口创建

// 在flutter的dart代码中main.dart
// 至少有一个默认入口,如 'main'
void main() {runApp(const MyApp());init();
}// 此时,可仿照默认入口,通过注解,创建多个不同的dart入口 - 工行的'投资理财'详情页面
@pragma('vm:entry-point')
void finance() {runApp(FinanceEntryApp());
}

结合Flutter源码,分析从原生端启动Flutter

原生与Flutter通信

在这里插入图片描述

类型说明
MethodChannel用于传递方法调用invokeMethod一次性通信:如Flutter调用埋点功能。

这里且介绍MethodChannel,在Native与Flutter间如何通信~Flutter侧发送,Native侧接收处理。
Flutter侧发送,结合源码看,通过创建一个MethodChannel实例并指定渠道名称name。且两侧的name须一致相同。然后使用MethodChannel实例调用执行方法invokeMethod,该方法传入Native侧将被调用方法名称method及通信消息内容arguments。之后,便启动了由Flutter向Native侧传递调用。
Native侧接收处理,创建一个与Flutter侧渠道名称name相同的MethodChannel实例。使用MethodChannel实例调用执行方法setMethodCallHandler,用以匹配Flutter侧方法名称method接收处理Flutter侧发送来的信息。详尽设计实现,请移步查看

ReactJs仿唯品会分类页面

详尽开发介绍,请移步查看

工程源码地址

点击进入仓库,查看工程源码


http://chatgpt.dhexx.cn/article/AjWBcd0O.shtml

相关文章

Android MVVM开发框架

MVVM 数据双向绑定&#xff0c;通过数据驱动UI&#xff0c;M提供数据&#xff0c;V视图&#xff0c;VM即数据驱动层 MVP框架图 &#xff08;图片来源于网络&#xff09; 学习MVVM开发框架&#xff0c;要先了解DataBinding&#xff0c;DataBinding 是什么&#xff1f; DataBi…

Android: 开发框架设计

Android 开发框架 Android运用框架的目的不外乎是实现代码的代码解耦、逻辑分类、快速集成 便于维护等目的&#xff1b;Android 开发架构从早期的MVC &#xff0c;到近年到MVP 架构&#xff0c;到最近流行到MVVM 架构。不断到对业务逻辑、代码结构进行分层&#xff0c;便于快速…

安卓框架

http://www.cnblogs.com/jincheng-yangchaofan/articles/7018780.html 框架&#xff1a;提供一定能力的小段程序 一.榜单介绍 排行榜包括四大类&#xff1a; 单一框架&#xff1a;仅提供路由、网络层、UI层、通信层或其他单一功能的框架 混合开发框架&#xff1a;提供开发hy…

安卓应用开发顶级框架大盘点,总有一款适合你

作者 | Slava Vaniukov 译者 | 苏本如&#xff0c;责编 | 夕颜 封图 | CSDN下载自视觉中国 出品 | CSDN&#xff08;ID:CSDNnews&#xff09; 随着软件开发向移动应用的转变&#xff0c;越来越多的企业意识到&#xff0c;移动应用程序对于企业和客户之间建立牢固的联系至关重要…

嵌入式Android底层开发(一)——安卓开发的整体框架与简述

一、Android简介 Android是一种基于Linux内核&#xff08;不包含GUN组件&#xff09;的自由及开放源代码的操作系统&#xff0c;主要使用于移动设备&#xff0c;如智能手机和平板电脑&#xff0c;由美国Google公司和开放手机联盟领导及开发。 主要参数表&#xff1a; 参数上…

Android 框架

背景 我们有一个需求&#xff1a;我们需要查询用户账号信息&#xff0c;用户输入账号&#xff0c;点击按钮可进行查询账号信息&#xff0c;如果查询数据成功&#xff0c;则将数据展示在界面上&#xff1b;如果查询数据失败&#xff0c;则在界面上提升获取数据失败。 假如说我们…

Android - 框架使用

目录 1 Gson解析JSON 1.1 引入依赖 1.2 使用 1.3 安装插件 1.4 Demo 2 下滑刷新&#xff0c;上滑加载新数据 2.1 背景 2.2 引入依赖 2.3 代码实现 3 加载网络图片 3.1 背景 3.2 引入依赖 3.3 代码实现 4 轮播图 4.1 引入依赖 4.2 代码实现 5 网络数据请求 Re…

Android 快速开发框架 集成框架

由于自己经常写项目&#xff0c;没有一个方便开发的一套框架怎么行&#xff0c;所以在日常开发总自己整理了一套&#xff0c;请各位过目&#xff0c;不喜勿喷。一个新项目搭建需要具备的环境:先导入我制作的jar包。添加必要的权限。需要一个Application初始化数据,下面开始调用…

Android应用-开发框架设计

目录 1. &#x1f4c2; 简介 1.1 背景 1.2 专业术语 2. &#x1f531; 总体设计思想 2.1 分层&#xff1a;组件化设计框架 2.2 分类&#xff1a;应用开发架构图 3. ⚛️ 框架详细设计 3.1 组件化框架外形 3.2 业务模块化 3.3 代码编程框架 4. &#x1f4a0; 框架其他…

Android常用框架

1.缓存框架 1.1DiskLruCache&#xff1a;Java实现基于LRU的磁盘缓存&#xff0c;DiskLruCache不是google官方所写&#xff0c;但是得到了官方推荐&#xff0c;DiskLruCache没有编写到SDK中去&#xff0c;如需使用可直接copy这个类到项目中去。使用场景&#xff1a;如“清除…

Android开发框架大全

包括各种快速开发框架、测试框架、系统框架、插件补丁框架、设计模式框架、主题切换框架。 android-tips-tricks&#xff1a; https://github.com/nisrulz/android-tips-tricks Android 开发的一些 Tips 集合 Android-Code-Style&#xff1a; https://github.com/LoranWong/And…

Android开发常用开源框架

Android开源框架系列 Android开源项目 Android开发常用开源框架2 Android开发常用开源框架3 GitHub上最火的Android开源项目,所有开源项目都有详细资料和配套视频 2017年伊始&#xff0c;你需要尝试的25个Android第三方库 Android开发常用第三方平台 免费的计算机编程类中…

Android开发框架模式(MVC、MVP、MVVM)实例解析

Android项目中&#xff0c;尤其是比较大型的项目开发中&#xff0c;模块内部的高聚合和模块间的低耦合性就显得尤为重要了。所以我们一般情况下需要为项目设计一种框架模式&#xff0c;通常情况下我们一般用到的三种MVC、MVP、MVVM。 通过框架模式设计的项目能够极大的提高开发…

LDA主题模型评估方法–Perplexity

在LDA主题模型之后,需要对模型的好坏进行评估,以此依据,判断改进的参数或者算法的建模能力。 Blei先生在论文《Latent Dirichlet Allocation》实验中用的是Perplexity值作为评判标准。 一、Perplexity定义 源于wiki:http://en.wikipedia.org/wiki/Perplexity perplexity是一…

LDA困惑度perplexity的一些个人理解

纠结这个问题很久了&#xff0c;期间主要去了gensim的google论坛&#xff0c;以及在StackOverflow、StackexChange用关键词topic number perplexity搜了下&#xff0c;得到这些很模糊的认识&#xff1a; 1. gensim的log_perplexity()解读&#xff1a; 根据gensim3.8.3的源码&…

NLP基础知识点:困惑度(Perplexity)

本篇内容翻译自Speech and Language Processing. Daniel Jurafsky & James H. Martin. 链接&#xff1a;https://web.stanford.edu/~jurafsky/slp3/ 不愧是自然语言处理领域的圣经&#xff0c;读起来流畅自然&#xff0c;以后还是要多读经典。 困惑度&#xff08;Perplexit…

Python LDA gensim 计算 perplexity

转载自 https://blog.csdn.net/qq_23926575/article/details/79472742 1.LDA主题模型困惑度 这部分参照&#xff1a;LDA主题模型评估方法–Perplexity&#xff0c;不过后面发现这篇文章Perplexity(困惑度)感觉写的更好一点&#xff0c;两篇都是翻译的维基百科。 perplexity是一…

困惑度 (perplexity)

困惑度 (perplexity) 在自然语言处理中,对于一个语言模型,一般用困惑度来衡量它的好坏,困惑度越低,说明语言模型面对一句话感到困惑的程度越低,语言模型就越好。 对于LDA模型,最常用的两个评价方法困惑度(Perplexity)、相似度(Corre)。 其中困惑度可以理解为对于一篇…

Metric评价指标-Perplexity语言模型

欢迎关注知乎&#xff1a; 世界是我改变的 知乎上的原文链接 一. 原理介绍 在研究生实习时候就做过语言模型的任务&#xff0c;当时让求PPL值&#xff0c;当时只是调包&#xff0c;不求甚解&#xff0c;哈哈哈&#xff0c;当时也没想到现在会开发这个评价指标&#xff0c;那现…

perplexity和预训练时用的loss的区别

Perplexity和预训练时用的loss都是用来评估语言模型的性能的指标&#xff0c;但是它们的计算方式和意义有所不同。 Perplexity是一种用来衡量语言模型对一个测试集的预测能力的指标。它的计算方式是将测试集中的所有句子输入到语言模型中&#xff0c;计算每个句子的困惑度&…