nativescript
Version:
Command-line interface for building NativeScript projects
269 lines (268 loc) • 14 kB
JavaScript
"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);