Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native 0.61+ support #1542

Merged
merged 1 commit into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading