Skip to content

Commit

Permalink
Add react native 61+ support
Browse files Browse the repository at this point in the history
  • Loading branch information
belemaire committed Apr 27, 2020
1 parent 38b01c7 commit 632adc7
Show file tree
Hide file tree
Showing 44 changed files with 1,759 additions and 1,806 deletions.
4 changes: 2 additions & 2 deletions docs/platform-parts/container/container-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,14 @@ It is possible to change these defaults, using the `androidConfig` object of `co
"containerGenerator": {
"androidConfig": {
"jsEngine": "jsc",
"jscVersion": "245459",
"jscVersion": "^245459.0.0",
"jscVariant": "android-jsc"
}
}
}
```

`jscVersion` is the version of the JavaScriptCore engine while `jscVariant` is the variant (`android-jsc` or `android-jsc-intl`).
`jscVersion` is the version (fixed or range) of the JavaScriptCore engine while `jscVariant` is the variant (`android-jsc` or `android-jsc-intl`).

_Hermes_

Expand Down
29 changes: 27 additions & 2 deletions docs/platform-parts/manifest/native-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ This example shows how to replace the string `"RCTBridgeModule.h"` with `<React/
Apply a given patch file, by running `git apply` command, from a specific directory.
The value of this property should be a single object containing the following two properties :
- `patch` : Path to the patch file to apply, relative to the directory containing the pluging configuration file (`config.json`).
- `root` : Path to the directory from which to run the `git apply` command, relative to the container generator output directory.
- `root` : Path to the directory from which to run the `git apply` command, relative to the container generator output directory. Mutually exclusive with `inNodeModules`.
- `inNodeModules` : If true, root will be set to root location of the plugin in node nodules. Mutually exclusive with `root`.

**Example**

Expand Down Expand Up @@ -286,4 +287,28 @@ For example setting `ENABLE_BITCODE` to `NO` for `Debug` and `Release` configura
}
}
]
```
```

**The following directives are only available when using React Native >= 0.61.0**

- `podFile`

Path to a Podfile to use for the Container, relative to the directory containing the plugin config.json file.\
Can only be set in 'react-native' plugin configuration.


- `podspec`

Path to a podspec file to use for the plugin, relative to the directory containing the plugin config.json file.\
Can be used in case a native module doesn't have yet an available podspec file or if the podspec file of the native module needs to be different than the one shipped with it.

- `extraPods`

Array of extra pod statements that will be injected in the Container Podfile.

- `requiresManualLinking`

Boolean flag that indicates whether this plugin requires manual linking.\
If defined and set to `true`, all plugin directives will be processed.
If not defined (default) or set to false, only `podFile`, `podspec` and `extraPods` directives will be processed.\n
This should only be set to `true` in very rare cases, for plugins that do not support auto linking.
1 change: 1 addition & 0 deletions ern-api-impl-gen/src/ApiImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function ernifyPackageJson(
},
],
},
requiresManualLinking: true,
},
}
}
Expand Down
42 changes: 30 additions & 12 deletions ern-container-gen-android/src/AndroidGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,20 +363,24 @@ export default class AndroidGenerator implements ContainerGenerator {
this.getJavaScriptEngine(config) === JavaScriptEngine.JSC
? await kax
.task('Injecting JavaScript engine [JavaScriptCore]')
.run(this.injectJavaScriptCoreEngine(config))
.run(
this.injectJavaScriptCoreEngine(config, reactNativePlugin.version)
)
: await kax
.task('Injecting JavaScript engine [Hermes]')
.run(this.injectHermesEngine(config))
.run(this.injectHermesEngine(config, reactNativePlugin.version))
}
}

public async postBundle(
config: ContainerGeneratorConfig,
bundle: BundlingResult
bundle: BundlingResult,
reactNativeVersion: string
) {
if (this.getJavaScriptEngine(config) === JavaScriptEngine.HERMES) {
const hermesVersion =
config.androidConfig.hermesVersion || android.DEFAULT_HERMES_VERSION
config.androidConfig.hermesVersion ||
android.getDefaultHermesVersion(reactNativeVersion)
const hermesCli = await kax
.task(`Installing hermes-engine@${hermesVersion}`)
.run(HermesCli.fromVersion(hermesVersion))
Expand Down Expand Up @@ -421,24 +425,34 @@ export default class AndroidGenerator implements ContainerGenerator {
* Container. This way, the JSC engine is shipped within the Container and
* applications won't crash at runtime when trying to load this library.
*/
public async injectJavaScriptCoreEngine(config: ContainerGeneratorConfig) {
const jscVersion =
public async injectJavaScriptCoreEngine(
config: ContainerGeneratorConfig,
reactNativeVersion: string
) {
let jscVersion =
(config.androidConfig && config.androidConfig.jscVersion) ||
android.DEFAULT_JSC_VERSION
android.getDefaultJSCVersion(reactNativeVersion)
if (/^\d+$/.test(jscVersion)) {
// For backward compatibility, to avoid breaking clients
// that are already providing a version through config that
// only specifies major excluding minor/patch
jscVersion = `${jscVersion}.0.0`
}
const jscVariant =
(config.androidConfig && config.androidConfig.jscVariant) ||
android.DEFAULT_JSC_VARIANT
const workingDir = createTmpDir()
try {
shell.pushd(workingDir)
await yarn.init()
await yarn.add(PackagePath.fromString(`jsc-android@${jscVersion}.0.0`))
await yarn.add(PackagePath.fromString(`jsc-android@${jscVersion}`))
const versionMajor = semver.major(semver.coerce(jscVersion)!.version)
const jscVersionPath = path.resolve(
`./node_modules/jsc-android/dist/org/webkit/${jscVariant}/r${jscVersion}`
`./node_modules/jsc-android/dist/org/webkit/${jscVariant}/r${versionMajor}`
)
const jscAARPath = path.join(
jscVersionPath,
`${jscVariant}-r${jscVersion}.aar`
`${jscVariant}-r${versionMajor}.aar`
)
return new Promise((resolve, reject) => {
const unzipper = new DecompressZip(jscAARPath)
Expand All @@ -464,10 +478,13 @@ export default class AndroidGenerator implements ContainerGenerator {
* Inject hermes engine into the Container
* Done in a similar way as injectJavaScriptCoreEngine method
*/
public async injectHermesEngine(config: ContainerGeneratorConfig) {
public async injectHermesEngine(
config: ContainerGeneratorConfig,
reactNativeVersion: string
) {
const hermesVersion =
(config.androidConfig && config.androidConfig.hermesVersion) ||
android.DEFAULT_HERMES_VERSION
android.getDefaultHermesVersion(reactNativeVersion)
const workingDir = createTmpDir()
try {
shell.pushd(workingDir)
Expand Down Expand Up @@ -559,6 +576,7 @@ export default class AndroidGenerator implements ContainerGenerator {
plugins: PackagePath[],
outDir: string
): Promise<any> {
const rnVersion = plugins.find(p => p.name === 'react-native')?.version!
for (const plugin of plugins) {
if (plugin.name === 'react-native') {
continue
Expand Down
1 change: 1 addition & 0 deletions ern-container-gen-ios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"fs-extra": "^8.1.0",
"fs-readdir-recursive": "^1.1.0",
"lodash": "^4.17.14",
"semver": "^5.5.0",
"xcode-ern": "^1.0.12"
},
"devDependencies": {
Expand Down
129 changes: 129 additions & 0 deletions ern-container-gen-ios/src/IosGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
childProcess,
manifest,
iosUtil,
injectReactNativeVersionKeysInObject,
Expand All @@ -9,6 +10,9 @@ import {
NativePlatform,
kax,
PluginConfig,
readPackageJson,
writePackageJson,
yarn,
} from 'ern-core'
import {
ContainerGenerator,
Expand All @@ -25,6 +29,7 @@ import xcode from 'xcode-ern'
import _ from 'lodash'
import readDir from 'fs-readdir-recursive'
import { Composite } from 'ern-composite-gen'
import semver from 'semver'

const ROOT_DIR = process.cwd()
const PATH_TO_HULL_DIR = path.join(__dirname, 'hull')
Expand Down Expand Up @@ -134,6 +139,130 @@ export default class IosGenerator implements ContainerGenerator {
)

fs.writeFileSync(projectPath, iosProject.writeSync())

if (semver.gte(reactNativePlugin.version!, '0.61.0')) {
//
// Add all native dependencies to package.json dependencies so that
// !use_native_modules can detect them to add their pod to the Podfile
const dependencies = await config.composite.getNativeDependencies({})
const resDependencies = [
...dependencies.thirdPartyInManifest,
...dependencies.thirdPartyNotInManifest,
]
const addDependencies: any = {}
resDependencies.forEach(p => {
addDependencies[p.name!] = p.version
})

//
// Create package.json in container directory root
// so that native modules pods can be resolved
// by use_native_modules! RN ruby script
const pjsonObj = {
dependencies: addDependencies,
name: 'container',
}
await writePackageJson(config.outDir, pjsonObj)

//
// Copy all native dependencies from composite node_modules
// to container node_modules so that pods can be found local
// to the container directory
const containerNodeModulesPath = path.join(config.outDir, 'node_modules')
shell.mkdir('-p', containerNodeModulesPath)
resDependencies.forEach(p => {
shell.cp('-rf', p.basePath!, containerNodeModulesPath)
})
// Add @react-native-community/cli-platform-ios because
// it contains the scripts needed for native modules pods linking
// look in composite to match proper version
const compositeNodeModulesPath = path.join(
config.composite.path,
'node_modules'
)
const cliPlatformIosPkg = '@react-native-community/cli-platform-ios'
const cliPlatformIosPkgVersion = (
await readPackageJson(
path.join(compositeNodeModulesPath, cliPlatformIosPkg)
)
).version
shell.pushd(config.outDir)
try {
await yarn.add(
PackagePath.fromString(
`${cliPlatformIosPkg}@${cliPlatformIosPkgVersion}`
)
)
} finally {
shell.popd()
}

//
// Run pod install
shell.pushd(config.outDir)
try {
await kax
.task('Running pod install')
.run(childProcess.spawnp('pod', ['install']))
} finally {
shell.popd()
}

//
// Clean node_modules by only keeping the directories that are
// needed for proper container build.
shell.pushd(config.outDir)
try {
//
// Look in the Pods pbxproj for any references to some files
// kepts in some node_module subdirectory (basically react-native
// as well as all native modules)
const f = fs.readFileSync('Pods/Pods.xcodeproj/project.pbxproj', {
encoding: 'utf8',
})

//
// Build an array of these directories
const re = RegExp('"../node_modules/([^"]+)"', 'g')
const matches = []
let match = re.exec(f)
while (match !== null) {
matches.push(match[1])
match = re.exec(f)
}
const res = matches
.map(r => r.split('/'))
.filter(x => x[0] !== 'react-native')
.map(x => x.join('/'))
.concat('react-native')

//
// Copy all retained directories from 'node_modules'
// to a new directory 'node_modules_light'
const nodeModulesLightDir = 'node_modules_light'
const nodeModulesDir = 'node_modules'
shell.mkdir('-p', nodeModulesLightDir)
for (const b of res) {
shell.mkdir('-p', path.join(nodeModulesLightDir, b))
shell.cp(
'-Rf',
path.join(nodeModulesDir, b, '{.*,*}'),
path.join(nodeModulesLightDir, b)
)
}
//
// Replace the huge 'node_modules' directory with the skimmed one
shell.rm('-rf', nodeModulesDir)
shell.mv(nodeModulesLightDir, nodeModulesDir)
//
// Finally get rid of all android directories to further reduce
// overall 'node_modules' directory size, as they are not needed
// for iOS container builds.
shell.rm('-rf', path.join(nodeModulesDir, '**/android'))
} finally {
shell.popd()
}
}
}

// Code to keep backward compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
// https://github.com/dempseyatgithub/BuildSettingExtractor
//

{{#RN_VERSION_GTE_61}}
#include "Pods/Target Support Files/Pods-ElectrodeContainer/Pods-ElectrodeContainer.debug.xcconfig"
{{/RN_VERSION_GTE_61}}

{{#RN_VERSION_LT_61}}
HEADER_SEARCH_PATHS =
OTHER_LDFLAGS = -ObjC -lc++ -lz
{{/RN_VERSION_LT_61}}

ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES
CLANG_ENABLE_MODULES = YES
Expand All @@ -15,12 +24,10 @@ DYLIB_COMPATIBILITY_VERSION = 1
DYLIB_CURRENT_VERSION = 1
DYLIB_INSTALL_NAME_BASE = @rpath
FRAMEWORK_SEARCH_PATHS = $(inherited) $(SRCROOT)/ElectrodeContainer/Frameworks
HEADER_SEARCH_PATHS =
INFOPLIST_FILE = ElectrodeContainer/Info.plist
INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks
IPHONEOS_DEPLOYMENT_TARGET = 10.0
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
OTHER_LDFLAGS = -ObjC -lc++ -lz
PRODUCT_BUNDLE_IDENTIFIER = com.walmartlabs.ern.ElectrodeContainer
PRODUCT_NAME = $(TARGET_NAME)
SKIP_INSTALL = YES
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
// https://github.com/dempseyatgithub/BuildSettingExtractor
//

{{#RN_VERSION_GTE_61}}
#include "Pods/Target Support Files/Pods-ElectrodeContainer/Pods-ElectrodeContainer.qadeployment.xcconfig"
{{/RN_VERSION_GTE_61}}

{{#RN_VERSION_LT_61}}
HEADER_SEARCH_PATHS =
OTHER_LDFLAGS = -ObjC -lc++ -lz
{{/RN_VERSION_LT_61}}

ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES
CLANG_ENABLE_MODULES = YES
Expand All @@ -17,12 +26,10 @@ DYLIB_INSTALL_NAME_BASE = @rpath
ENABLE_ON_DEMAND_RESOURCES = NO
ENABLE_TESTABILITY = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) $(SRCROOT)/ElectrodeContainer/Frameworks
HEADER_SEARCH_PATHS =
INFOPLIST_FILE = ElectrodeContainer/Info.plist
INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
ONLY_ACTIVE_ARCH = NO
OTHER_LDFLAGS = -ObjC -lc++ -lz
PRODUCT_BUNDLE_IDENTIFIER = com.walmartlabs.ern.ElectrodeContainer
PRODUCT_NAME = $(TARGET_NAME)
SKIP_INSTALL = YES
Expand Down

0 comments on commit 632adc7

Please sign in to comment.