nodejs-mobile-react-native-redmagic
Version:
Node.js for Mobile Apps React Native plugin
343 lines (306 loc) • 15.3 kB
JavaScript
var path = require('path');
var fs = require('fs');
var ncp = require('ncp');
var xcode = require('xcode');
const android = require('./../../../node_modules/@react-native-community/cli/build/core/android');
const ios = require('./../../../node_modules/@react-native-community/cli/build/core/ios');
function hostPackageDir(file) {
var pathComponents = file.split(path.sep);
var modulesDirIndex = pathComponents.lastIndexOf('node_modules');
if (modulesDirIndex < 1) return undefined;
return pathComponents.slice(0, modulesDirIndex).join(path.sep);
}
const getRNPMConfig = (folder) =>
// $FlowFixMe non-literal require
require(path.join(folder, './package.json')).rnpm || {};
var scriptPath = __filename;
const folder = hostPackageDir(scriptPath);
const rnpm = getRNPMConfig(folder);
function getProjectConfig() {
var scriptPath = __filename;
console.error("ScriptPath: "+scriptPath);
const folder = hostPackageDir(scriptPath);
console.error("folder: "+folder);
var returnObj={};
returnObj.ios = ios.projectConfig(folder, rnpm.ios || {});
returnObj.android = android.projectConfig(folder, rnpm.android || {});
return returnObj;
}
// Adds a custom function to remove script build phases, which is not supported in the xcode module.
xcode.project.prototype.myRemovePbxScriptBuildPhase = function (buildPhaseName, target) {
var buildPhaseTargetUuid = target || this.getFirstTarget().uuid;
var buildPhaseUuid_comment = this.buildPhase(buildPhaseName, buildPhaseTargetUuid);
if (!buildPhaseUuid_comment)
{
throw new Error("Couldn't find the build script phase to remove: " + buildPhaseName );
}
// Remove the '_comment' suffix to get the actual uuid.
var buildPhaseUuid=buildPhaseUuid_comment.split('_')[0];
// Remove from the pbxBuildPhaseObjects
var pbxBuildPhaseObjects = this.getPBXObject('PBXShellScriptBuildPhase');
if (pbxBuildPhaseObjects) {
delete pbxBuildPhaseObjects[buildPhaseUuid];
delete pbxBuildPhaseObjects[buildPhaseUuid_comment];
}
// Remove from the target's buildPhases
var nativeTargets = this.pbxNativeTargetSection();
var nativeTarget = nativeTargets[buildPhaseTargetUuid];
var buildPhases = nativeTarget.buildPhases;
for(var i in buildPhases)
{
var buildPhase = buildPhases[i];
if (buildPhase.value == buildPhaseUuid) {
buildPhases.splice(i, 1);
break;
}
}
};
var detectedConfigs=getProjectConfig();
if ( detectedConfigs && detectedConfigs.ios && detectedConfigs.ios.pbxprojPath)
{
var pbxProjectPath = detectedConfigs.ios.pbxprojPath;
var xcodeProject = xcode.project(pbxProjectPath);
var mainProjectName = detectedConfigs.ios.projectName;
xcodeProject.parse(function (error) {
if (error) {
console.error("Couldn't parse .pbx project : " + JSON.stringify(error));
return 1;
}
//Create a Frameworks group and add it to the project's main Group
var mainGroupUUID = xcodeProject.pbxProjectSection()[xcodeProject.getFirstProject().uuid].mainGroup;
var frameworksGroup = xcodeProject.pbxGroupByName('Frameworks');
if (!frameworksGroup)
{
var frameworksUUID = xcodeProject.pbxCreateGroup("Frameworks");
xcodeProject.addToPbxGroup(frameworksUUID,mainGroupUUID);
}
//Add an EmbedFrameworks build phase to the app's target
var firstTargetUUID = xcodeProject.getFirstTarget().uuid;
if(!xcodeProject.pbxEmbedFrameworksBuildPhaseObj(firstTargetUUID))
{
var buildPhaseResult = xcodeProject.addBuildPhase(
[],
'PBXCopyFilesBuildPhase',
'Embed Frameworks',
firstTargetUUID,
'framework');
buildPhaseResult.buildPhase.dstSubfolderSpec=10;
}
//Override addToFrameworkSearchPaths to add the framework path to all targets.
//The one provided in the xcode module adds the wrong path and not to the right target.
let myaddToFrameworkSearchPaths = function(fileName)
{
var configurations = xcodeProject.pbxXCBuildConfigurationSection(),
INHERITED = '"$(inherited)"',
config, buildSettings, searchPaths;
var fileDir = path.dirname(fileName);
var filePos = '"\\"' + fileDir + '\\""';
for (config in configurations) {
buildSettings = configurations[config].buildSettings;
if(!buildSettings || !buildSettings['PRODUCT_NAME'])
continue;
if (!buildSettings['FRAMEWORK_SEARCH_PATHS']
|| buildSettings['FRAMEWORK_SEARCH_PATHS'] === INHERITED) {
buildSettings['FRAMEWORK_SEARCH_PATHS'] = [INHERITED];
}
buildSettings['FRAMEWORK_SEARCH_PATHS'].push(filePos);
}
};
//Removes the old libnode.framework from the firstTarget, if it exists.
var oldFrameworkPath="../node_modules/nodejs-mobile-react-native-redmagic/ios/libnode.framework";
if (xcodeProject.hasFile(oldFrameworkPath)) {
var deletedFrameworkFileRef=xcodeProject.removeFramework(
oldFrameworkPath,
{customFramework:true, embed:true, link: true, sign: true, target: firstTargetUUID}
);
}
//Adds the NodeMobile framework to the firstTarget (it's the main app target)
var frameworkPath="../node_modules/nodejs-mobile-react-native-redmagic/ios/NodeMobile.framework";
var frameworkFileRef=xcodeProject.addFramework(
frameworkPath,
{customFramework:true, embed:true, link: true, sign: true, target: firstTargetUUID}
);
if(frameworkFileRef)
{
myaddToFrameworkSearchPaths(frameworkPath);
}
//Create the resources group.
var resourcesGroup = xcodeProject.pbxGroupByName('Resources');
if (!resourcesGroup)
{
xcodeProject.pbxCreateGroup("Resources");
}
//Adds the default node project as a resource to the first project, in the main group.
xcodeProject.addResourceFile(
"../nodejs-assets/nodejs-project",
{target: firstTargetUUID},
mainGroupUUID
);
//Adds the built-in module inside the plugin as a resource to the first project, in the main group.
xcodeProject.addResourceFile(
"../node_modules/nodejs-mobile-react-native-redmagic/install/resources/nodejs-modules/builtin_modules",
{target: firstTargetUUID},
mainGroupUUID
);
//Disable bitcode, as it's not present in the libnode binary.
xcodeProject.addBuildProperty(
'ENABLE_BITCODE','NO','Debug'
);
xcodeProject.addBuildProperty(
'ENABLE_BITCODE','NO','Release'
);
//Adds a build phase to rebuild native modules
var rebuildNativeModulesBuildPhaseName = 'Build NodeJS Mobile Native Modules';
var rebuildNativeModulesBuildPhaseScript = `
set -e
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
# If build native modules preference is not set, look for it in the project's
#nodejs-assets/BUILD_NATIVE_MODULES.txt file.
NODEJS_ASSETS_DIR="$( cd "$PROJECT_DIR" && cd ../nodejs-assets/ && pwd )"
PREFERENCE_FILE_PATH="$NODEJS_ASSETS_DIR/BUILD_NATIVE_MODULES.txt"
if [ -f "$PREFERENCE_FILE_PATH" ]; then
NODEJS_MOBILE_BUILD_NATIVE_MODULES="$(cat $PREFERENCE_FILE_PATH | xargs)"
fi
fi
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
# If build native modules preference is not set, try to find .gyp files
#to turn it on.
gypfiles=($(find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -type f -name "*.gyp"))
if [ \${#gypfiles[@]} -gt 0 ]; then
NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
else
NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
fi
fi
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
# Delete object files that may already come from within the npm package.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.o" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.a" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type f -delete
# Delete bundle contents that may be there from previous builds.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.node/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.node" -type d -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.framework/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d -delete
# Apply patches to the modules package.json
if [ -d "$CODESIGNING_FOLDER_PATH"/nodejs-project/node_modules/ ]; then
PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-redmagic/scripts/ && pwd )"
NODEJS_PROJECT_MODULES_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd nodejs-project/node_modules/ && pwd )"
node "$PATCH_SCRIPT_DIR"/patch-package.js $NODEJS_PROJECT_MODULES_DIR
fi
# Get the nodejs-mobile-gyp location
if [ -d "$PROJECT_DIR/../node_modules/nodejs-mobile-gyp/" ]; then
NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-gyp/ && pwd )"
else
NODEJS_MOBILE_GYP_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native-redmagic/node_modules/nodejs-mobile-gyp/ && pwd )"
fi
NODEJS_MOBILE_GYP_BIN_FILE="$NODEJS_MOBILE_GYP_DIR"/bin/node-gyp.js
# Rebuild modules with right environment
NODEJS_HEADERS_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-redmagic/ios/libnode/ && pwd )"
pushd $CODESIGNING_FOLDER_PATH/nodejs-project/
if [ "$PLATFORM_NAME" == "iphoneos" ]
then
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="arm64" npm --verbose rebuild --build-from-source
else
GYP_DEFINES="OS=ios" npm_config_nodedir="$NODEJS_HEADERS_DIR" npm_config_node_gyp="$NODEJS_MOBILE_GYP_BIN_FILE" npm_config_platform="ios" npm_config_format="make-ios" npm_config_node_engine="chakracore" npm_config_arch="x64" npm --verbose rebuild --build-from-source
fi
popd
`
var rebuildNativeModulesBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', rebuildNativeModulesBuildPhaseName, firstTargetUUID);
if (rebuildNativeModulesBuildPhase) {
xcodeProject.myRemovePbxScriptBuildPhase(rebuildNativeModulesBuildPhaseName, firstTargetUUID);
}
xcodeProject.addBuildPhase(
[],
'PBXShellScriptBuildPhase',
rebuildNativeModulesBuildPhaseName,
firstTargetUUID,
{ shellPath: '/bin/sh', shellScript: rebuildNativeModulesBuildPhaseScript }
);
//Adds a build phase to sign native modules
var signNativeModulesBuildPhaseName = 'Sign NodeJS Mobile Native Modules';
var signNativeModulesBuildPhaseScript = `
set -e
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
# If build native modules preference is not set, look for it in the project's
#nodejs-assets/BUILD_NATIVE_MODULES.txt file.
NODEJS_ASSETS_DIR="$( cd "$PROJECT_DIR" && cd ../nodejs-assets/ && pwd )"
PREFERENCE_FILE_PATH="$NODEJS_ASSETS_DIR/BUILD_NATIVE_MODULES.txt"
if [ -f "$PREFERENCE_FILE_PATH" ]; then
NODEJS_MOBILE_BUILD_NATIVE_MODULES="$(cat $PREFERENCE_FILE_PATH | xargs)"
fi
fi
if [ -z "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then
# If build native modules preference is not set, try to find .gyp files
#to turn it on.
gypfiles=($(find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -type f -name "*.gyp"))
if [ \${#gypfiles[@]} -gt 0 ]; then
NODEJS_MOBILE_BUILD_NATIVE_MODULES=1
else
NODEJS_MOBILE_BUILD_NATIVE_MODULES=0
fi
fi
if [ "1" != "$NODEJS_MOBILE_BUILD_NATIVE_MODULES" ]; then exit 0; fi
# Delete object files
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.o" -type f -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.a" -type f -delete
# Create Info.plist for each framework built and loader override.
PATCH_SCRIPT_DIR="$( cd "$PROJECT_DIR" && cd ../node_modules/nodejs-mobile-react-native-redmagic/scripts/ && pwd )"
NODEJS_PROJECT_DIR="$( cd "$CODESIGNING_FOLDER_PATH" && cd nodejs-project/ && pwd )"
node "$PATCH_SCRIPT_DIR"/ios-create-plists-and-dlopen-override.js $NODEJS_PROJECT_DIR
# Embed every resulting .framework in the application and delete them afterwards.
embed_framework()
{
FRAMEWORK_NAME="$(basename "$1")"
cp -r "$1" "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/"
/usr/bin/codesign --force --sign $EXPANDED_CODE_SIGN_IDENTITY --preserve-metadata=identifier,entitlements,flags --timestamp=none "$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/$FRAMEWORK_NAME"
}
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d | while read frmwrk_path; do embed_framework "$frmwrk_path"; done
#Delete gyp temporary .deps dependency folders from the project structure.
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/.deps/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name ".deps" -type d -delete
#Delete frameworks from their build paths
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -path "*/*.framework/*" -delete
find "$CODESIGNING_FOLDER_PATH/nodejs-project/" -name "*.framework" -type d -delete
`
var signNativeModulesBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', signNativeModulesBuildPhaseName, firstTargetUUID);
if (signNativeModulesBuildPhase) {
xcodeProject.myRemovePbxScriptBuildPhase(signNativeModulesBuildPhaseName, firstTargetUUID);
}
xcodeProject.addBuildPhase(
[],
'PBXShellScriptBuildPhase',
signNativeModulesBuildPhaseName,
firstTargetUUID,
{ shellPath: '/bin/sh', shellScript: signNativeModulesBuildPhaseScript }
);
//Adds a build phase to remove the x64 strips from the NodeMobile framework. Needed for correct App Store submission.
var removeSimulatorArchsBuildPhaseName = 'Remove NodeJS Mobile Framework Simulator Strips';
var removeSimulatorArchsBuildPhaseScript = `
set -e
FRAMEWORK_BINARY_PATH="$TARGET_BUILD_DIR/$FRAMEWORKS_FOLDER_PATH/NodeMobile.framework/NodeMobile"
FRAMEWORK_STRIPPED_PATH="$FRAMEWORK_BINARY_PATH-strip"
if [ "$PLATFORM_NAME" != "iphonesimulator" ]; then
if $(lipo "$FRAMEWORK_BINARY_PATH" -verify_arch "x86_64") ; then
lipo -output "$FRAMEWORK_STRIPPED_PATH" -remove "x86_64" "$FRAMEWORK_BINARY_PATH"
rm "$FRAMEWORK_BINARY_PATH"
mv "$FRAMEWORK_STRIPPED_PATH" "$FRAMEWORK_BINARY_PATH"
echo "Removed simulator strip from NodeMobile.framework"
fi
fi
`
var removeSimulatorArchsBuildPhase = xcodeProject.buildPhaseObject('PBXShellScriptBuildPhase', removeSimulatorArchsBuildPhaseName, firstTargetUUID);
if (removeSimulatorArchsBuildPhase) {
xcodeProject.myRemovePbxScriptBuildPhase(removeSimulatorArchsBuildPhaseName, firstTargetUUID);
}
xcodeProject.addBuildPhase(
[],
'PBXShellScriptBuildPhase',
removeSimulatorArchsBuildPhaseName,
firstTargetUUID,
{ shellPath: '/bin/sh', shellScript: removeSimulatorArchsBuildPhaseScript }
);
//Writes the updated .pbx file
fs.writeFileSync(pbxProjectPath,xcodeProject.writeSync(),'utf-8');
});
}