NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

mand-mobile-rn 多 Android Module link 实现

  • 2019-09-19
  • 本文字数:3958 字

    阅读完需:约 13 分钟

mand-mobile-rn 多 Android Module link 实现

在 react-native 生态中,包含原生 android 代码的 library 项目,都是通过项目的根文件夹中的 android 文件夹或者 android 文件夹下的 app 文件夹作为 library module 提供外部依赖。mand-mobile-rn 通过 rnpm 接口实现了对 react-native library 项目多个 Android module 的 link 实现。


mand-mobile-rn 是滴滴金融 FE 团队开发的面向金融场景的 react-native 组件库。


使用 react-native 的小伙伴,一定对下面列出的 react-native library 项目比较熟悉,这些组件都是通过封装原生模块或源生 UI 组件提供 react-native 侧调用。


  • react-native-vector-icons

  • react-native-svg

  • react-native-linear-gradient


上述列出的项目在 package.json 依赖 yarn 之后,调用 react-native link 命令,会在 Android 侧依赖引入相应的 library module,提供 react-native 依赖 Android 源生模块或者组件。


rootProject.name = 'samples'include ':react-native-vector-icons'project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')include ':react-native-svg'project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')include ':react-native-linear-gradient'project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')include ':app'
复制代码


通过 link 这三个项目,可以看出都是添加 android 目录的相对路径到 settings.gradle 提供外部依赖。


在 react-native 生态中,包含原生 android 代码的 library 项目,都是通过项目的根文件夹中的 android 文件夹或者 android 文件夹下的 app 文件夹作为 library module 提供外部依赖。


在 mand-mobile-rn 中,分别对 ImagePicker,RefreshControl,NumberKerboard 三个原生模块创建了三个原生 android module 提供外部依赖,有别于传统的 react-native library 项目,这三个 module 文件夹并没有放在 android 文件夹下(即使放在 android 文件夹下,也无法同时 link 这个三个 module)。


.├── android├── build├── docs├── gradle├── ios├── samples├── scripts├── sites├── src│   ├── _styles│   ├── _utils│   ├── assets│   ├── components│   └── natives│       ├── Core│       ├── ImagePicker│       │   ├── android│       │   └── ios│       ├── NumberKeyboard│       │   ├── android│       │   └── ios│       └── RefreshControl│           ├── android│           └── ios├── template└── tests
复制代码


mand-mobile-rn 是如何提供使用方集成的?通过下面的文章,来一步一步介绍。

1.react-native link 命令是如何实现的?

在上文中写到 “即使放在 android 文件夹下,也无法同时 link 这个三个 module” ,真的是这样吗?下面通过 react-native-cli 项目的源码来证实。


在 packages/cli/src/core/android/findAndroidAppFolder.js 文件中,定义了如下代码,用来寻找 link 的 library 项目中的 android 目录。


export default function findAndroidAppFolder(folder) {  const flat = 'android';  const nested = path.join('android', 'app');
if (fs.existsSync(path.join(folder, nested))) { return nested; }
if (fs.existsSync(path.join(folder, flat))) { return flat; }
return null;}
复制代码


这段代码可以看出,首先判断 android/app 文件夹是否存在,如果不存在,继续判断 android 文件夹是否存在。通过代码也就说明了,react-native link 命令,只会调用 library 项目根下的 android/app 或者 android 文件夹作为 library module,提供外部依赖。

2.react-native-code-push 引发的思考

在集成 react-native-code-push 时,code push 会让你输入


”deployment key“,这和其他的 react-native library 项目的行为并不一致。在阅读 react-native-code-push 源码时, 发现 package.json 中有如下声明。


"rnpm": {    "android": {      "packageInstance": "new CodePush(${androidDeploymentKey}, getApplicationContext(), BuildConfig.DEBUG)"    },    "ios": {      "sharedLibraries": [        "libz"      ]    },    "params": [      {        "type": "input",        "name": "androidDeploymentKey",        "message": "What is your CodePush deployment key for Android (hit <ENTER> to ignore)"      }    ],    "commands": {      "postlink": "node node_modules/react-native-code-push/scripts/postlink/run"    }  }
复制代码


这段声明,看起来就是让输入”deployment key“的原因。


通过 Google,可以搜索到 rnpm 项目(https://github.com/rnpm/rnpm ),在 react-native v0.27 版本时,合并进入 react-native-cli,但是 react-native-cli 文档中并没有详细介绍 rnpm,具体介绍和使用还要看 https:// github. com/rnpm/rnpm 。


通过阅读文档,可知 commands prelink/postlink 可以指定脚本,用来 hook react-native link 命令执行前和执行后。


react-native-code-push 利用 postlink 来执行 node 脚本进行依赖代码的写入。


react-native-code-push 脚本代码:


https:// github. com/Microsoft/react-native-code-push/blob/master/scripts/postlink/android/postlink.js

3.mand-mobile-rn 实现

为了实现一次调用 link 命令,集成三个 android module,mand-mobile-rn 使用和 react-native-code-push 同样的原理,通过在 commands postlink 指定脚本,写入代码实现依赖。


注册一个 library 原生模块或原生组件到 react-native Android 工程中,大概需要如下三个步骤:


注册组件 module 到 ./android/settings.gradle


在 ./android/app/build.gradle 中声明依赖 module


在 ReactNativeHost.getPackages() 中注册组件的 package

applyPatch.js

上述的三个步骤,都要写入代码到文件中,因此定义一个 applyPatch.js 文件作为写入代码工具方法,代码如下:


var fs = require('fs')
function applyPatch(patch) { if (!fs.existsSync(patch.path)) { return Promise.reject(patch.noExistNotice) } var content = fs.readFileSync(patch.path, 'utf-8')
console.log(`Writing ${patch.path}`)
if (~content.indexOf(patch.patch)) { console.log(patch.alreadyAddedNotice) } else { fs.writeFileSync( patch.path, content.replace(patch.pattern, (match) => `${match}${patch.patch}`), ) } return Promise.resolve()}
module.exports = applyPatch
复制代码


读取目标文件内容,然后替换匹配的内容,最终再次写回到文件当中。

natives.json

因为每个模块的命名和路径肯定是不同的,同时为了方便 js 读取,定义 natives.json 文件来声明每个原生模块的全路径名和 module 位置。代码如下:


[  {    "moduleName": "mand-mobile-image-picker",    "packageName": "com.mandmobile.react.imagepicker.MDImagePickerPackage",    "modulePath": "src/natives/ImagePicker/android"  },  {    "moduleName": "mand-mobile-number-keyboard",    "packageName": "com.mandmobile.MDNumberKeyboardPackage",    "modulePath": "src/natives/NumberKeyboard/android"  },  {    "moduleName": "mand-mobile-refresh-control",    "packageName": "com.mandmobile.react.refreshcontrol.MDRefreshControlPackage",    "modulePath": "src/natives/RefreshControl/android"  }]
复制代码

android/postlink.js

通过读取 natives.json 获取需要写入的组件,然后通过 Promise 顺序分别写入 settings.gralde,app/build.gradle,MainApplication。


module.exports = () => {  console.log('Running android postlink script')  if (!nativeModules || nativeModules.lenght == 0) {    return Promise.reject()  }
return applyPatch(rootBuildGradlePatch()) .then(() => applyPatch(settingGradlePatch(nativeModules))) .then(() => applyPatch(appBuildGradlePatch(nativeModules))) .then(() => applyPatch(importApplicationPatch(nativeModules))) .then(() => applyPatch(packagePatch(nativeModules)))}
复制代码

settingGradlePatch.js

settingGradlePatch.js 负责组织写入数据,以符合 applyPatch.js 执行写入。代码如下:


function settingGradlePatch(mandMobilPath,natives) {  var patch = ''
for (native of natives) { patch += `include ':${native.moduleName}'project(':${native.moduleName}').projectDir = new File(rootProject.projectDir, '../${mandMobilPath}/${native.modulePath}')` }
return { path: path.join('android', 'settings.gradle'), pattern: /include\s* \'\:app\'/, patch, noExistNotice: `Couldn't find "settings.gradle" file. Please see Doc`, alreadyAddedNotice: `"settings.gradle" is already linked`, }}
复制代码


appBuildGradlePatch,importApplicationPatch 等原理大同小异,都是通过正则匹配之后写入代码,不再重复。这里是源码入口

4.总结

rnpm 极大方便了 react-native library 开发方,把复杂的依赖方式,写成脚本注入到代码中。通过 rnpm ,未来 mand-mobile-rn 可以扩展在 link 命令集成时,在命令行中选择是否依赖源生模块,以及依赖那个原生模块。


本文转载自公众号滴滴技术(ID:didi_tech)。


原文链接:


https://mp.weixin.qq.com/s/Cn0MRzZi7VPNDm_kGtRkwA


2019-09-19 17:031900

评论 1 条评论

发布
用户头像
竟然看到自己多年前的文章。
2022-09-02 20:05 · 北京
回复
没有更多了
发现更多内容

判例学习(一)梨视频诉字节跳动帮助侵权二审判决

Yin

学习 读书笔记 互联网 知识产权 法律

【写作群星榜】5.29~6.4写作平台优秀作者&文章排名

InfoQ写作社区官方

写作平台 排行榜 热门活动

ARTS-WEEK02

子路无倦

MyBatis启动之XMLConfigBuilder解析配置文件(二)

ytao

后端 mybatis

过滤器 和 拦截器 6个区别,别再傻傻分不清了

程序员小富

Java

深入理解Java虚拟机

SkyeDance

深入理解JVM

分布式架构,刚性事务-2PC必须注意的问题及3PC详细解

奈学教育

分布式架构 2PC注意事项 3PC详解

hexo博客系统的实现原理与搭建

音视频专家-李超

Hexo 博客

强烈安利第一个画图工具!

我是程序员小贱

高效工作 高效

万字总结——反射(框架之魂)

学习Java的小姐姐

Java 反射 Java 25 周年

如何让解决无法访问 GitHub 的问题?

JackTian

GitHub

Silicon Labs Gecko bootloader 简介

taox

zigbee bootlaoder

别做误人子弟的「职业导师」

Tony Wu

职业成长 导师 教练

TCP 半连接队列和全连接队列满了会发生什么?又该如何应对?

小林coding

Linux TCP 网络安全 计算机网络 网络协议

游戏夜读 | 网络游戏怎么赚钱?

game1night

python3.8.3安装ipython和jupyter

肖飞码字

python3.x Jupyter Notebook

大数据中台之Kafka,到底好在哪里?

奈学教育

kafka

预告|2020中国CRM品牌测评报告

人称T客

深入理解JVM垃圾回收机制 - 何为垃圾?

SkyeDance

深入理解JVM 垃圾回收机制

使用ADMT和PES实现window AD账户跨域迁移-介绍篇

BigYoung

windows AD ADMT PES 迁移

Android工程架构演进及康威定律

石头

【大厂面试03期】MySQL是怎么解决幻读问题的?

NotFound9

MySQL 数据库 编程 架构

机器学习算法评估指标——2D 目标跟踪

做技术BP的文案Gou

学习 2D 评估标准

C++:两百字三段代码解决函数返回局部变量问题

韩小非

c++ 函数栈调用 返回局部变量

我是一个连地摊都不会摆的废人

Neco.W

创业 投机 投机者 地摊

白天写代码,晚上摆地摊!9年前摆地摊学会了这些道理...

王磊

5G时代,如何彻底搞定海量数据库的设计与实践

奈学教育

海量数据库的设计与实践

原创 | TDD工具集:JUnit、AssertJ和Mockito (十七)编写测试-标签和过滤

编程道与术

Java 编程 TDD 单元测试 JUnit

centos6.9开机启动服务说明

唯爱

HTML5 && CSS

shirley

html5 css3

NIO 看破也说破(五): 搞,今天就搞,搞懂Buffer

小眼睛聊技术

Java 学习 读书笔记 架构 后端

mand-mobile-rn 多 Android Module link 实现_文化 & 方法_游子聪_InfoQ精选文章