UNPKG

nodejs-mobile-react-native

Version:
203 lines (190 loc) 6.98 kB
const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const {spawnSync} = require('child_process'); function visitEveryFramework(projectPath) { var foundFrameworks = []; var countInvalidFrameworks = 0; var countValidFrameworks = 0; function recursivelyFindFrameworks(currentPath) { let currentFiles = fs.readdirSync(currentPath); for (let i = 0; i < currentFiles.length; i++) { let currentFilename = path.normalize( path.join(currentPath, currentFiles[i]), ); if (fs.lstatSync(currentFilename).isDirectory()) { if (currentFilename.endsWith('.node')) { let frameworkContents = fs.readdirSync(currentFilename); // Frameworks output by nodejs-mobile-gyp are expected to have only // one file inside, corresponding to the proper shared library. if (frameworkContents.length != 1) { console.log( 'Skipping a ".node". Expected to find only one file inside this path: ' + currentFilename, ); countInvalidFrameworks++; } else { let currentBinaryName = frameworkContents[0]; let checkFileType = spawnSync('file', [ path.join(currentFilename, currentBinaryName), ]); // File inside a .framework should be a dynamically linked shared // library. if ( checkFileType.stdout .toString() .indexOf('dynamically linked shared library') > -1 ) { let newFrameworkObject = { originalFileName: currentFilename, originalRelativePath: '', originalBinaryName: currentBinaryName, newFrameworkName: '', newFrameworkFileName: '', }; foundFrameworks.push(newFrameworkObject); countValidFrameworks++; } else { console.log( 'Skipping a ".node". Couldn\'t find a dynamically linked shared library inside ' + currentFilename + ' because ' + checkFileType.stdout.toString(), ); countInvalidFrameworks++; } } } recursivelyFindFrameworks(currentFilename); } } } recursivelyFindFrameworks(projectPath); console.log( 'Found ' + countValidFrameworks + ' valid frameworks and ' + countInvalidFrameworks + ' invalid frameworks after rebuilding the native modules for iOS.', ); if (foundFrameworks.length < 1) { console.log( 'No valid framework native modules were found. Skipping integrating them into the App.', ); return; } for (let i = 0; i < foundFrameworks.length; i++) { // Fill the helper fields for each framework. let currentFramework = foundFrameworks[i]; currentFramework.originalRelativePath = path.relative( projectPath, currentFramework.originalFileName, ); // To make each framework name unique while embedding, use a digest of the relative path. let hash = crypto.createHash('sha1'); hash.update(currentFramework.originalRelativePath); currentFramework.newFrameworkName = 'node' + hash.digest('hex'); currentFramework.newFrameworkFileName = path.join( path.dirname(currentFramework.originalFileName), currentFramework.newFrameworkName + '.framework', ); } for (let i = 0; i < foundFrameworks.length; i++) { // Rename the binaries to the new framework structure and add a .plist let currentFramework = foundFrameworks[i]; fs.renameSync( currentFramework.originalFileName, currentFramework.newFrameworkFileName, ); fs.renameSync( path.join( currentFramework.newFrameworkFileName, currentFramework.originalBinaryName, ), path.join( currentFramework.newFrameworkFileName, currentFramework.newFrameworkName, ), ); // Read template Info.plist let plistXmlContents = fs .readFileSync(path.join(__dirname, 'plisttemplate.xml')) .toString(); // Replace values with the new bundle name and XCode environment variables. plistXmlContents = plistXmlContents .replace( /\{ENV_MAC_OS_X_PRODUCT_BUILD_VERSION\}/g, process.env.MAC_OS_X_PRODUCT_BUILD_VERSION, ) .replace(/\{VAR_BINARY_NAME\}/g, currentFramework.newFrameworkName) .replace(/\{ENV_DEFAULT_COMPILER\}/g, process.env.DEFAULT_COMPILER) .replace( /\{ENV_PLATFORM_PRODUCT_BUILD_VERSION\}/g, process.env.PLATFORM_PRODUCT_BUILD_VERSION, ) .replace(/\{ENV_SDK_VERSION\}/g, process.env.SDK_VERSION) .replace( /\{ENV_SDK_PRODUCT_BUILD_VERSION\}/g, process.env.SDK_PRODUCT_BUILD_VERSION, ) .replace(/\{ENV_SDK_NAME\}/g, process.env.SDK_NAME) .replace( /\{ENV_XCODE_VERSION_ACTUAL\}/g, process.env.XCODE_VERSION_ACTUAL, ) .replace( /\{ENV_XCODE_PRODUCT_BUILD_VERSION\}/g, process.env.XCODE_PRODUCT_BUILD_VERSION, ); // Use plutil to generate the plist in the binary format. let plistGeneration = spawnSync( 'plutil', [ '-convert', 'binary1', // Will convert the xml plist to binary. '-o', path.join(currentFramework.newFrameworkFileName, 'Info.plist'), // target Info.plist path. '-', // read the input from the process stdin. ], { input: plistXmlContents, }, ); } var frameworkOverrideContents = []; for (let i = 0; i < foundFrameworks.length; i++) { // Generate the contents of a JSON file for overriding dlopen calls at runtime. let currentFramework = foundFrameworks[i]; frameworkOverrideContents.push({ originalpath: currentFramework.originalRelativePath.split(path.sep), newpath: [ '..', 'Frameworks', currentFramework.newFrameworkName + '.framework', currentFramework.newFrameworkName, ], }); } fs.writeFileSync( path.join(projectPath, 'override-dlopen-paths-data.json'), JSON.stringify(frameworkOverrideContents), ); // Copy runtime script that will override dlopen paths. fs.copyFileSync( path.join(__dirname, 'override-dlopen-paths-preload.js'), path.join(projectPath, 'override-dlopen-paths-preload.js'), ); for (let i = 0; i < foundFrameworks.length; i++) { // Put an empty file in each of the .node original locations, since some modules check their existence. fs.closeSync(fs.openSync(foundFrameworks[i].originalFileName, 'w')); } } if (process.argv.length >= 3) { if (fs.existsSync(process.argv[2])) { visitEveryFramework(path.normalize(process.argv[2])); } process.exit(0); } else { console.error('A path is expected as an argument.'); process.exit(1); }