写点什么

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:031819

评论 1 条评论

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

盲盒h5小程序app系统开发

盲盒开发一番赏盲芒趣蛋趣小程序app开发

盲盒小程序开发盲盒源码搭建

初识 .NET6

面向对象的猫

.net core .net6

进击的Java(九)

ES_her0

11月日更

怎么自学Python,大概要多久?

老表

Python 11月日更 编程入门 思路 如何解决问题

盲盒开发源码搭建小程序app

当AI能够在15分钟内部署,世界距离大变革不远了

百度大脑

人工智能

去安定医院看失眠,有必要吗?

脑极体

盲盒小程序开发源码搭建

支撑长安链运行,区块链算力平台是什么?

CECBC

飞桨中国行——企业服务专场

百度大脑

人工智能

自定义View:多点触摸画笔的实现

Changing Lin

11月日更

.NET6 内置IOC容器

面向对象的猫

.net core .net6

选择 Pulsar 而不是 Kafka 的 7 大理由

Apache Pulsar

kafka 架构 云原生 中间件 Apache Pulsar

从消息到数据湖:看 Apache RocketMQ、Hudi、Kyuubi 最新进展

阿里巴巴云原生

数据湖 Meetup Apache RocketMQ Apache Hudi Apache Kyuubi

大数据训练营一期1017作业

朱磊

盲盒开发盲盒小程序系统开发

以用户体验为抓手,助力券商数字化转型

博睿数据

盲盒app开发

如何用Camtasia为“微课”视频添加光标效果?

淋雨

Camtasia

一个基于PoS共识算法的区块链实例解析(升级版)

Regan Yue

区块链 共识算法 Go 语言 11月日更

盲盒开发

公司应该监控员工的上网行为吗?

石云升

职场经验 11月日更

Android C++系列:Linux文件IO操作(一)

轻口味

c++ android jni 11月日更

Kafka 已落伍,转角遇见 Pulsar!

Apache Pulsar

kafka 架构 分布式 Apache Pulsar 消息系统

对比 Apache Kafka 和 Apache Pulsar 创建工作队列

Apache Pulsar

kafka 分布式 中间件 Apache Pulsar 工作队列

Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)

不脱发的程序猿

Python qt PyQt GUI设计 多线程中信号与槽的使用

社科院专家认为元宇宙是双刃剑,将带来五大巨变

CECBC

ARP欺骗与防范

喀拉峻

网络安全 安全 信息安全

Flink CDC 2.1 正式发布,稳定性大幅提升,新增 Oracle,MongoDB 支持

Apache Flink

大数据 flink 后端 实时计算 CDC

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