From c1359a32c0b65f65f7a3a7cb86188baf1d972669 Mon Sep 17 00:00:00 2001 From: Dave Alden Date: Mon, 1 Jul 2019 10:12:16 +0100 Subject: [PATCH] [iOS] Ensure runpath search path contains $(inherited) to avoid build warnings/issues. Resolves #25. --- scripts/after_prepare.js | 4 + scripts/ios/helper.js | 208 ++++++++++++++++++++++----------------- 2 files changed, 124 insertions(+), 88 deletions(-) diff --git a/scripts/after_prepare.js b/scripts/after_prepare.js index 9e3111164..3371828bc 100644 --- a/scripts/after_prepare.js +++ b/scripts/after_prepare.js @@ -50,6 +50,10 @@ module.exports = function (context) { if (platforms.indexOf('ios') !== -1 && utilities.directoryExists(IOS_DIR)) { console.log('Preparing Firebase on iOS'); utilities.copyKey(PLATFORM.IOS); + + var helper = require("./ios/helper"); + var xcodeProjectPath = helper.getXcodeProjectPath(context); + helper.ensureRunpathSearchPath(context, xcodeProjectPath); } if (platforms.indexOf('android') !== -1 && utilities.directoryExists(ANDROID_DIR)) { console.log('Preparing Firebase on Android'); diff --git a/scripts/ios/helper.js b/scripts/ios/helper.js index 771b35707..3b9dd2a56 100644 --- a/scripts/ios/helper.js +++ b/scripts/ios/helper.js @@ -11,132 +11,164 @@ var comment = "\"Crashlytics\""; module.exports = { - /** + /** * Used to get the path to the XCode project's .pbxproj file. * * @param {object} context - The Cordova context. * @returns The path to the XCode project's .pbxproj file. */ - getXcodeProjectPath: function (context) { + getXcodeProjectPath: function (context) { - var appName = utilities.getAppName(context); + var appName = utilities.getAppName(context); - return path.join("platforms", "ios", appName + ".xcodeproj", "project.pbxproj"); - }, + return path.join("platforms", "ios", appName + ".xcodeproj", "project.pbxproj"); + }, - /** + /** * This helper is used to add a build phase to the XCode project which runs a shell * script during the build process. The script executes Crashlytics run command line * tool with the API and Secret keys. This tool is used to upload the debug symbols * (dSYMs) so that Crashlytics can display stack trace information in it's web console. */ - addShellScriptBuildPhase: function (context, xcodeProjectPath) { - - // Read and parse the XCode project (.pxbproj) from disk. - // File format information: http://www.monobjc.net/xcode-project-file-format.html - var xcodeProject = xcode.project(xcodeProjectPath); - xcodeProject.parseSync(); - - // Build the body of the script to be executed during the build phase. - var script = '"' + '\\"${PODS_ROOT}/Fabric/run\\"' + '"'; - - // Generate a unique ID for our new build phase. - var id = xcodeProject.generateUuid(); - // Create the build phase. - xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = { - isa: "PBXShellScriptBuildPhase", - buildActionMask: 2147483647, - files: [], - inputPaths: ['"' + '$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)' + '"'], - name: comment, - outputPaths: [], - runOnlyForDeploymentPostprocessing: 0, - shellPath: "/bin/sh", - shellScript: script, - showEnvVarsInLog: 0 + addShellScriptBuildPhase: function (context, xcodeProjectPath) { + + // Read and parse the XCode project (.pxbproj) from disk. + // File format information: http://www.monobjc.net/xcode-project-file-format.html + var xcodeProject = xcode.project(xcodeProjectPath); + xcodeProject.parseSync(); + + // Build the body of the script to be executed during the build phase. + var script = '"' + '\\"${PODS_ROOT}/Fabric/run\\"' + '"'; + + // Generate a unique ID for our new build phase. + var id = xcodeProject.generateUuid(); + // Create the build phase. + xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = { + isa: "PBXShellScriptBuildPhase", + buildActionMask: 2147483647, + files: [], + inputPaths: ['"' + '$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)' + '"'], + name: comment, + outputPaths: [], + runOnlyForDeploymentPostprocessing: 0, + shellPath: "/bin/sh", + shellScript: script, + showEnvVarsInLog: 0 }; - // Add a comment to the block (viewable in the source of the pbxproj file). - xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment; + // Add a comment to the block (viewable in the source of the pbxproj file). + xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment; - // Add this new shell script build phase block to the targets. - for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) { + // Add this new shell script build phase block to the targets. + for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) { - // Skip over the comment blocks. - if (nativeTargetId.indexOf("_comment") !== -1) { - continue; - } + // Skip over the comment blocks. + if (nativeTargetId.indexOf("_comment") !== -1) { + continue; + } - var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId]; + var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId]; - nativeTarget.buildPhases.push({ - value: id, - comment: comment - }); - } + nativeTarget.buildPhases.push({ + value: id, + comment: comment + }); + } - // Finally, write the .pbxproj back out to disk. - fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync()); - }, + // Finally, write the .pbxproj back out to disk. + fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync()); + }, - /** + /** * This helper is used to remove the build phase from the XCode project that was added * by the addShellScriptBuildPhase() helper method. */ - removeShellScriptBuildPhase: function (context, xcodeProjectPath) { + removeShellScriptBuildPhase: function (context, xcodeProjectPath) { - // Read and parse the XCode project (.pxbproj) from disk. - // File format information: http://www.monobjc.net/xcode-project-file-format.html - var xcodeProject = xcode.project(xcodeProjectPath); - xcodeProject.parseSync(); + // Read and parse the XCode project (.pxbproj) from disk. + // File format information: http://www.monobjc.net/xcode-project-file-format.html + var xcodeProject = xcode.project(xcodeProjectPath); + xcodeProject.parseSync(); - // First, we want to delete the build phase block itself. + // First, we want to delete the build phase block itself. - var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase; + var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase; - var commentTest = comment.replace(/"/g, ''); - for (var buildPhaseId in buildPhases) { + var commentTest = comment.replace(/"/g, ''); + for (var buildPhaseId in buildPhases) { - var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId]; - var shouldDelete = false; + var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId]; + var shouldDelete = false; - if (buildPhaseId.indexOf("_comment") === -1) { - // Dealing with a build phase block. + if (buildPhaseId.indexOf("_comment") === -1) { + // Dealing with a build phase block. - // If the name of this block matches ours, then we want to delete it. - shouldDelete = buildPhase.name && buildPhase.name.indexOf(commentTest) !== -1; - } else { - // Dealing with a comment block. + // If the name of this block matches ours, then we want to delete it. + shouldDelete = buildPhase.name && buildPhase.name.indexOf(commentTest) !== -1; + } else { + // Dealing with a comment block. - // If this is a comment block that matches ours, then we want to delete it. - shouldDelete = buildPhase === commentTest; - } + // If this is a comment block that matches ours, then we want to delete it. + shouldDelete = buildPhase === commentTest; + } - if (shouldDelete) { - delete buildPhases[buildPhaseId]; - } - } + if (shouldDelete) { + delete buildPhases[buildPhaseId]; + } + } - // Second, we want to delete the native target reference to the block. + // Second, we want to delete the native target reference to the block. - var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget; + var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget; - for (var nativeTargetId in nativeTargets) { + for (var nativeTargetId in nativeTargets) { - // Skip over the comment blocks. - if (nativeTargetId.indexOf("_comment") !== -1) { - continue; - } + // Skip over the comment blocks. + if (nativeTargetId.indexOf("_comment") !== -1) { + continue; + } - var nativeTarget = nativeTargets[nativeTargetId]; + var nativeTarget = nativeTargets[nativeTargetId]; - // We remove the reference to the block by filtering out the the ones that match. - nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) { - return buildPhase.comment !== commentTest; - }); - } + // We remove the reference to the block by filtering out the the ones that match. + nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) { + return buildPhase.comment !== commentTest; + }); + } + + // Finally, write the .pbxproj back out to disk. + fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync()); + }, + + ensureRunpathSearchPath: function(context, xcodeProjectPath){ - // Finally, write the .pbxproj back out to disk. - fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync()); - } + function addRunpathSearchBuildProperty(proj, build) { + const LD_RUNPATH_SEARCH_PATHS = proj.getBuildProperty("LD_RUNPATH_SEARCH_PATHS", build); + if (!LD_RUNPATH_SEARCH_PATHS) { + proj.addBuildProperty("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks\"", build); + } + if (LD_RUNPATH_SEARCH_PATHS.indexOf("@executable_path/Frameworks") == -1) { + var newValue = LD_RUNPATH_SEARCH_PATHS.substr(0, LD_RUNPATH_SEARCH_PATHS.length - 1); + newValue += ' @executable_path/Frameworks\"'; + proj.updateBuildProperty("LD_RUNPATH_SEARCH_PATHS", newValue, build); + } + if (LD_RUNPATH_SEARCH_PATHS.indexOf("$(inherited)") == -1) { + var newValue = LD_RUNPATH_SEARCH_PATHS.substr(0, LD_RUNPATH_SEARCH_PATHS.length - 1); + newValue += ' $(inherited)\"'; + proj.updateBuildProperty("LD_RUNPATH_SEARCH_PATHS", newValue, build); + } + } + + // Read and parse the XCode project (.pxbproj) from disk. + // File format information: http://www.monobjc.net/xcode-project-file-format.html + var xcodeProject = xcode.project(xcodeProjectPath); + xcodeProject.parseSync(); + + // Add search paths build property + addRunpathSearchBuildProperty(xcodeProject, "Debug"); + addRunpathSearchBuildProperty(xcodeProject, "Release"); + + // Finally, write the .pbxproj back out to disk. + fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync()); + } };