Skip to content

Commit 84f20ab

Browse files
committed
Fix some issues about the provision switch
1 parent d992963 commit 84f20ab

18 files changed

+240
-40
lines changed

lib/bootstrap.ts

+3
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,7 @@ $injector.require("projectChangesService", "./services/project-changes-service")
124124

125125
$injector.require("emulatorPlatformService", "./services/emulator-platform-service");
126126

127+
$injector.require("pbxprojDomXcode", "./services/pbxproj-dom-xcode");
128+
127129
$injector.require("staticConfig", "./config");
130+

lib/declarations.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ interface IClean {
9898
}
9999

100100
interface IProvision {
101-
provision: any;
101+
provision: string;
102102
}
103103

104104
interface ITeamIdentifier {

lib/definitions/project-changes.d.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ interface IProjectChangesInfo {
1515
configChanged: boolean;
1616
packageChanged: boolean;
1717
nativeChanged: boolean;
18-
hasChanges: boolean;
19-
changesRequireBuild: boolean;
18+
signingChanged: boolean;
19+
20+
readonly hasChanges: boolean;
21+
readonly changesRequireBuild: boolean;
22+
readonly changesRequirePrepare: boolean;
2023
}
2124

2225
interface IProjectChangesOptions extends IAppFilesUpdaterOptions, IProvision {}

lib/definitions/project.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ interface IPlatformProjectService extends NodeJS.EventEmitter {
258258
* @returns {void}
259259
*/
260260
cleanProject(projectRoot: string, projectData: IProjectData): Promise<void>
261+
262+
/**
263+
* Check the current state of the project, and validate against the options.
264+
* If there are parts in the project that are inconsistent with the desired options, marks them in the changeset flags.
265+
*/
266+
checkForChanges(changeset: IProjectChangesInfo, options: IProjectChangesOptions, projectData: IProjectData): void;
261267
}
262268

263269
interface IAndroidProjectPropertiesManager {

lib/services/android-project-service.ts

+4
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
435435
await adb.executeShellCommand(["rm", "-rf", deviceRootPath]);
436436
}
437437

438+
public checkForChanges(changesInfo: IProjectChangesInfo, options: IProjectChangesOptions, projectData: IProjectData): void {
439+
// Nothing android specific to check yet.
440+
}
441+
438442
private _canUseGradle: boolean;
439443
private canUseGradle(projectData: IProjectData, frameworkVersion?: string): boolean {
440444
if (!this._canUseGradle) {

lib/services/ios-project-service.ts

+50-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { PlistSession } from "plist-merge-patch";
1111
import { EOL } from "os";
1212
import * as temp from "temp";
1313
import * as plist from "plist";
14-
import { Xcode } from "pbxproj-dom/xcode";
1514
import { IOSProvisionService } from "./ios-provision-service";
1615

1716
export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
@@ -42,7 +41,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
4241
private $pluginVariablesService: IPluginVariablesService,
4342
private $xcprojService: IXcprojService,
4443
private $iOSProvisionService: IOSProvisionService,
45-
private $sysInfo: ISysInfo) {
44+
private $sysInfo: ISysInfo,
45+
private $pbxprojDomXcode: IPbxprojDomXcode) {
4646
super($fs, $projectDataService);
4747
}
4848

@@ -379,10 +379,9 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
379379
await this.createIpa(projectRoot, projectData, buildConfig);
380380
}
381381

382-
private async setupSigningFromProvision(projectRoot: string, projectData: IProjectData, provision?: any): Promise<void> {
382+
private async setupSigningFromProvision(projectRoot: string, projectData: IProjectData, provision?: string): Promise<void> {
383383
if (provision) {
384-
const pbxprojPath = path.join(projectRoot, projectData.projectName + ".xcodeproj", "project.pbxproj");
385-
const xcode = Xcode.open(pbxprojPath);
384+
const xcode = this.$pbxprojDomXcode.Xcode.open(this.getPbxProjPath(projectData));
386385
const signing = xcode.getSigning(projectData.projectName);
387386

388387
let shouldUpdateXcode = false;
@@ -399,8 +398,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
399398
}
400399

401400
if (shouldUpdateXcode) {
402-
// This is slow, it read through 260 mobileprovision files on my machine and does quite some checking whether provisioning profiles and devices will match.
403-
// That's why we try to avoid id by checking in the Xcode first.
404401
const pickStart = Date.now();
405402
const mobileprovision = await this.$iOSProvisionService.pick(provision, projectData.projectId);
406403
const pickEnd = Date.now();
@@ -428,11 +425,16 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
428425
}
429426

430427
private async setupSigningForDevice(projectRoot: string, buildConfig: IiOSBuildConfig, projectData: IProjectData): Promise<void> {
431-
const pbxprojPath = path.join(projectRoot, projectData.projectName + ".xcodeproj", "project.pbxproj");
432-
const xcode = Xcode.open(pbxprojPath);
428+
const xcode = this.$pbxprojDomXcode.Xcode.open(this.getPbxProjPath(projectData));
433429
const signing = xcode.getSigning(projectData.projectName);
434430

435-
if ((this.readXCConfigProvisioningProfile(projectData) || this.readXCConfigProvisioningProfileForIPhoneOs(projectData)) && (!signing || signing.style !== "Manual")) {
431+
const hasProvisioningProfileInXCConfig =
432+
this.readXCConfigProvisioningProfileSpecifierForIPhoneOs(projectData) ||
433+
this.readXCConfigProvisioningProfileSpecifier(projectData) ||
434+
this.readXCConfigProvisioningProfileForIPhoneOs(projectData) ||
435+
this.readXCConfigProvisioningProfile(projectData);
436+
437+
if (hasProvisioningProfileInXCConfig && (!signing || signing.style !== "Manual")) {
436438
xcode.setManualSigningStyle(projectData.projectName);
437439
xcode.save();
438440
} else if (!buildConfig.provision && !(signing && signing.style === "Manual" && !buildConfig.teamId)) {
@@ -623,7 +625,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
623625

624626
if (provision) {
625627
let projectRoot = path.join(projectData.platformsDir, "ios");
626-
await this.setupSigningFromProvision(projectRoot, provision);
628+
await this.setupSigningFromProvision(projectRoot, projectData, provision);
627629
}
628630

629631
let project = this.createPbxProj(projectData);
@@ -844,6 +846,35 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
844846
return Promise.resolve();
845847
}
846848

849+
public checkForChanges(changesInfo: IProjectChangesInfo, options: IProjectChangesOptions, projectData: IProjectData): void {
850+
const provision = options.provision;
851+
if (provision !== undefined) {
852+
// Check if the native project's signing is set to the provided provision...
853+
const pbxprojPath = this.getPbxProjPath(projectData);
854+
855+
if (this.$fs.exists(pbxprojPath)) {
856+
const xcode = this.$pbxprojDomXcode.Xcode.open(pbxprojPath);
857+
const signing = xcode.getSigning(projectData.projectName);
858+
if (signing && signing.style === "Manual") {
859+
for (let name in signing.configurations) {
860+
let config = signing.configurations[name];
861+
if (config.uuid !== provision && config.name !== provision) {
862+
changesInfo.signingChanged = true;
863+
break;
864+
}
865+
}
866+
} else {
867+
// Specifying provisioning profile requires "Manual" signing style.
868+
// If the current signing style was not "Manual" it was probably "Automatic" or,
869+
// it was not uniform for the debug and release build configurations.
870+
changesInfo.signingChanged = true;
871+
}
872+
} else {
873+
changesInfo.signingChanged = true;
874+
}
875+
}
876+
}
877+
847878
private getAllLibsForPluginWithFileExtension(pluginData: IPluginData, fileExtension: string): string[] {
848879
let filterCallback = (fileName: string, pluginPlatformsFolderPath: string) => path.extname(fileName) === fileExtension;
849880
return this.getAllNativeLibrariesForPlugin(pluginData, IOSProjectService.IOS_PLATFORM_NAME, filterCallback);
@@ -1186,6 +1217,14 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
11861217
return this.readXCConfig("PROVISIONING_PROFILE[sdk=iphoneos*]", projectData);
11871218
}
11881219

1220+
private readXCConfigProvisioningProfileSpecifier(projectData: IProjectData): string {
1221+
return this.readXCConfig("PROVISIONING_PROFILE_SPECIFIER", projectData);
1222+
}
1223+
1224+
private readXCConfigProvisioningProfileSpecifierForIPhoneOs(projectData: IProjectData): string {
1225+
return this.readXCConfig("PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]", projectData);
1226+
}
1227+
11891228
private async getDevelopmentTeam(projectData: IProjectData, teamId?: string): Promise<string> {
11901229
teamId = teamId || this.readTeamId(projectData);
11911230

lib/services/ios-provision-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class IOSProvisionService {
2929

3030
function formatSupportedDeviceCount(prov: mobileprovision.provision.MobileProvision) {
3131
if (devices.length > 0 && prov.Type === "Development") {
32-
return prov.ProvisionedDevices.reduce((count, device) => count + (devices.indexOf(device) >= 0 ? 1 : 0), 0) + "/" + devices.length + " targets";
32+
return prov.ProvisionedDevices.filter(device => devices.indexOf(device) >= 0).length + "/" + devices.length + " targets";
3333
} else {
3434
return "";
3535
}

lib/services/pbxproj-dom-xcode.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as PbxprojDomXcodeModule from "pbxproj-dom/xcode";
2+
3+
declare global {
4+
type IPbxprojDomXcode = typeof PbxprojDomXcodeModule;
5+
}
6+
7+
$injector.register("pbxprojDomXcode", () => require("pbxproj-dom/xcode"), true);

lib/services/platform-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ export class PlatformService extends EventEmitter implements IPlatformService {
293293
}
294294
}
295295

296-
if (!changesInfo || changesInfo.appResourcesChanged) {
296+
if (!changesInfo || changesInfo.changesRequirePrepare) {
297297
await this.copyAppFiles(platform, appFilesUpdaterOptions, projectData);
298298
this.copyAppResources(platform, projectData);
299299
await platformData.platformProjectService.prepareProject(projectData, platformSpecificData);

lib/services/project-changes-service.ts

+12-11
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,27 @@ class ProjectChangesInfo implements IProjectChangesInfo {
1111
public configChanged: boolean;
1212
public packageChanged: boolean;
1313
public nativeChanged: boolean;
14+
public signingChanged: boolean;
1415

1516
public get hasChanges(): boolean {
1617
return this.packageChanged ||
1718
this.appFilesChanged ||
1819
this.appResourcesChanged ||
1920
this.modulesChanged ||
20-
this.configChanged;
21+
this.configChanged ||
22+
this.signingChanged;
2123
}
2224

2325
public get changesRequireBuild(): boolean {
2426
return this.packageChanged ||
2527
this.appResourcesChanged ||
2628
this.nativeChanged;
2729
}
30+
31+
public get changesRequirePrepare(): boolean {
32+
return this.appResourcesChanged ||
33+
this.signingChanged;
34+
}
2835
}
2936

3037
export class ProjectChangesService implements IProjectChangesService {
@@ -75,16 +82,10 @@ export class ProjectChangesService implements IProjectChangesService {
7582
]);
7683
}
7784
}
78-
if (platform.toLowerCase() === this.$devicePlatformsConstants.iOS.toLowerCase()) {
79-
const nextCommandProvisionUUID = projectChangesOptions.provision;
80-
// We should consider reading here the provisioning profile UUID from the xcodeproj and xcconfig.
81-
const prevProvisionUUID = this._prepareInfo.iOSProvisioningProfileUUID;
82-
if (nextCommandProvisionUUID !== prevProvisionUUID) {
83-
this._changesInfo.nativeChanged = true;
84-
this._changesInfo.configChanged = true;
85-
this._prepareInfo.iOSProvisioningProfileUUID = nextCommandProvisionUUID;
86-
}
87-
}
85+
86+
let projectService = platformData.platformProjectService;
87+
projectService.checkForChanges(this._changesInfo, projectChangesOptions, projectData);
88+
8889
if (projectChangesOptions.bundle !== this._prepareInfo.bundle || projectChangesOptions.release !== this._prepareInfo.release) {
8990
this._changesInfo.appFilesChanged = true;
9091
this._changesInfo.appResourcesChanged = true;

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"mute-stream": "0.0.5",
5757
"open": "0.0.5",
5858
"osenv": "0.1.3",
59-
"pbxproj-dom": "1.0.9",
59+
"pbxproj-dom": "1.0.11",
6060
"plist": "1.1.0",
6161
"plist-merge-patch": "0.0.9",
6262
"plistlib": "0.2.1",
@@ -98,8 +98,8 @@
9898
"grunt-tslint": "4.0.0",
9999
"istanbul": "0.4.5",
100100
"mocha": "3.1.2",
101-
"mocha-typescript": "^1.0.4",
102101
"should": "7.0.2",
102+
"source-map-support": "^0.4.14",
103103
"tslint": "4.3.1",
104104
"typescript": "2.1.4"
105105
},

test/ios-project-service.ts

+90
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ function createTestInjector(projectPath: string, projectName: string): IInjector
8585
testInjector.register("androidProcessService", {});
8686
testInjector.register("processService", {});
8787
testInjector.register("sysInfo", {});
88+
testInjector.register("pbxprojDomXcode", {});
8889
return testInjector;
8990
}
9091

@@ -486,3 +487,92 @@ describe("Relative paths", () => {
486487
assert.equal(result, path.join("..", "..", "sub", "path"));
487488
});
488489
});
490+
491+
describe("iOS Project Service Signing", () => {
492+
let testInjector: IInjector;
493+
let projectPath: string;
494+
let files: any;
495+
let pbxprojects: any;
496+
let iOSProjectService: IPlatformProjectService;
497+
let projectData: any;
498+
let pbxproj: string;
499+
500+
beforeEach(() => {
501+
let projectName = "projectDirectory";
502+
files = {};
503+
pbxprojects = {};
504+
projectPath = temp.mkdirSync(projectName);
505+
testInjector = createTestInjector(projectPath, projectName);
506+
testInjector.register("fs", {
507+
files: {},
508+
readJson(path: string): any {
509+
if (this.exists(path)) {
510+
return JSON.stringify(files[path]);
511+
} else {
512+
return null;
513+
}
514+
},
515+
exists(path: string): boolean {
516+
return path in files;
517+
}
518+
});
519+
testInjector.register("pbxprojDomXcode", {
520+
Xcode: {
521+
open(path: string) {
522+
return pbxprojects[path];
523+
}
524+
}
525+
});
526+
pbxproj = path.join(projectPath, "platforms/ios/projectDirectory.xcodeproj/project.pbxproj");
527+
iOSProjectService = testInjector.resolve("iOSProjectService");
528+
projectData = testInjector.resolve("projectData");
529+
});
530+
531+
describe("Check for Changes", () => {
532+
it("sets signingChanged if no Xcode project exists", () => {
533+
let changes = <IProjectChangesInfo>{};
534+
iOSProjectService.checkForChanges(changes, { bundle: false, release: false, provision: "NativeScriptDev" }, projectData);
535+
assert.isTrue(!!changes.signingChanged);
536+
});
537+
it("sets signingChanged if the Xcode projects is configured with Automatic signing, but proivsion is specified", () => {
538+
files[pbxproj] = "";
539+
pbxprojects[pbxproj] = {
540+
getSigning() {
541+
return { style: "Automatic" };
542+
}
543+
};
544+
let changes = <IProjectChangesInfo>{};
545+
iOSProjectService.checkForChanges(changes, { bundle: false, release: false, provision: "NativeScriptDev" }, projectData);
546+
assert.isTrue(!!changes.signingChanged);
547+
});
548+
it("sets signingChanged if the Xcode projects is configured with Manual signing, but the proivsion specified differs the selected in the pbxproj", () => {
549+
files[pbxproj] = "";
550+
pbxprojects[pbxproj] = {
551+
getSigning() {
552+
return { style: "Manual", configurations: {
553+
Debug: { name: "NativeScriptDev2" },
554+
Release: { name: "NativeScriptDev2" }
555+
}};
556+
}
557+
};
558+
let changes = <IProjectChangesInfo>{};
559+
iOSProjectService.checkForChanges(changes, { bundle: false, release: false, provision: "NativeScriptDev" }, projectData);
560+
assert.isTrue(!!changes.signingChanged);
561+
});
562+
it("does not set signingChanged if the Xcode projects is configured with Manual signing and proivsion matches", () => {
563+
let pbxproj = path.join(projectPath, "platforms/ios/projectDirectory.xcodeproj/project.pbxproj");
564+
files[pbxproj] = "";
565+
pbxprojects[pbxproj] = {
566+
getSigning() {
567+
return { style: "Manual", configurations: {
568+
Debug: { name: "NativeScriptDev" },
569+
Release: { name: "NativeScriptDev" }
570+
}};
571+
}
572+
};
573+
let changes = <IProjectChangesInfo>{};
574+
iOSProjectService.checkForChanges(changes, { bundle: false, release: false, provision: "NativeScriptDev" }, projectData);
575+
assert.isFalse(!!changes.signingChanged);
576+
});
577+
});
578+
});

test/mocha.opts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
--recursive
22
--reporter spec
3+
--require source-map-support/register
34
--require test/test-bootstrap.js
45
--timeout 150000
56
test/

test/npm-support.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ async function setupProject(dependencies?: any): Promise<any> {
159159
ensureConfigurationFileInAppResources: (): any => null,
160160
interpolateConfigurationFile: (): void => undefined,
161161
isPlatformPrepared: (projectRoot: string) => false,
162-
validatePlugins: (projectData: IProjectData) => Promise.resolve()
162+
validatePlugins: (projectData: IProjectData) => Promise.resolve(),
163+
checkForChanges: () => { /* */ }
163164
}
164165
};
165166
};

0 commit comments

Comments
 (0)