iOS端创建ReactNative容器第一步:打出jsbundle和资源包

react-native的打包流程是通过执行react-native bundle指令进行的。
添加构建指令
修改RN项目中的package.json文件,先其中添加构建命令build-release-ios和build-debug-ios

复制代码
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"test": "jest",
"build-release-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev false ",
"build-debug-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev true "
},

说明如下;
react-native的打包是使用的命令react-native bundle, 然后再根据需要添加对应的参数。
--entry-file ,ios或者android打包入口的js文件名称,比如index.js(如果要根据不同的平台添加不同的功能,则需要将安卓和iOS的打包入口分开创建index.ios.js, index.android.js)
--platform ,平台名称(ios或者android)
--dev ,设置为false的时候表示为发布包,true为测试包,发布包会对JavaScript代码进行优化处理。
--bundle-output, 生成的jsbundle文件的名称,比如 ./dest/bundle/index.jsbundle
--assets-dest 图片以及其他资源存放的目录,比如./dest/bundle, 注意这里导出的资源是在jsbundle中通过引用使用的资源。
开始打包
打开RN项目,执行下面的打包指令进行打包

复制代码
npm run build-release-ios
或者
yarn build-release-ios

指令执行完成后,打包的产物是放置在了./dest/bundle/目录之下

内置打包产物
将jsbundel包和assets资源包拖到项目中,放置到同一个目录下。

然后修改jsbundle的读取位置,将从服务器读取改成从本地读取。

复制代码
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{

  return [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"jsbundle"];

//  return [self getBundleURL];
}

- (NSURL *)getBundleURL
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

在iOS项目中,根据不同的业务类型加载不同的模块名称

复制代码
  RNContainerController * containerVC = [[RNManager sharedInstance] loadWithModuleName:@"News" initialProps:@{}];
  [self presentModalViewController:containerVC animated:YES];


JSBundle产物介绍
RN 通过执行react-native bundle打包命令得到产物JSBundle。

复制代码
"build-debug-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev true "

因为我们平时写的RN模块中会使用到图片,git,json文件这些资源,所以打出的产物也包含了js文件和资源文件。
产物JSBundle内容组成

复制代码
//1.全局变量定义
var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=true,process=this.process||{},__METRO_GLOBAL_PREFIX__='',__requireCycleIgnorePatterns=[/(^|\/|\\)node_modules($|\/|\\)/];process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"development";
//2.require, clear全局函数声明
(function (global) {
  "use strict";

  global.__r = metroRequire;
  global[`${__METRO_GLOBAL_PREFIX__}__d`] = define;
  global.__c = clear;
  global.__registerSegment = registerSegment;
  var modules = clear();
  var EMPTY = {};
  var CYCLE_DETECTED = {};
  var _ref = {},
    hasOwnProperty = _ref.hasOwnProperty;
  if (__DEV__) {
    global.$RefreshReg$ = function () {};
    global.$RefreshSig$ = function () {
      return function (type) {
        return type;
      };
    };
  }
})()
//3.RN模块定义(包括RN框架自己的,第三方库的,用户自定义的)
__d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) {
xxx
xxx
xxx
},544,[1,262,306,21,50,91],"node_modules/react-native/Libraries/NewAppScreen/components/ReloadInstructions.js");
__d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) {
  var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0], "@babel/runtime/helpers/interopRequireDefault");
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = News;
  var _react = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1], "react"));
  var _reactNative = _$$_REQUIRE(_dependencyMap[2], "react-native");
  var _jsxRuntime = _$$_REQUIRE(_dependencyMap[3], "react/jsx-runtime");
  var _jsxFileName = "/Users/admin/Documents/MyFile/react-native-container/src/News.tsx";
  function News(params) {
    return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.SafeAreaView, {
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
          style: {
            color: 'red'
          },
          children: "Hello ReactNative"
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Switch, {
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
            children: "\u5F00\u5173"
          })
        })]
      })
    });
  }
},545,[1,50,2,91],"src/News.tsx");
__d(function(global, require, _importDefaultUnused, _importAllUnused, module, exports, _dependencyMapUnused) {
  module.exports = {
  "name": "AwesomeProject",
  "displayName": "AAAAA"
}
;
},546,[],"app.json");
//4.require方法调用
__r(54);
__r(0);

从上面内容可知,jsbundle有四部分组成:
1.var 全局变量声明,包括对当前运行环境的定义,bundle 的启动时间、Process进程环境相关信息;
2.在(function() { })() 闭包中定义了对 define(__d)、 require(__r)、clear(__c) 的支持,以及 module(react-native及第三方dependences依赖的module) 的加载逻辑;
3.使用__d定义的模块信息,包括RN框架源码 js 部分、自定义js代码部分、图片资源信息,供 require 引入使用;
4.通过require执行模块代码,找到 __d 定义的代码块并执行,其中require中的数字即为 __d定义行中最后出现的那个数字。
参考文章:https://blog.csdn.net/qq_24694139/article/details/107540009