UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

269 lines (268 loc) • 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IOSSigningService = void 0; const path = require("path"); const constants_1 = require("../../constants"); const helpers = require("../../common/helpers"); const _ = require("lodash"); const yok_1 = require("../../common/yok"); const constants = require("../../constants"); class IOSSigningService { constructor($errors, $fs, $iOSProvisionService, $logger, $pbxprojDomXcode, $prompter, $xcconfigService, $xcprojService) { this.$errors = $errors; this.$fs = $fs; this.$iOSProvisionService = $iOSProvisionService; this.$logger = $logger; this.$pbxprojDomXcode = $pbxprojDomXcode; this.$prompter = $prompter; this.$xcconfigService = $xcconfigService; this.$xcprojService = $xcprojService; } async setupSigningForDevice(projectRoot, projectData, iOSBuildData) { const xcode = this.$pbxprojDomXcode.Xcode.open(this.getPbxProjPath(projectData, projectRoot)); const signing = xcode.getSigning(projectData.projectName); const hasProvisioningProfileInXCConfig = this.readXCConfigProvisioningProfileSpecifierForIPhoneOs(projectData) || this.readXCConfigProvisioningProfileSpecifier(projectData) || this.readXCConfigProvisioningProfileForIPhoneOs(projectData) || this.readXCConfigProvisioningProfile(projectData); if (hasProvisioningProfileInXCConfig && (!signing || signing.style !== "Manual")) { xcode.setManualSigningStyle(projectData.projectName); this.getExtensionNames(projectData).forEach((name) => { xcode.setManualSigningStyle(name); }); xcode.save(); } else if (!iOSBuildData.provision && !(signing && signing.style === "Manual" && !iOSBuildData.teamId)) { const teamId = await this.getDevelopmentTeam(projectData, projectRoot, iOSBuildData.teamId); await this.setupSigningFromTeam(projectRoot, projectData, teamId); } } async setupSigningFromTeam(projectRoot, projectData, teamId) { const xcode = this.$pbxprojDomXcode.Xcode.open(this.getPbxProjPath(projectData, projectRoot)); const signing = xcode.getSigning(projectData.projectName); let shouldUpdateXcode = false; if (signing && signing.style === "Automatic") { if (signing.team !== teamId) { const teamIdsForName = await this.$iOSProvisionService.getTeamIdsWithName(teamId); if (!teamIdsForName.some((id) => id === signing.team)) { shouldUpdateXcode = true; } } } else { shouldUpdateXcode = true; } if (shouldUpdateXcode) { const teamIdsForName = await this.$iOSProvisionService.getTeamIdsWithName(teamId); if (teamIdsForName.length > 0) { this.$logger.trace(`Team id ${teamIdsForName[0]} will be used for team name "${teamId}".`); teamId = teamIdsForName[0]; } xcode.setAutomaticSigningStyle(projectData.projectName, teamId); xcode.setAutomaticSigningStyleByTargetProductTypesList([ constants_1.IOSNativeTargetProductTypes.appExtension, constants_1.IOSNativeTargetProductTypes.watchApp, constants_1.IOSNativeTargetProductTypes.watchExtension, ], teamId); this.getExtensionNames(projectData).forEach((name) => { xcode.setAutomaticSigningStyle(name, teamId); }); xcode.save(); this.$logger.trace(`Set Automatic signing style and team id ${teamId}.`); } else { this.$logger.trace(`The specified ${teamId} is already set in the Xcode.`); } } async setupSigningFromProvision(projectRoot, projectData, provision, mobileProvisionData) { if (!provision) { return; } const xcode = this.$pbxprojDomXcode.Xcode.open(this.getPbxProjPath(projectData, projectRoot)); const signing = xcode.getSigning(projectData.projectName); let shouldUpdateXcode = false; if (signing && signing.style === "Manual") { for (const config in signing.configurations) { const options = signing.configurations[config]; if (options.name !== provision && options.uuid !== provision) { shouldUpdateXcode = true; break; } } } else { shouldUpdateXcode = true; } if (shouldUpdateXcode) { const projectSigningConfig = await this.getManualSigningConfiguration(projectData, provision, mobileProvisionData); xcode.setManualSigningStyle(projectData.projectName, projectSigningConfig); xcode.setManualSigningStyleByTargetProductTypesList([ constants_1.IOSNativeTargetProductTypes.appExtension, constants_1.IOSNativeTargetProductTypes.watchApp, constants_1.IOSNativeTargetProductTypes.watchExtension, ], projectSigningConfig); this.$logger.trace(`Set Manual signing style and provisioning profile: ${projectSigningConfig.name} (${projectSigningConfig.uuid})`); const extensionSigningConfig = await Promise.all(this.getExtensionsManualSigningConfiguration(projectData)); extensionSigningConfig.forEach(({ name, configuration }) => { xcode.setManualSigningStyle(name, configuration); this.$logger.trace(`Set Manual signing style and provisioning profile: ${configuration.name} (${configuration.uuid})`); }); xcode.save(); } else { this.$logger.trace(`The specified provisioning profile is already set in the Xcode: ${provision}`); } } getExtensionNames(projectData) { const extensionFolderPath = path.join(projectData.getAppResourcesDirectoryPath(), constants.iOSAppResourcesFolderName, constants.NATIVE_EXTENSION_FOLDER); if (this.$fs.exists(extensionFolderPath)) { const extensionNames = this.$fs .readDirectory(extensionFolderPath) .filter((fileName) => { const extensionPath = path.join(extensionFolderPath, fileName); const stats = this.$fs.getFsStats(extensionPath); return stats.isDirectory() && !fileName.startsWith("."); }); return extensionNames; } return []; } getExtensionsManualSigningConfiguration(projectData) { const provisioningJSONPath = path.join(projectData.getAppResourcesDirectoryPath(), constants.iOSAppResourcesFolderName, constants.NATIVE_EXTENSION_FOLDER, constants.EXTENSION_PROVISIONING_FILENAME); if (this.$fs.exists(provisioningJSONPath)) { const provisioningJSON = this.$fs.readJson(provisioningJSONPath); const extensionNames = this.getExtensionNames(projectData); const provisioning = Object.entries(provisioningJSON).map(async ([id, provision]) => { const name = id.split(".").at(-1); if (extensionNames.includes(name)) { const configuration = await this.getManualSigningConfiguration(projectData, provision); return { name, configuration }; } return null; }); return provisioning; } return []; } async getManualSigningConfiguration(projectData, provision, mobileProvisionData) { const pickStart = Date.now(); const mobileprovision = mobileProvisionData || (await this.$iOSProvisionService.pick(provision, projectData.projectIdentifiers.ios)); const pickEnd = Date.now(); this.$logger.trace("Searched and " + (mobileprovision ? "found" : "failed to find ") + " matching provisioning profile. (" + (pickEnd - pickStart) + "ms.)"); if (!mobileprovision) { this.$errors.fail("Failed to find mobile provision with UUID or Name: " + provision); } const configuration = { team: mobileprovision.TeamIdentifier && mobileprovision.TeamIdentifier.length > 0 ? mobileprovision.TeamIdentifier[0] : undefined, uuid: mobileprovision.UUID, name: mobileprovision.Name, identity: mobileprovision.Type === "Development" ? "iPhone Developer" : "iPhone Distribution", }; return configuration; } getBuildXCConfigFilePath(projectData) { return path.join(projectData.appResourcesDirectoryPath, constants_1.iOSAppResourcesFolderName, constants_1.BUILD_XCCONFIG_FILE_NAME); } getPbxProjPath(projectData, projectRoot) { return path.join(this.$xcprojService.getXcodeprojPath(projectData, projectRoot), "project.pbxproj"); } readTeamIdFromFile(projectRoot) { try { const filePath = path.join(projectRoot, "teamid"); if (this.$fs.exists(filePath)) { return this.$fs.readText(filePath); } } catch (e) { this.$logger.trace("Unable to read file: teamid. Error is: ", e); } return undefined; } async getDevelopmentTeam(projectData, projectRoot, teamId) { teamId = teamId || this.readXCConfigDevelopmentTeam(projectData); if (!teamId) { const teams = await this.$iOSProvisionService.getDevelopmentTeams(); this.$logger.warn("Xcode requires a team id to be specified when building for device."); this.$logger.warn("You can specify the team id by setting the DEVELOPMENT_TEAM setting in build.xcconfig file located in App_Resources folder of your app, or by using the --teamId option when calling run, debug or livesync commands."); if (teams.length === 1) { teamId = teams[0].id; this.$logger.warn("Found and using the following development team installed on your system: " + teams[0].name + " (" + teams[0].id + ")"); } else if (teams.length > 0) { if (!helpers.isInteractive()) { this.$errors.fail(`Unable to determine default development team. Available development teams are: ${_.map(teams, (team) => team.id)}. Specify team in app/App_Resources/iOS/build.xcconfig file in the following way: DEVELOPMENT_TEAM = <team id>`); } const fromFile = this.readTeamIdFromFile(projectRoot); if (fromFile) { const idFromFile = teams.find((value) => value.id === fromFile); if (idFromFile) { teamId = idFromFile.id; this.$logger.info(`Team Id resolved from file: '${teamId}'.`); } } if (!teamId) { const choices = []; for (const team of teams) { choices.push(team.name + " (" + team.id + ")"); } const choice = await this.$prompter.promptForChoice("Found multiple development teams, select one:", choices); teamId = teams[choices.indexOf(choice)].id; const choicesPersist = [ "Yes, set the DEVELOPMENT_TEAM setting in build.xcconfig file.", "Yes, persist the team id in platforms folder.", "No, don't persist this setting.", ]; const choicePersist = await this.$prompter.promptForChoice("Do you want to make teamId: " + teamId + " a persistent choice for your app?", choicesPersist); switch (choicesPersist.indexOf(choicePersist)) { case 0: const xcconfigFile = path.join(projectData.appResourcesDirectoryPath, "iOS", constants_1.BUILD_XCCONFIG_FILE_NAME); this.$fs.appendFile(xcconfigFile, "\nDEVELOPMENT_TEAM = " + teamId + "\n"); break; case 1: this.$fs.writeFile(path.join(projectRoot, "teamid"), teamId); break; default: break; } } } } this.$logger.trace(`Selected teamId is '${teamId}'.`); return teamId; } readXCConfigDevelopmentTeam(projectData) { return this.$xcconfigService.readPropertyValue(this.getBuildXCConfigFilePath(projectData), "DEVELOPMENT_TEAM"); } readXCConfigProvisioningProfile(projectData) { return this.$xcconfigService.readPropertyValue(this.getBuildXCConfigFilePath(projectData), "PROVISIONING_PROFILE"); } readXCConfigProvisioningProfileForIPhoneOs(projectData) { return this.$xcconfigService.readPropertyValue(this.getBuildXCConfigFilePath(projectData), "PROVISIONING_PROFILE[sdk=iphoneos*]"); } readXCConfigProvisioningProfileSpecifier(projectData) { return this.$xcconfigService.readPropertyValue(this.getBuildXCConfigFilePath(projectData), "PROVISIONING_PROFILE_SPECIFIER"); } readXCConfigProvisioningProfileSpecifierForIPhoneOs(projectData) { return this.$xcconfigService.readPropertyValue(this.getBuildXCConfigFilePath(projectData), "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]"); } } exports.IOSSigningService = IOSSigningService; yok_1.injector.register("iOSSigningService", IOSSigningService);