Arquitetura de desenvolvimento híbrido | A engenharia do Android integra React Native, Flutter, ReactJs
- Descrição do projeto de arquitetura
-
- Criar projeto nativo do Android
- Criar Flutter
- Criar Reagir Nativo
- Projeto de arquitetura da barra de navegação inferior
- Endereço de origem do projeto
Descrição do projeto de arquitetura
Este artigo apresenta e registra detalhes e processos importantes no desenvolvimento da arquitetura híbrida de front-end grande. Ao integrar as duas principais estruturas híbridas React Native, Flutter e ReactJs[Vue] no projeto nativo do Android, o design híbrido da arquitetura dos três tipos de módulos é integrado. E na criação de negócios dessas pilhas de tecnologia convencionais, eles constroem suas próprias rodas, usam design de arquitetura inovador e tecnologias essenciais para alcançar. E no processo de codificação, ele também criará ferramentas comuns, barra de status imersiva , barra de navegação inferior , atualização dinâmica do Flutter, entrada múltipla do Flutter,
tabela 1 | tab2 | tab3 | tab4 | tab5 |
---|---|---|---|---|
Imitação da página inicial do China Merchants Bank | imitação de mensagens instantâneas | Imitação da página inicial do ICBC | imitação vibrato minha página | Classificação de imitação Vipshop |
Crie uma página inicial no projeto nativo e use-a na página inicial 五个TAB
.
TAB1
, usando codificação nativa Java+Kotlin, imitando a página inicial do China Merchants Bank, usando excelente design de arquitetura e completando o desacoplamento independente de cada módulo da lista.TAB2
, usando codificação nativa Java+Kotlin, imitando o WeChat e realizando mensagens instantâneas por meio do Android Socket.TAB3
, usando codificação React Native, imitando a página inicial do ICBC.TAB4
, usando codificação Flutter, imitando Douyin na minha página.TAB5
, codificado com ReactJs, imitando a página de classificação do Vipshop.
Criar projeto nativo do Android
Versão do Android Studio | versão do plug-in gradle | versão gradle | versão kotlin | Versão do JDK | outro |
---|---|---|---|---|---|
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 |
Criar Flutter
Versão do Android Studio | versão do plug-in gradle | versão gradle | Versão do JDK | outro |
---|---|---|---|---|
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 a engenharia nativa
Introdução detalhada da integração, por favor mova para ver
Criar Reagir Nativo
Comparado com a criação do Flutter, a criação do projeto React Native é muito mais complicada. Ao criar, você encontrará o problema de falha na criação. Após a criação bem-sucedida, você também encontrará o problema de relatório de erros ao iniciar o serviço Metro . E essas questões estão todas relacionadas a nodejs版本
. Por favor, leia a documentação oficial do ambiente de construção em detalhes ,React Naitve版本
Instrução de criação do React Native:
npx react-native init hibrid_rn --version 0.67.0
Instrução de inicialização do serviço Metro:npx react-native start
Instrução de compilação e instalação do Android apk:yarn android
versão do nó | Reagir versão nativa | Versão do JDK | ilustrar |
---|---|---|---|
v16.17.0 | 0,67,0 | JDK11 | Para obter o número da versão detalhada, mova para ver o código |
Resolva o problema do erro RN
Se houver um erro, o seguinte
如下报错信息,则是node版本号使用不当导致~
/node_modules/@react-native-community/cli/build/commands/doctor/healthchecks/index.js:48
} catch {}
^
SyntaxError: token inesperado { em createScript (vm.js:80:10) em Object.runInThisContext (vm.js:139:10) em Module._compile (module.js:617:28) em Object.Module._extensions…js (module.js:664:10) … … …
Se houver um erro, o seguinte
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).
Solução, especifique ReactNative para determinar o número da versão !! Modifique ReactNative paraapp/build.gradle
implementation "com.facebook.react:react-native:+"
implementation "com.facebook.react:react-native:0.67.0"
Se houver um erro, o seguinte
Execution failed for task ':app:mergeDebugNativeLibs'.
More than one file was found with OS independent path 'lib/x86_64/libfbjni.so'
A solução é adicionar o erro relatado na captura de tela no 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 a engenharia 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
}
}
Descrição do campo de parâmetro:
entryFile : "index.android.js"
, indicando o nome do arquivo de entrada de recurso Android de carregamento de configuração.def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/"
, indicando queenableHermes==true
naquela época , o motor de execução Hermes foi introduzido. Caso contrário, o mecanismo de execução JavaScriptCore é usado.
Hermes é um recurso opcional do React Native. Se você deseja habilitar o Hermes, precisa garantir que a versão do projeto React Native esteja
0.60.2版本
acima e também precisaandroid/app/build.gradle
fazer as seguintes alterações no . Nós configuramos aquienableHermes: false
project.ext.react = [
entryFile: "index.js",
enableHermes: true // 配置开启Hermes引擎
]
Depois que o RN estiver integrado, inicie um erro
Depois de integrar o RN no projeto nativo, use o React Native como parte do LayoutView na Activity do projeto nativo para testar o status da integração. Descobriu que iniciar o React Native do Native relatou o seguinte erro ~
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.
A mensagem de erro dizia que o serviço Metro não foi iniciado ou que o pacote de recursos do bundle não foi encontrado. O fato é que o serviço Metro atual foi iniciado e não há problema em iniciar diretamente o projeto React Native. Existem duas soluções para isso:
- Empacote o código do projeto atual
React Native
e copie o código do pacotebundle资源
para o diretório do projeto Nativo/main/assets/rn
. Então não há problema em rodar em Nativo. - O terminal VSCode executa instruções de empacotamento:
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/
- Desempacotado. Ambos Native e React Native precisam ser configurados. ① Configure o IP do serviço e o número da porta para o APP do pacote de depuração instalado. ②Configurar permissões de rede,
application标签
configurar no meiotools:targetApi="28" android:allowBackup="true"
. ③ Inicie o serviço Metro.
Projeto de arquitetura da barra de navegação inferior
Use a linguagem java para personalizar o controle de layout da barra de navegação na parte inferior da página inicial (o efeito + código fonte de navegação na figura abaixo ) e introduza a UML personalizada~
TabBtnLayoutBottomNav
Exibição personalizada do layout da barra de navegação inferior. Herdado de FrameLayout, implementado a partir da interface ITabLayout. Layout da barra de navegação inferior, posicionamento internoTabBtnBottom
,TabBtnBottom
Uma única guia em um layout de barra de navegação inferior. Herdado de RelativeLayout, implementado a partir da interface I ITab (ITab herda a interface de escuta de evento de clique OnTabSelectedListener).TabBtnLayoutBottomNav
Encapsula internamente uma única coleção TabList<OnTabSelectedListener>
(incluindo todo o monitoramento OnTabSelectedListener adicionado por TabBtnBottom e TabBtnLayoutBottomNav)TabBtnBottom.setOnClickListener
. , e o retorno de chamada de monitoramento adicionado por TabBtnLayoutBottomNav. Como resultado, um único Tab e TabBtnLayoutBottomNav são associados a eventos de clique e podem preparar o caminho para a exibição integrada de comutação de cliques de fragmentos.
TabBtnFragmentLayout
, para exibir o ** controle de layout personalizado ** da página de fragmento e colocá-lo no arquivo de layout TabBtnLayoutBottomNav. O índice de retorno de chamada de monitoramento adicionado por TabBtnLayoutBottomNav, o métodosetCurrentItem
obtém instruções e exibe a página de fragmento correspondente.TabBtnFragmentAdapter
, para exibir a classe do adaptador para a página de fragmento. As instruções específicas mostram a lógica da página de fragmento, que é implementada no métodoinstantiateItem
.
Imitação original da página inicial do China Merchants Bank
Mensagens instantâneas nativas do Android Socket
React Native imita a página inicial do ICBC
Use o RN para imitar a página inicial do Industrial and Commercial Bank of China (encontrei o ícone com dificuldade) e, em seguida, perceba o efeito StatusBar和TitleBar
aleatório . **滑动渐变**
Aqui, inicie e abra o RN pelo nativo, o efeito é o seguinte~
Passar nativamente o objeto inicial de props, RN usa
// 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 se comunicar com RN
Introdução do efeito alcançado
Um método para chamar Android ToastJRNBridge.kt
é definido na classe de ponte do lado Nativo para o lado ReactNative chamar. O efeito é o seguinte
Notas durante o desenvolvimento
Aqui tomamos este projeto como exemplo para introduzir a lógica das etapas de desenvolvimento ao realizar a comunicação entre RN e C-side.
1. Defina a ferramenta de ponte no lado C do código-fonte lógicoJRNBridge.kt
. A classe ponte herda de ReactContextBaseJavaModule.java, o método de implementação getName
- o nome obtido será usado no lado ReactNative,
// bridge/index.js
import {
NativeModules} from 'react-native'
module.exports = NativeModules.RNBridge // 这里的 RNBridge 就是getName得到。
2. O método de comunicação entre ReactNative e C-side Native precisa ser anotado@ReactMethod
.
3. Crie JReactPackage.kt para herdarReactPackage.kt
e reescrever o métodocreateNativeModules和createViewManagers
. O método de reescritacreateNativeModules
é adicionar JReactPackage à lista NativeModule para registro subsequente.
createNativeModules | createViewManagers |
---|---|
Reescrever e adicionar NativeModule quando ReactNative chamar o método Native | Native UI, já que ReactNative UI foi reescrito e adicionado ViewManager |
4. Adicione e registre MainReactPackage() e JReactPackage() no ReactInstanceManager.
Entre eles, MainReactPackage() e JReactPackage() são obrigatórios, caso contrário, um erro será relatado'StatusBarManager' could not be found. Verify that a module by this name is registered in the native binary.
Caso contrário, JReactPackage() relata um erro e não consegue localizá-lo RNBridge.toast({toast:'正在取号中,请稍后...'})
.
5. Exporte o JRNBridge registrado em NativeModulesem ReactNativeEm seguida, introduza e use-o em vários lugares no ReactNative.
import RNBridge from '@bridge/index'
<TouchableOpacity onPress={
()=>{
RNBridge.toast({
toast:'正在取号中,请稍后...'})}} >
Flutter imita vibrato minha página
Flutter hot update
Flutter热更新,通过动态.so文件的加载实现。
A ideia do carregamento dinâmico dos arquivos .so é
refletir o valor que está sendo modificadoFlutterLoader.java类
,valorFlutterApplicationInfo.aotSharedLibraryName
original. Depois disso,copiar a substituição para odiretório original. A maneira de copiar, como empacotar um novo apk de lançamento primeiro, descompactar e extrair o arquivo libapp.so neste momento (renomeado para libapp**.so) e colocá-lo no diretório assets/. Posteriormente, quando o código for copiado, o pacote so no diretório assets/ será copiado para o diretório recém-especificado onde será carregadoe, em seguida, a atualização a quente será concluída logicamente.libapp.so
libapp**.so
libapp**.so
libapp.so
libapp.so
Crie vários mecanismos FlutterEngine e implemente várias entradas de dardo
Uma página de investimento e gestão financeira de flutter , como a segunda entrada de dardo. E aberto pelo motor correspondente definido abaixo.
Crie vários mecanismos FlutterEngine
Criando FlutterEngine
um objeto de instância do mecanismo. Ele é passado durante a criação JFlutterLoader
e redefine dart代码包
a maneira como o FlutterLoader original o obtém. Depois disso, comece a executar o código Dart de acordo com o DartEntrypoint fornecido. E armazene em cache a Flutter引擎
instância criada. que é passado DartEntrypoint
para 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
}
Criar várias entradas de dardo
// 在flutter的dart代码中main.dart
// 至少有一个默认入口,如 'main'
void main() {
runApp(const MyApp());
init();
}
// 此时,可仿照默认入口,通过注解,创建多个不同的dart入口 - 工行的'投资理财'详情页面
@pragma('vm:entry-point')
void finance() {
runApp(FinanceEntryApp());
}
Combinado com o código-fonte do Flutter, analise a inicialização do Flutter a partir da ponta nativa
Comunicação nativa com Flutter
tipo | ilustrar |
---|---|
MétodoCanal | Comunicação única usada para transferir invokeMethod chamadas de método: como chamar a função de ponto enterrado do Flutter. |
Aqui vamos apresentar o MethodChannel , como se comunicar entre Native e Flutter~ O lado Flutter envia e o lado Native recebe e processa.
Flutter侧发送
, combinado com o código-fonte, criando um MethodChannel实例
e especificando o nome do canal name
. E ambos os lados name
devem ser iguais. Em seguida, use a instância MethodChannel para chamar e executar 方法invokeMethod
, e será chamado o método passado para o lado Nativo 方法名称method
e o conteúdo da mensagem de comunicação arguments
. Depois disso, a chamada de transferência do Flutter para o lado nativo é iniciada.
Native侧接收处理
, crie um canal com name
o mesmo nome do canal lateral do Flutter MethodChannel实例
. Use a instância MethodChannel para chamar e executar 方法setMethodCallHandler
para corresponder Flutter侧方法名称method
às informações de recebimento e processamento enviadas do lado do Flutter. Projeto e implementação detalhados, mova para ver
Página da categoria Vipshop de imitação do ReactJs
Introdução de desenvolvimento detalhada, mova para ver
Endereço de origem do projeto
Clique para entrar no warehouse para ver o código-fonte do projeto