From 7fdb7b784eec37fa41f54c7394dd75bb3428d39d Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 18 Apr 2019 17:51:22 +0300 Subject: [PATCH 01/10] feat: initial work on watch app integration --- lib/bootstrap.ts | 1 + lib/common/definitions/mobile.d.ts | 4 + .../ios/simulator/ios-simulator-device.ts | 1 + lib/definitions/xcode.d.ts | 3 +- lib/services/ios-project-service.ts | 32 +++-- lib/services/ios-watch-app-service.ts | 117 ++++++++++++++++++ 6 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 lib/services/ios-watch-app-service.ts diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 0cdbeb89bd..d99ca32d44 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -13,6 +13,7 @@ $injector.require("androidProjectService", "./services/android-project-service") $injector.require("androidPluginBuildService", "./services/android-plugin-build-service"); $injector.require("iOSEntitlementsService", "./services/ios-entitlements-service"); $injector.require("iOSExtensionsService", "./services/ios-extensions-service"); +$injector.require("iOSWatchAppService", "./services/ios-watch-app-service"); $injector.require("iOSProjectService", "./services/ios-project-service"); $injector.require("iOSProvisionService", "./services/ios-provision-service"); $injector.require("xcconfigService", "./services/xcconfig-service"); diff --git a/lib/common/definitions/mobile.d.ts b/lib/common/definitions/mobile.d.ts index 1ce531beef..229c23a939 100644 --- a/lib/common/definitions/mobile.d.ts +++ b/lib/common/definitions/mobile.d.ts @@ -81,6 +81,10 @@ declare module Mobile { imageIdentifier?: string; } + interface IIOSWatchSimulatorDevice extends IDeviceInfo{ + + } + interface IDeviceError extends Error, IDeviceIdentifier { } interface IDeviceIdentifier { diff --git a/lib/common/mobile/ios/simulator/ios-simulator-device.ts b/lib/common/mobile/ios/simulator/ios-simulator-device.ts index 50a178d4f3..489712a140 100644 --- a/lib/common/mobile/ios/simulator/ios-simulator-device.ts +++ b/lib/common/mobile/ios/simulator/ios-simulator-device.ts @@ -10,6 +10,7 @@ export class IOSSimulator extends IOSDeviceBase implements Mobile.IiOSDevice { public applicationManager: Mobile.IDeviceApplicationManager; public fileSystem: Mobile.IDeviceFileSystem; public deviceInfo: Mobile.IDeviceInfo; + public watchSimulator: Mobile.IIOSWatchSimulatorDevice; constructor(private simulator: Mobile.IiSimDevice, private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, diff --git a/lib/definitions/xcode.d.ts b/lib/definitions/xcode.d.ts index 065fbe2067..01c561dab3 100644 --- a/lib/definitions/xcode.d.ts +++ b/lib/definitions/xcode.d.ts @@ -28,7 +28,7 @@ declare module "nativescript-dev-xcode" { pbxXCBuildConfigurationSection(): any; - addTarget(targetName: string, targetType: string, targetPath?: string): target; + addTarget(targetName: string, targetType: string, targetPath?: string, parentTarget?: string): target; addBuildPhase(filePathsArray: string[], buildPhaseType: string, comment: string, @@ -47,6 +47,7 @@ declare module "nativescript-dev-xcode" { addBuildProperty(prop: string, value: any, build_name?: string, productName?: string): void; addToHeaderSearchPaths(file: string|Object, productName?: string): void; removeTargetsByProductType(targetType: string): void + getFirstTarget(): {uuid: string} } class target { diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 3a68c26b91..45d451fb06 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -53,7 +53,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private $plistParser: IPlistParser, private $sysInfo: ISysInfo, private $xcconfigService: IXcconfigService, - private $iOSExtensionsService: IIOSExtensionsService) { + private $iOSExtensionsService: IIOSExtensionsService, + private $iOSWatchAppService: IIOSExtensionsService) { super($fs, $projectDataService); } @@ -414,7 +415,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ args = args.concat((buildConfig && buildConfig.architectures) || this.getBuildArchitectures(projectData, buildConfig, ["armv7", "arm64"])); args = args.concat([ - "-sdk", DevicePlatformSdkName, "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR) ]); @@ -503,6 +503,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ xcode.setAutomaticSigningStyle(projectData.projectName, teamId); xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.app-extension", teamId); + xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.watchkit2-extension", teamId); + xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.application.watchapp2", teamId); xcode.save(); this.$logger.trace(`Set Automatic signing style and team id ${teamId}.`); @@ -584,12 +586,13 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ .concat([ "build", "-configuration", getConfigurationName(buildConfig.release), - "-sdk", SimulatorPlatformSdkName, "ONLY_ACTIVE_ARCH=NO", "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR), - "CODE_SIGN_IDENTITY=", + "CODE_SIGNING_ALLOWED=NO", + "-destination", + "generic/platform=iOS Simulator" ]) - .concat(this.xcbuildProjectArgs(projectRoot, projectData)); + .concat(this.xcbuildProjectArgs(projectRoot, projectData, "scheme")); await this.xcodebuild(args, projectRoot, buildConfig.buildOutputStdio); } @@ -781,15 +784,18 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f _.each(imagesToRemove, image => project.removeResourceFile(path.join(this.getAppResourcesDestinationDirectoryPath(projectData), image))); this.savePbxProj(project, projectData); - - const resourcesNativeCodePath = path.join( - projectData.getAppResourcesDirectoryPath(), - this.getPlatformData(projectData).normalizedPlatformName, - constants.NATIVE_SOURCE_FOLDER - ); - - await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); } + + const platformData = this.getPlatformData(projectData); + const resourlcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); + const pbxProjPath = this.getPbxProjPath(projectData); + const resourcesNativeCodePath = path.join( + projectData.getAppResourcesDirectoryPath(), + platformData.normalizedPlatformName, + constants.NATIVE_SOURCE_FOLDER + ); + await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); + await this.$iOSWatchAppService.addExtensionsFromPath({ extensionsFolderPath: path.join(resourlcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); } diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts new file mode 100644 index 0000000000..5d90ebedac --- /dev/null +++ b/lib/services/ios-watch-app-service.ts @@ -0,0 +1,117 @@ +import * as path from "path"; + +export class IOSWatchAppService implements IIOSExtensionsService { + constructor(private $fs: IFileSystem, + private $pbxprojDomXcode: IPbxprojDomXcode, + private $xcode: IXcode) { + } + + public async addExtensionsFromPath({extensionsFolderPath, projectData, platformData, pbxProjPath}: IAddExtensionsFromPathOptions): Promise { + const targetUuids: string[] = []; + let addedExtensions = false; + if (!this.$fs.exists(extensionsFolderPath)) { + return false; + } + const project = new this.$xcode.project(pbxProjPath); + const appPath = path.join(extensionsFolderPath, "watchapp"); + const extensionPath = path.join(extensionsFolderPath, "watchextension"); + project.parseSync(); + const appFolder = this.$fs.readDirectory(appPath) + .filter(fileName => { + const filePath = path.join(appPath, fileName); + const stats = this.$fs.getFsStats(filePath); + + return stats.isDirectory() && !fileName.startsWith("."); + })[0]; + + const extensionFolder = this.$fs.readDirectory(extensionPath) + .filter(fileName => { + const filePath = path.join(extensionPath, fileName); + const stats = this.$fs.getFsStats(filePath); + + return stats.isDirectory() && !fileName.startsWith("."); + })[0]; + + let targetUuid = this.addExtensionToProject(appPath, appFolder, project, projectData, platformData, "watch_app", `${projectData.projectIdentifiers.ios}.watchkitapp`, project.getFirstTarget().uuid); + targetUuids.push(targetUuid); + targetUuid = this.addExtensionToProject(extensionPath, extensionFolder, project, projectData, platformData, "watch_extension", `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, targetUuid); + targetUuids.push(targetUuid); + addedExtensions = true; + + this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); + this.prepareExtensionSigning(targetUuids, projectData, pbxProjPath); + + return addedExtensions; + } + + private addExtensionToProject(extensionsFolderPath: string, extensionFolder: string, project: IXcode.project, projectData: IProjectData, platformData: IPlatformData, targetType: string, identifier: string, parentTarget: string): string { + const extensionPath = path.join(extensionsFolderPath, extensionFolder); + const extensionRelativePath = path.relative(platformData.projectRoot, extensionPath); + const files = this.$fs.readDirectory(extensionPath) + .filter(filePath => !filePath.startsWith(".")) + .map(filePath => path.join(extensionPath, filePath)); + const target = project.addTarget(extensionFolder, targetType, extensionRelativePath, parentTarget); + project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid); + project.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', target.uuid); + project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid); + + const extJsonPath = path.join(extensionsFolderPath, extensionFolder, "extension.json"); + if (this.$fs.exists(extJsonPath)) { + const extensionJson = this.$fs.readJson(extJsonPath); + _.forEach(extensionJson.frameworks, framework => { + project.addFramework( + framework, + { target: target.uuid } + ); + }); + if (extensionJson.assetcatalogCompilerAppiconName) { + project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", extensionJson.assetcatalogCompilerAppiconName, target.uuid); + } + } + const identifierParts = identifier.split("."); + identifierParts.pop(); + const wkAppBundleIdentifier = identifierParts.join("."); + project.addPbxGroup(files, extensionFolder, extensionPath, null, { isMain: true, target: target.uuid, filesRelativeToProject: true }); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Debug", extensionFolder); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Release", extensionFolder); + project.addBuildProperty("SDKROOT", "watchos", "Debug", extensionFolder); + project.addBuildProperty("SDKROOT", "watchos", "Release", extensionFolder); + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Debug", extensionFolder); + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Release", extensionFolder); + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Debug", extensionFolder); + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Release", extensionFolder); + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Debug", extensionFolder); + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Release", extensionFolder); + project.addToHeaderSearchPaths(extensionPath, target.pbxNativeTarget.productName); + + return target.uuid; + } + + private prepareExtensionSigning(targetUuids: string[], projectData:IProjectData, projectPath: string) { + const xcode = this.$pbxprojDomXcode.Xcode.open(projectPath); + const signing = xcode.getSigning(projectData.projectName); + if (signing !== undefined) { + _.forEach(targetUuids, targetUuid => { + if (signing.style === "Automatic") { + xcode.setAutomaticSigningStyleByTargetKey(targetUuid, signing.team); + } else { + for (const config in signing.configurations) { + const signingConfiguration = signing.configurations[config]; + xcode.setManualSigningStyleByTargetKey(targetUuid, signingConfiguration); + break; + } + } + }); + } + xcode.save(); + } + + public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { + const project = new this.$xcode.project(pbxProjPath); + project.parseSync(); + project.removeTargetsByProductType("com.apple.product-type.app-extension"); + this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); + } +} + +$injector.register("iOSWatchAppService", IOSWatchAppService); From 25bf41a627a3f85ffe907acf3a913aeab4ad45cb Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Fri, 19 Apr 2019 16:28:44 +0300 Subject: [PATCH 02/10] refactor: extract common logic for watch app and extensions --- lib/definitions/project.d.ts | 29 ++++- lib/services/ios-extensions-service.ts | 58 +++------- .../ios-native-target-service-base.ts | 43 +++++++ lib/services/ios-project-service.ts | 11 +- lib/services/ios-watch-app-service.ts | 106 ++++++------------ 5 files changed, 124 insertions(+), 123 deletions(-) create mode 100644 lib/services/ios-native-target-service-base.ts diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 37be0d1158..e5d4254a94 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -592,17 +592,42 @@ interface IIOSExtensionsService { removeExtensions(options: IRemoveExtensionsOptions): void; } -interface IAddExtensionsFromPathOptions { - extensionsFolderPath: string; +interface IIOSNativeTargetServiceBase { +} + +/** + * Describes a service used to add and remove iOS extension + */ +interface IIOSExtensionsService { + addExtensionsFromPath(options: IAddExtensionsFromPathOptions): Promise; + removeExtensions(options: IRemoveExtensionsOptions): void; +} + +interface IIOSWatchAppService { + addWatchAppFromPath(options: IAddWatchAppFromPathOptions): Promise; + removeWatchApp(options: IRemoveWatchAppOptions): void; +} + +interface IAddTargetFromPathOptions { projectData: IProjectData; platformData: IPlatformData; pbxProjPath: string; } +interface IAddExtensionsFromPathOptions extends IAddTargetFromPathOptions { + extensionsFolderPath: string; +} + +interface IAddWatchAppFromPathOptions extends IAddTargetFromPathOptions { + watchAppFolderPath: string; +} + interface IRemoveExtensionsOptions { pbxProjPath: string } +interface IRemoveWatchAppOptions extends IRemoveExtensionsOptions{} + interface IRubyFunction { functionName: string; functionParameters?: string; diff --git a/lib/services/ios-extensions-service.ts b/lib/services/ios-extensions-service.ts index e54420b635..bd8daa362d 100644 --- a/lib/services/ios-extensions-service.ts +++ b/lib/services/ios-extensions-service.ts @@ -1,9 +1,11 @@ import * as path from "path"; +import { NativeTargetServiceBase } from "./ios-native-target-service-base"; -export class IOSExtensionsService implements IIOSExtensionsService { - constructor(private $fs: IFileSystem, - private $pbxprojDomXcode: IPbxprojDomXcode, - private $xcode: IXcode) { +export class IOSExtensionsService extends NativeTargetServiceBase implements IIOSExtensionsService { + constructor(protected $fs: IFileSystem, + protected $pbxprojDomXcode: IPbxprojDomXcode, + protected $xcode: IXcode) { + super($fs, $pbxprojDomXcode, $xcode); } public async addExtensionsFromPath({extensionsFolderPath, projectData, platformData, pbxProjPath}: IAddExtensionsFromPathOptions): Promise { @@ -22,29 +24,20 @@ export class IOSExtensionsService implements IIOSExtensionsService { return stats.isDirectory() && !fileName.startsWith("."); }) .forEach(extensionFolder => { - const targetUuid = this.addExtensionToProject(extensionsFolderPath, extensionFolder, project, projectData, platformData); - targetUuids.push(targetUuid); + const target = this.addTargetToProject(extensionsFolderPath, extensionFolder, 'app_extension', project, platformData); + this.configureTarget(extensionFolder, path.join(extensionsFolderPath, extensionFolder), target, project, projectData); + targetUuids.push(target.uuid); addedExtensions = true; }); this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); - this.prepareExtensionSigning(targetUuids, projectData, pbxProjPath); + this.prepareSigning(targetUuids, projectData, pbxProjPath); return addedExtensions; } - private addExtensionToProject(extensionsFolderPath: string, extensionFolder: string, project: IXcode.project, projectData: IProjectData, platformData: IPlatformData): string { - const extensionPath = path.join(extensionsFolderPath, extensionFolder); - const extensionRelativePath = path.relative(platformData.projectRoot, extensionPath); - const files = this.$fs.readDirectory(extensionPath) - .filter(filePath => !filePath.startsWith(".")) - .map(filePath => path.join(extensionPath, filePath)); - const target = project.addTarget(extensionFolder, 'app_extension', extensionRelativePath); - project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid); - project.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', target.uuid); - project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid); - - const extJsonPath = path.join(extensionsFolderPath, extensionFolder, "extension.json"); + private configureTarget(extensionName: string, extensionPath: string, target: IXcode.target, project: IXcode.project, projectData: IProjectData) { + const extJsonPath = path.join(extensionPath, "extension.json"); if (this.$fs.exists(extJsonPath)) { const extensionJson = this.$fs.readJson(extJsonPath); _.forEach(extensionJson.frameworks, framework => { @@ -58,31 +51,8 @@ export class IOSExtensionsService implements IIOSExtensionsService { } } - project.addPbxGroup(files, extensionFolder, extensionPath, null, { isMain: true, target: target.uuid, filesRelativeToProject: true }); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionFolder}`, "Debug", extensionFolder); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionFolder}`, "Release", extensionFolder); - project.addToHeaderSearchPaths(extensionPath, target.pbxNativeTarget.productName); - - return target.uuid; - } - - private prepareExtensionSigning(targetUuids: string[], projectData:IProjectData, projectPath: string) { - const xcode = this.$pbxprojDomXcode.Xcode.open(projectPath); - const signing = xcode.getSigning(projectData.projectName); - if (signing !== undefined) { - _.forEach(targetUuids, targetUuid => { - if (signing.style === "Automatic") { - xcode.setAutomaticSigningStyleByTargetKey(targetUuid, signing.team); - } else { - for (const config in signing.configurations) { - const signingConfiguration = signing.configurations[config]; - xcode.setManualSigningStyleByTargetKey(targetUuid, signingConfiguration); - break; - } - } - }); - } - xcode.save(); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionName}`, "Debug", extensionName); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionName}`, "Release", extensionName); } public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { diff --git a/lib/services/ios-native-target-service-base.ts b/lib/services/ios-native-target-service-base.ts new file mode 100644 index 0000000000..48d1d94779 --- /dev/null +++ b/lib/services/ios-native-target-service-base.ts @@ -0,0 +1,43 @@ +import * as path from "path"; + +export abstract class NativeTargetServiceBase implements IIOSNativeTargetServiceBase { + constructor(protected $fs: IFileSystem, + protected $pbxprojDomXcode: IPbxprojDomXcode, + protected $xcode: IXcode) { + } + + protected addTargetToProject(extensionsFolderPath: string, extensionFolder: string, targetType: string, project: IXcode.project, platformData: IPlatformData, parentTarget?: string): IXcode.target { + const extensionPath = path.join(extensionsFolderPath, extensionFolder); + const extensionRelativePath = path.relative(platformData.projectRoot, extensionPath); + const files = this.$fs.readDirectory(extensionPath) + .filter(filePath => !filePath.startsWith(".")) + .map(filePath => path.join(extensionPath, filePath)); + const target = project.addTarget(extensionFolder, targetType, extensionRelativePath, parentTarget); + project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid); + project.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', target.uuid); + project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid); + + project.addPbxGroup(files, extensionFolder, extensionPath, null, { isMain: true, target: target.uuid, filesRelativeToProject: true }); + project.addToHeaderSearchPaths(extensionPath, target.pbxNativeTarget.productName); + return target; + } + + protected prepareSigning(targetUuids: string[], projectData:IProjectData, projectPath: string) { + const xcode = this.$pbxprojDomXcode.Xcode.open(projectPath); + const signing = xcode.getSigning(projectData.projectName); + if (signing !== undefined) { + _.forEach(targetUuids, targetUuid => { + if (signing.style === "Automatic") { + xcode.setAutomaticSigningStyleByTargetKey(targetUuid, signing.team); + } else { + for (const config in signing.configurations) { + const signingConfiguration = signing.configurations[config]; + xcode.setManualSigningStyleByTargetKey(targetUuid, signingConfiguration); + break; + } + } + }); + } + xcode.save(); + } +} diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 45d451fb06..0dab214a99 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -54,7 +54,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private $sysInfo: ISysInfo, private $xcconfigService: IXcconfigService, private $iOSExtensionsService: IIOSExtensionsService, - private $iOSWatchAppService: IIOSExtensionsService) { + private $iOSWatchAppService: IIOSWatchAppService) { super($fs, $projectDataService); } @@ -785,9 +785,9 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f this.savePbxProj(project, projectData); } - + const platformData = this.getPlatformData(projectData); - const resourlcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); + const resourcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); const pbxProjPath = this.getPbxProjPath(projectData); const resourcesNativeCodePath = path.join( projectData.getAppResourcesDirectoryPath(), @@ -795,7 +795,8 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f constants.NATIVE_SOURCE_FOLDER ); await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); - await this.$iOSWatchAppService.addExtensionsFromPath({ extensionsFolderPath: path.join(resourlcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); + this.$iOSWatchAppService.removeWatchApp({ pbxProjPath }); + await this.$iOSWatchAppService.addWatchAppFromPath({ watchAppFolderPath: path.join(resourcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); } @@ -809,6 +810,8 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f // src folder should not be copied as the pbxproject will have references to its files this.$fs.deleteDirectory(path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, constants.NATIVE_SOURCE_FOLDER)); this.$fs.deleteDirectory(path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, constants.NATIVE_EXTENSION_FOLDER)); + this.$fs.deleteDirectory(path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, "watchapp")); + this.$fs.deleteDirectory(path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, "watchextension")); this.$fs.deleteDirectory(this.getAppResourcesDestinationDirectoryPath(projectData)); } diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 5d90ebedac..54d8d15374 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -1,20 +1,22 @@ import * as path from "path"; +import { NativeTargetServiceBase } from "./ios-native-target-service-base"; -export class IOSWatchAppService implements IIOSExtensionsService { - constructor(private $fs: IFileSystem, - private $pbxprojDomXcode: IPbxprojDomXcode, - private $xcode: IXcode) { +export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSWatchAppService { + constructor(protected $fs: IFileSystem, + protected $pbxprojDomXcode: IPbxprojDomXcode, + protected $xcode: IXcode) { + super($fs, $pbxprojDomXcode, $xcode); } - public async addExtensionsFromPath({extensionsFolderPath, projectData, platformData, pbxProjPath}: IAddExtensionsFromPathOptions): Promise { + public async addWatchAppFromPath({watchAppFolderPath, projectData, platformData, pbxProjPath}: IAddWatchAppFromPathOptions): Promise { const targetUuids: string[] = []; let addedExtensions = false; - if (!this.$fs.exists(extensionsFolderPath)) { + if (!this.$fs.exists(watchAppFolderPath)) { return false; } const project = new this.$xcode.project(pbxProjPath); - const appPath = path.join(extensionsFolderPath, "watchapp"); - const extensionPath = path.join(extensionsFolderPath, "watchextension"); + const appPath = path.join(watchAppFolderPath, "watchapp"); + const extensionPath = path.join(watchAppFolderPath, "watchextension"); project.parseSync(); const appFolder = this.$fs.readDirectory(appPath) .filter(fileName => { @@ -32,84 +34,42 @@ export class IOSWatchAppService implements IIOSExtensionsService { return stats.isDirectory() && !fileName.startsWith("."); })[0]; - let targetUuid = this.addExtensionToProject(appPath, appFolder, project, projectData, platformData, "watch_app", `${projectData.projectIdentifiers.ios}.watchkitapp`, project.getFirstTarget().uuid); - targetUuids.push(targetUuid); - targetUuid = this.addExtensionToProject(extensionPath, extensionFolder, project, projectData, platformData, "watch_extension", `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, targetUuid); - targetUuids.push(targetUuid); - addedExtensions = true; + const watchApptarget = this.addTargetToProject(appPath, appFolder, "watch_app", project, platformData, project.getFirstTarget().uuid); + this.configureTarget(appFolder, path.join(appPath, appFolder), `${projectData.projectIdentifiers.ios}.watchkitapp`, watchApptarget, project); + targetUuids.push(watchApptarget.uuid); + const watchExtensionTarget = this.addTargetToProject(extensionPath, extensionFolder, "watch_extension", project, platformData, watchApptarget.uuid); + this.configureTarget(extensionFolder, path.join(extensionPath, extensionFolder), `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, watchExtensionTarget, project); + targetUuids.push(watchExtensionTarget.uuid); + addedExtensions = true; this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); - this.prepareExtensionSigning(targetUuids, projectData, pbxProjPath); + this.prepareSigning(targetUuids, projectData, pbxProjPath); return addedExtensions; } - private addExtensionToProject(extensionsFolderPath: string, extensionFolder: string, project: IXcode.project, projectData: IProjectData, platformData: IPlatformData, targetType: string, identifier: string, parentTarget: string): string { - const extensionPath = path.join(extensionsFolderPath, extensionFolder); - const extensionRelativePath = path.relative(platformData.projectRoot, extensionPath); - const files = this.$fs.readDirectory(extensionPath) - .filter(filePath => !filePath.startsWith(".")) - .map(filePath => path.join(extensionPath, filePath)); - const target = project.addTarget(extensionFolder, targetType, extensionRelativePath, parentTarget); - project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid); - project.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', target.uuid); - project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid); - - const extJsonPath = path.join(extensionsFolderPath, extensionFolder, "extension.json"); - if (this.$fs.exists(extJsonPath)) { - const extensionJson = this.$fs.readJson(extJsonPath); - _.forEach(extensionJson.frameworks, framework => { - project.addFramework( - framework, - { target: target.uuid } - ); - }); - if (extensionJson.assetcatalogCompilerAppiconName) { - project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", extensionJson.assetcatalogCompilerAppiconName, target.uuid); - } - } + private configureTarget(targetName: string, targetPath: string, identifier: string, target: IXcode.target, project: IXcode.project) { const identifierParts = identifier.split("."); identifierParts.pop(); const wkAppBundleIdentifier = identifierParts.join("."); - project.addPbxGroup(files, extensionFolder, extensionPath, null, { isMain: true, target: target.uuid, filesRelativeToProject: true }); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Debug", extensionFolder); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Release", extensionFolder); - project.addBuildProperty("SDKROOT", "watchos", "Debug", extensionFolder); - project.addBuildProperty("SDKROOT", "watchos", "Release", extensionFolder); - project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Debug", extensionFolder); - project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Release", extensionFolder); - project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Debug", extensionFolder); - project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Release", extensionFolder); - project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Debug", extensionFolder); - project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Release", extensionFolder); - project.addToHeaderSearchPaths(extensionPath, target.pbxNativeTarget.productName); - - return target.uuid; - } - - private prepareExtensionSigning(targetUuids: string[], projectData:IProjectData, projectPath: string) { - const xcode = this.$pbxprojDomXcode.Xcode.open(projectPath); - const signing = xcode.getSigning(projectData.projectName); - if (signing !== undefined) { - _.forEach(targetUuids, targetUuid => { - if (signing.style === "Automatic") { - xcode.setAutomaticSigningStyleByTargetKey(targetUuid, signing.team); - } else { - for (const config in signing.configurations) { - const signingConfiguration = signing.configurations[config]; - xcode.setManualSigningStyleByTargetKey(targetUuid, signingConfiguration); - break; - } - } - }); - } - xcode.save(); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Debug", targetName); + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Release", targetName); + project.addBuildProperty("SDKROOT", "watchos", "Debug", targetName); + project.addBuildProperty("SDKROOT", "watchos", "Release", targetName); + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Debug", targetName); + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Release", targetName); + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Debug", targetName); + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Release", targetName); + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Debug", targetName); + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Release", targetName); + project.addToHeaderSearchPaths(targetPath, target.pbxNativeTarget.productName); } - public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { + public removeWatchApp({pbxProjPath}: IRemoveWatchAppOptions): void { const project = new this.$xcode.project(pbxProjPath); project.parseSync(); - project.removeTargetsByProductType("com.apple.product-type.app-extension"); + project.removeTargetsByProductType("com.apple.product-type.application.watchapp2"); + project.removeTargetsByProductType("com.apple.product-type.watchkit2-extension"); this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); } } From 57a97a390df38acd4e379744c6aba55953d4ad19 Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Tue, 23 Apr 2019 16:59:06 +0300 Subject: [PATCH 03/10] fix: code signing for apps with watchapp --- lib/services/ios-project-service.ts | 44 +++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 0dab214a99..b7be03e2ac 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -21,6 +21,11 @@ interface INativeSourceCodeGroup { files: string[]; } +enum ProductArgs { + target = "target", + scheme = "scheme" +} + const DevicePlatformSdkName = "iphoneos"; const SimulatorPlatformSdkName = "iphonesimulator"; @@ -215,7 +220,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ const archivePath = options && options.archivePath ? path.resolve(options.archivePath) : path.join(platformData.getBuildOutputPath(buildConfig), projectData.projectName + ".xcarchive"); let args = ["archive", "-archivePath", archivePath, "-configuration", getConfigurationName(!buildConfig || buildConfig.release)] - .concat(this.xcbuildProjectArgs(projectRoot, projectData, "scheme")); + .concat(this.xcbuildProjectArgs(projectRoot, projectData, ProductArgs.scheme)); if (options && options.additionalArgs) { args = args.concat(options.additionalArgs); @@ -340,7 +345,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ return exportFile; } - private xcbuildProjectArgs(projectRoot: string, projectData: IProjectData, product?: "scheme" | "target"): string[] { + private xcbuildProjectArgs(projectRoot: string, projectData: IProjectData, product?: ProductArgs): string[] { const xcworkspacePath = path.join(projectRoot, projectData.projectName + ".xcworkspace"); if (this.$fs.exists(xcworkspacePath)) { return ["-workspace", xcworkspacePath, product ? "-" + product : "-scheme", projectData.projectName]; @@ -414,6 +419,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ args = args.concat((buildConfig && buildConfig.architectures) || this.getBuildArchitectures(projectData, buildConfig, ["armv7", "arm64"])); + if (!this.hasWatchApp(projectData)) { + args = args.concat([ + "-sdk", DevicePlatformSdkName + ]); + } + args = args.concat([ "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR) ]); @@ -580,6 +591,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private async buildForSimulator(projectRoot: string, args: string[], projectData: IProjectData, buildConfig?: IBuildConfig): Promise { const architectures = this.getBuildArchitectures(projectData, buildConfig, ["i386", "x86_64"]); + let product = ProductArgs.target; args = args .concat(architectures) @@ -588,11 +600,16 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ "-configuration", getConfigurationName(buildConfig.release), "ONLY_ACTIVE_ARCH=NO", "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR), - "CODE_SIGNING_ALLOWED=NO", - "-destination", - "generic/platform=iOS Simulator" - ]) - .concat(this.xcbuildProjectArgs(projectRoot, projectData, "scheme")); + ]); + + if (this.hasWatchApp(projectData)) { + product = ProductArgs.scheme; + args = args.concat(["-destination", "generic/platform=iOS Simulator", "CODE_SIGNING_ALLOWED=NO"]); + } else { + args = args.concat(["-sdk", SimulatorPlatformSdkName, "CODE_SIGN_IDENTITY="]); + } + + args = args.concat(this.xcbuildProjectArgs(projectRoot, projectData, product)); await this.xcodebuild(args, projectRoot, buildConfig.buildOutputStdio); } @@ -790,7 +807,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f const resourcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); const pbxProjPath = this.getPbxProjPath(projectData); const resourcesNativeCodePath = path.join( - projectData.getAppResourcesDirectoryPath(), + resourcesDirectoryPath, platformData.normalizedPlatformName, constants.NATIVE_SOURCE_FOLDER ); @@ -1398,6 +1415,17 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f "Enterprise": "enterprise" }[provision.Type]; } + + private hasWatchApp(projectData: IProjectData) { + const platformData = this.getPlatformData(projectData); + const watchAppPath = path.join( + projectData.getAppResourcesDirectoryPath(), + platformData.normalizedPlatformName, + constants.IOS_WATCHAPP_FOLDER + ); + + return this.$fs.exists(watchAppPath); + } } $injector.register("iOSProjectService", IOSProjectService); From 3c08232152ffa98cd55081f0effe9961ecac1a78 Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Tue, 23 Apr 2019 17:00:25 +0300 Subject: [PATCH 04/10] refactor: extract more common logic for extension and watchapp --- lib/constants.ts | 2 + lib/services/ios-extensions-service.ts | 27 ++----- .../ios-native-target-service-base.ts | 45 +++++++++++ lib/services/ios-watch-app-service.ts | 81 ++++++++++--------- 4 files changed, 96 insertions(+), 59 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index a1a8961018..38713eb2d9 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -49,6 +49,8 @@ export const TNS_NATIVE_SOURCE_GROUP_NAME = "TNSNativeSource"; export const NATIVE_SOURCE_FOLDER = "src"; export const APPLICATION_RESPONSE_TIMEOUT_SECONDS = 60; export const NATIVE_EXTENSION_FOLDER = "extensions"; +export const IOS_WATCHAPP_FOLDER = "watchapp"; +export const IOS_WATCHAPP_EXTENSION_FOLDER = "watchextension"; export class PackageVersion { static NEXT = "next"; diff --git a/lib/services/ios-extensions-service.ts b/lib/services/ios-extensions-service.ts index bd8daa362d..b92475f712 100644 --- a/lib/services/ios-extensions-service.ts +++ b/lib/services/ios-extensions-service.ts @@ -16,13 +16,7 @@ export class IOSExtensionsService extends NativeTargetServiceBase implements IIO } const project = new this.$xcode.project(pbxProjPath); project.parseSync(); - this.$fs.readDirectory(extensionsFolderPath) - .filter(fileName => { - const filePath = path.join(extensionsFolderPath, fileName); - const stats = this.$fs.getFsStats(filePath); - - return stats.isDirectory() && !fileName.startsWith("."); - }) + this.getTargetDirectories(extensionsFolderPath) .forEach(extensionFolder => { const target = this.addTargetToProject(extensionsFolderPath, extensionFolder, 'app_extension', project, platformData); this.configureTarget(extensionFolder, path.join(extensionsFolderPath, extensionFolder), target, project, projectData); @@ -38,21 +32,12 @@ export class IOSExtensionsService extends NativeTargetServiceBase implements IIO private configureTarget(extensionName: string, extensionPath: string, target: IXcode.target, project: IXcode.project, projectData: IProjectData) { const extJsonPath = path.join(extensionPath, "extension.json"); - if (this.$fs.exists(extJsonPath)) { - const extensionJson = this.$fs.readJson(extJsonPath); - _.forEach(extensionJson.frameworks, framework => { - project.addFramework( - framework, - { target: target.uuid } - ); - }); - if (extensionJson.assetcatalogCompilerAppiconName) { - project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", extensionJson.assetcatalogCompilerAppiconName, target.uuid); - } - } + this.setConfigurationsFromJsonFile(extJsonPath, target.uuid, project); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionName}`, "Debug", extensionName); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", `${projectData.projectIdentifiers.ios}.${extensionName}`, "Release", extensionName); + this.setXcodeTargetBuildConfigurationProperties( + [{name: "PRODUCT_BUNDLE_IDENTIFIER", value: `${projectData.projectIdentifiers.ios}.${extensionName}`}], + extensionName, + project); } public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { diff --git a/lib/services/ios-native-target-service-base.ts b/lib/services/ios-native-target-service-base.ts index 48d1d94779..8fbe505924 100644 --- a/lib/services/ios-native-target-service-base.ts +++ b/lib/services/ios-native-target-service-base.ts @@ -1,5 +1,16 @@ import * as path from "path"; +export enum BuildNames { + debug = "Debug", + release = "Release" +} + +export interface IXcodeTargetBuildConfigurationProperty { + name: string; + value: any; + buildNames?: BuildNames[]; +} + export abstract class NativeTargetServiceBase implements IIOSNativeTargetServiceBase { constructor(protected $fs: IFileSystem, protected $pbxprojDomXcode: IPbxprojDomXcode, @@ -40,4 +51,38 @@ export abstract class NativeTargetServiceBase implements IIOSNativeTargetService } xcode.save(); } + + protected getTargetDirectories(folderPath: string): string[] { + return this.$fs.readDirectory(folderPath) + .filter(fileName => { + const filePath = path.join(folderPath, fileName); + const stats = this.$fs.getFsStats(filePath); + + return stats.isDirectory() && !fileName.startsWith("."); + }); + } + + protected setXcodeTargetBuildConfigurationProperties(properties: IXcodeTargetBuildConfigurationProperty[], targetName: string, project: IXcode.project): void { + properties.forEach(property => { + const buildNames = property.buildNames || [BuildNames.debug, BuildNames.release]; + buildNames.forEach((buildName) => { + project.addBuildProperty(property.name, property.value, buildName, targetName); + }); + }); + } + + protected setConfigurationsFromJsonFile(jsonPath: string, targetUuid: string, project: IXcode.project) { + if (this.$fs.exists(jsonPath)) { + const configurationJson = this.$fs.readJson(jsonPath) || {}; + _.forEach(configurationJson.frameworks, framework => { + project.addFramework( + framework, + { target: targetUuid } + ); + }); + if (configurationJson.assetcatalogCompilerAppiconName) { + project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", configurationJson.assetcatalogCompilerAppiconName, targetUuid); + } + } + } } diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 54d8d15374..095ac2c105 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -10,59 +10,45 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW public async addWatchAppFromPath({watchAppFolderPath, projectData, platformData, pbxProjPath}: IAddWatchAppFromPathOptions): Promise { const targetUuids: string[] = []; - let addedExtensions = false; + if (!this.$fs.exists(watchAppFolderPath)) { return false; } - const project = new this.$xcode.project(pbxProjPath); - const appPath = path.join(watchAppFolderPath, "watchapp"); - const extensionPath = path.join(watchAppFolderPath, "watchextension"); - project.parseSync(); - const appFolder = this.$fs.readDirectory(appPath) - .filter(fileName => { - const filePath = path.join(appPath, fileName); - const stats = this.$fs.getFsStats(filePath); - return stats.isDirectory() && !fileName.startsWith("."); - })[0]; + const appPath = path.join(watchAppFolderPath, "watchapp"); + const appFolder = this.getTargetDirectories(appPath)[0]; - const extensionFolder = this.$fs.readDirectory(extensionPath) - .filter(fileName => { - const filePath = path.join(extensionPath, fileName); - const stats = this.$fs.getFsStats(filePath); + const extensionPath = path.join(watchAppFolderPath, "watchextension"); + const extensionFolder = this.getTargetDirectories(extensionPath)[0]; - return stats.isDirectory() && !fileName.startsWith("."); - })[0]; + const project = new this.$xcode.project(pbxProjPath); + project.parseSync(); const watchApptarget = this.addTargetToProject(appPath, appFolder, "watch_app", project, platformData, project.getFirstTarget().uuid); - this.configureTarget(appFolder, path.join(appPath, appFolder), `${projectData.projectIdentifiers.ios}.watchkitapp`, watchApptarget, project); + this.configureTarget( + appFolder, + path.join(appPath, appFolder), + `${projectData.projectIdentifiers.ios}.watchkitapp`, + "watchapp.json", + watchApptarget, + project + ); targetUuids.push(watchApptarget.uuid); + const watchExtensionTarget = this.addTargetToProject(extensionPath, extensionFolder, "watch_extension", project, platformData, watchApptarget.uuid); - this.configureTarget(extensionFolder, path.join(extensionPath, extensionFolder), `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, watchExtensionTarget, project); + this.configureTarget( + extensionFolder, + path.join(extensionPath, extensionFolder), + `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, + "extension.json", + watchExtensionTarget, + project); targetUuids.push(watchExtensionTarget.uuid); - addedExtensions = true; this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); this.prepareSigning(targetUuids, projectData, pbxProjPath); - return addedExtensions; - } - - private configureTarget(targetName: string, targetPath: string, identifier: string, target: IXcode.target, project: IXcode.project) { - const identifierParts = identifier.split("."); - identifierParts.pop(); - const wkAppBundleIdentifier = identifierParts.join("."); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Debug", targetName); - project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Release", targetName); - project.addBuildProperty("SDKROOT", "watchos", "Debug", targetName); - project.addBuildProperty("SDKROOT", "watchos", "Release", targetName); - project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Debug", targetName); - project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Release", targetName); - project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Debug", targetName); - project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Release", targetName); - project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Debug", targetName); - project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Release", targetName); - project.addToHeaderSearchPaths(targetPath, target.pbxNativeTarget.productName); + return true; } public removeWatchApp({pbxProjPath}: IRemoveWatchAppOptions): void { @@ -72,6 +58,25 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW project.removeTargetsByProductType("com.apple.product-type.watchkit2-extension"); this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); } + + private configureTarget(targetName: string, targetPath: string, identifier: string, configurationFileName: string, target: IXcode.target, project: IXcode.project) { + const targetConfigurationJsonPath = path.join(targetPath, configurationFileName); + this.setConfigurationsFromJsonFile(targetConfigurationJsonPath, target.uuid, project); + + const identifierParts = identifier.split("."); + identifierParts.pop(); + const wkAppBundleIdentifier = identifierParts.join("."); + + this.setXcodeTargetBuildConfigurationProperties([ + {name: "PRODUCT_BUNDLE_IDENTIFIER", value: identifier}, + {name: "SDKROOT", value: "watchos"}, + {name: "TARGETED_DEVICE_FAMILY", value: 4}, + {name: "WATCHOS_DEPLOYMENT_TARGET", value: 4.1}, + {name: "WK_APP_BUNDLE_IDENTIFIER", value: wkAppBundleIdentifier} + ], targetName, project); + + project.addToHeaderSearchPaths(targetPath, target.pbxNativeTarget.productName); + } } $injector.register("iOSWatchAppService", IOSWatchAppService); From 1723a67ac9977c2aaec0a4aea3bf6787bb8a6c43 Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Wed, 24 Apr 2019 20:03:26 +0300 Subject: [PATCH 05/10] refactor: extract some constants --- lib/constants.ts | 17 +++++++++++++++++ lib/services/ios-extensions-service.ts | 5 +++-- lib/services/ios-project-service.ts | 24 ++++++++++++++++++------ lib/services/ios-watch-app-service.ts | 23 +++++++++++++---------- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index 38713eb2d9..7443a4632a 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -282,3 +282,20 @@ export const LiveSyncEvents = { liveSyncStarted: "liveSyncStarted", liveSyncNotification: "notify" }; + +export enum IOSDeviceTargets { + ios = "1,2", + watchos = 4 +} + +export enum IOSNativeTargetProductTypes { + watchApp = "com.apple.product-type.application.watchapp2", + watchExtension = "com.apple.product-type.watchkit2-extension", + appExtension = "com.apple.product-type.app-extension" +} + +export enum IOSNativeTargetTypes { + watchApp = "watch_app", + watchExtension = "watch_extension", + appExtension = "app_extension" +} diff --git a/lib/services/ios-extensions-service.ts b/lib/services/ios-extensions-service.ts index b92475f712..3e55c184db 100644 --- a/lib/services/ios-extensions-service.ts +++ b/lib/services/ios-extensions-service.ts @@ -1,5 +1,6 @@ import * as path from "path"; import { NativeTargetServiceBase } from "./ios-native-target-service-base"; +import { IOSNativeTargetProductTypes, IOSNativeTargetTypes } from "../constants"; export class IOSExtensionsService extends NativeTargetServiceBase implements IIOSExtensionsService { constructor(protected $fs: IFileSystem, @@ -18,7 +19,7 @@ export class IOSExtensionsService extends NativeTargetServiceBase implements IIO project.parseSync(); this.getTargetDirectories(extensionsFolderPath) .forEach(extensionFolder => { - const target = this.addTargetToProject(extensionsFolderPath, extensionFolder, 'app_extension', project, platformData); + const target = this.addTargetToProject(extensionsFolderPath, extensionFolder, IOSNativeTargetTypes.appExtension, project, platformData); this.configureTarget(extensionFolder, path.join(extensionsFolderPath, extensionFolder), target, project, projectData); targetUuids.push(target.uuid); addedExtensions = true; @@ -43,7 +44,7 @@ export class IOSExtensionsService extends NativeTargetServiceBase implements IIO public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { const project = new this.$xcode.project(pbxProjPath); project.parseSync(); - project.removeTargetsByProductType("com.apple.product-type.app-extension"); + project.removeTargetsByProductType(IOSNativeTargetProductTypes.appExtension); this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); } } diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index b7be03e2ac..3ba70d90b3 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -13,7 +13,7 @@ import * as plist from "plist"; import { IOSProvisionService } from "./ios-provision-service"; import { IOSEntitlementsService } from "./ios-entitlements-service"; import * as mobileProvisionFinder from "ios-mobileprovision-finder"; -import { BUILD_XCCONFIG_FILE_NAME, IosProjectConstants } from "../constants"; +import { BUILD_XCCONFIG_FILE_NAME, IosProjectConstants, IOSNativeTargetProductTypes } from "../constants"; interface INativeSourceCodeGroup { name: string; @@ -513,9 +513,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ } xcode.setAutomaticSigningStyle(projectData.projectName, teamId); - xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.app-extension", teamId); - xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.watchkit2-extension", teamId); - xcode.setAutomaticSigningStyleByTargetProductType("com.apple.product-type.application.watchapp2", teamId); + xcode.setAutomaticSigningStyleByTargetProductTypesList([ + IOSNativeTargetProductTypes.appExtension, + IOSNativeTargetProductTypes.watchApp, + IOSNativeTargetProductTypes.watchExtension + ], + teamId); xcode.save(); this.$logger.trace(`Set Automatic signing style and team id ${teamId}.`); @@ -557,7 +560,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ identity: mobileprovision.Type === "Development" ? "iPhone Developer" : "iPhone Distribution" }; xcode.setManualSigningStyle(projectData.projectName, configuration); - xcode.setManualSigningStyleByTargetProductType("com.apple.product-type.app-extension", configuration); + xcode.setManualSigningStyleByTargetProductTypesList([ + IOSNativeTargetProductTypes.appExtension, + IOSNativeTargetProductTypes.watchApp, + IOSNativeTargetProductTypes.watchExtension + ], + configuration); xcode.save(); // this.cache(uuid); @@ -813,7 +821,11 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f ); await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); this.$iOSWatchAppService.removeWatchApp({ pbxProjPath }); - await this.$iOSWatchAppService.addWatchAppFromPath({ watchAppFolderPath: path.join(resourcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); + const addedWatchApp = await this.$iOSWatchAppService.addWatchAppFromPath({ watchAppFolderPath: path.join(resourcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); + + if (addedWatchApp) { + this.$logger.warn("The support for Apple Watch App is currently in Beta. For more information about the current development state and any known issues, please check the relevant GitHub issue: ISSUE LINK"); + } } diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 095ac2c105..8d679302d9 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -1,7 +1,10 @@ import * as path from "path"; import { NativeTargetServiceBase } from "./ios-native-target-service-base"; +import { IOSDeviceTargets, IOS_WATCHAPP_FOLDER, IOS_WATCHAPP_EXTENSION_FOLDER, IOSNativeTargetProductTypes, IOSNativeTargetTypes } from "../constants"; export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSWatchAppService { + private static WATCH_APP_IDENTIFIER = "watchkitapp"; + private static WACTCH_EXTENSION_IDENTIFIER = "watchkitextension"; constructor(protected $fs: IFileSystem, protected $pbxprojDomXcode: IPbxprojDomXcode, protected $xcode: IXcode) { @@ -15,31 +18,31 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW return false; } - const appPath = path.join(watchAppFolderPath, "watchapp"); + const appPath = path.join(watchAppFolderPath, IOS_WATCHAPP_FOLDER); const appFolder = this.getTargetDirectories(appPath)[0]; - const extensionPath = path.join(watchAppFolderPath, "watchextension"); + const extensionPath = path.join(watchAppFolderPath, IOS_WATCHAPP_EXTENSION_FOLDER); const extensionFolder = this.getTargetDirectories(extensionPath)[0]; const project = new this.$xcode.project(pbxProjPath); project.parseSync(); - const watchApptarget = this.addTargetToProject(appPath, appFolder, "watch_app", project, platformData, project.getFirstTarget().uuid); + const watchApptarget = this.addTargetToProject(appPath, appFolder, IOSNativeTargetTypes.watchApp, project, platformData, project.getFirstTarget().uuid); this.configureTarget( appFolder, path.join(appPath, appFolder), - `${projectData.projectIdentifiers.ios}.watchkitapp`, + `${projectData.projectIdentifiers.ios}.${IOSWatchAppService.WATCH_APP_IDENTIFIER}`, "watchapp.json", watchApptarget, project ); targetUuids.push(watchApptarget.uuid); - const watchExtensionTarget = this.addTargetToProject(extensionPath, extensionFolder, "watch_extension", project, platformData, watchApptarget.uuid); + const watchExtensionTarget = this.addTargetToProject(extensionPath, extensionFolder, IOSNativeTargetTypes.watchExtension, project, platformData, watchApptarget.uuid); this.configureTarget( extensionFolder, path.join(extensionPath, extensionFolder), - `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, + `${projectData.projectIdentifiers.ios}.${IOSWatchAppService.WATCH_APP_IDENTIFIER}.${IOSWatchAppService.WACTCH_EXTENSION_IDENTIFIER}`, "extension.json", watchExtensionTarget, project); @@ -54,8 +57,8 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW public removeWatchApp({pbxProjPath}: IRemoveWatchAppOptions): void { const project = new this.$xcode.project(pbxProjPath); project.parseSync(); - project.removeTargetsByProductType("com.apple.product-type.application.watchapp2"); - project.removeTargetsByProductType("com.apple.product-type.watchkit2-extension"); + project.removeTargetsByProductType(IOSNativeTargetProductTypes.watchApp); + project.removeTargetsByProductType(IOSNativeTargetProductTypes.watchExtension); this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); } @@ -70,8 +73,8 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW this.setXcodeTargetBuildConfigurationProperties([ {name: "PRODUCT_BUNDLE_IDENTIFIER", value: identifier}, {name: "SDKROOT", value: "watchos"}, - {name: "TARGETED_DEVICE_FAMILY", value: 4}, - {name: "WATCHOS_DEPLOYMENT_TARGET", value: 4.1}, + {name: "TARGETED_DEVICE_FAMILY", value: IOSDeviceTargets.watchos}, + {name: "WATCHOS_DEPLOYMENT_TARGET", value: 4.1}, //TODO consider WATCHOS_DEPLOYMENT_TARGET in json configuration {name: "WK_APP_BUNDLE_IDENTIFIER", value: wkAppBundleIdentifier} ], targetName, project); From ac311ecaac4f552dfd6298e8240f7b1240409e6a Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 25 Apr 2019 17:21:21 +0300 Subject: [PATCH 06/10] chore: update pbxproj libraries --- npm-shrinkwrap.json | 11 +++++------ package.json | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 2c6008a7fe..46a9da7799 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -5316,9 +5316,8 @@ } }, "nativescript-dev-xcode": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/nativescript-dev-xcode/-/nativescript-dev-xcode-0.1.0.tgz", - "integrity": "sha512-auQd2/qVdOwD/8v+rHKLflYE8jpT4o1wMwtEFkFGp7sewLkBQz7y9pH79oNM7ztyw0gnL/cFAhLT/ViGLWdw6w==", + "version": "https://github.com/NativeScript/nativescript-dev-xcode/tarball/ec70f5d6032a72b65298ad56fa6ec0c4b2ef03a3", + "integrity": "sha512-CIZGo20Mulu/0u5Im6MYfh/gt2jldK3zt/HtWjUBogV/0QVQNKry2ewC6BudpjetUw4otjmqTRlUhY6wXpZ9Bg==", "requires": { "simple-plist": "^1.0.0", "uuid": "^3.3.2" @@ -6066,9 +6065,9 @@ "dev": true }, "pbxproj-dom": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pbxproj-dom/-/pbxproj-dom-1.1.0.tgz", - "integrity": "sha512-ti2ZuXEptfYbkkUweP6sBtLBlRjTcWkxWG450lbJ+PwNMk8nvhhAtV7lIuQPHR29h7hPUHOIvUBAIljIx8ygxg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pbxproj-dom/-/pbxproj-dom-1.2.0.tgz", + "integrity": "sha512-K2czrWqA68AR0q1UXz5EBi/zoxcljrkO4RSJX0jPnVn3iyE0HYnYOzaEEDYMpueczkT/Vtdm3SCc3NM+12kMaQ==" }, "pend": { "version": "1.2.0", diff --git a/package.json b/package.json index ad975a9576..4ea1444a73 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "minimatch": "3.0.2", "mkdirp": "0.5.1", "mute-stream": "0.0.5", - "nativescript-dev-xcode": "0.1.0", + "nativescript-dev-xcode": "https://github.com/NativeScript/nativescript-dev-xcode/tarball/ec70f5d6032a72b65298ad56fa6ec0c4b2ef03a3", "nativescript-doctor": "1.9.2", "nativescript-preview-sdk": "0.3.4", "open": "0.0.5", @@ -64,7 +64,7 @@ "osenv": "0.1.3", "pacote": "8.1.6", "pako": "1.0.6", - "pbxproj-dom": "1.1.0", + "pbxproj-dom": "1.2.0", "plist": "1.1.0", "plist-merge-patch": "0.1.1", "proper-lockfile": "3.2.0", From 4b69bb3d949ff610ba665d5515c1d13a91e47796 Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 25 Apr 2019 18:03:13 +0300 Subject: [PATCH 07/10] fix: no way to control watchos deployment target --- lib/services/ios-extensions-service.ts | 3 ++- lib/services/ios-native-target-service-base.ts | 12 ++++++++++-- lib/services/ios-watch-app-service.ts | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/services/ios-extensions-service.ts b/lib/services/ios-extensions-service.ts index 3e55c184db..fc83e100cf 100644 --- a/lib/services/ios-extensions-service.ts +++ b/lib/services/ios-extensions-service.ts @@ -33,12 +33,13 @@ export class IOSExtensionsService extends NativeTargetServiceBase implements IIO private configureTarget(extensionName: string, extensionPath: string, target: IXcode.target, project: IXcode.project, projectData: IProjectData) { const extJsonPath = path.join(extensionPath, "extension.json"); - this.setConfigurationsFromJsonFile(extJsonPath, target.uuid, project); this.setXcodeTargetBuildConfigurationProperties( [{name: "PRODUCT_BUNDLE_IDENTIFIER", value: `${projectData.projectIdentifiers.ios}.${extensionName}`}], extensionName, project); + + this.setConfigurationsFromJsonFile(extJsonPath, target.uuid, extensionName, project); } public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { diff --git a/lib/services/ios-native-target-service-base.ts b/lib/services/ios-native-target-service-base.ts index 8fbe505924..d409adcfaf 100644 --- a/lib/services/ios-native-target-service-base.ts +++ b/lib/services/ios-native-target-service-base.ts @@ -71,17 +71,25 @@ export abstract class NativeTargetServiceBase implements IIOSNativeTargetService }); } - protected setConfigurationsFromJsonFile(jsonPath: string, targetUuid: string, project: IXcode.project) { + protected setConfigurationsFromJsonFile(jsonPath: string, targetUuid: string, targetName: string, project: IXcode.project) { if (this.$fs.exists(jsonPath)) { const configurationJson = this.$fs.readJson(jsonPath) || {}; + _.forEach(configurationJson.frameworks, framework => { project.addFramework( framework, { target: targetUuid } ); }); + if (configurationJson.assetcatalogCompilerAppiconName) { - project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", configurationJson.assetcatalogCompilerAppiconName, targetUuid); + project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", configurationJson.assetcatalogCompilerAppiconName, targetUuid); + } + + if (configurationJson.targetBuildConfigurationProperties) { + const properties: IXcodeTargetBuildConfigurationProperty[] = []; + _.forEach(configurationJson.targetBuildConfigurationProperties, (value, name: string) => properties.push({value, name})); + this.setXcodeTargetBuildConfigurationProperties(properties, targetName, project); } } } diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 8d679302d9..0a3bbbe8d3 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -64,7 +64,6 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW private configureTarget(targetName: string, targetPath: string, identifier: string, configurationFileName: string, target: IXcode.target, project: IXcode.project) { const targetConfigurationJsonPath = path.join(targetPath, configurationFileName); - this.setConfigurationsFromJsonFile(targetConfigurationJsonPath, target.uuid, project); const identifierParts = identifier.split("."); identifierParts.pop(); @@ -74,10 +73,11 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW {name: "PRODUCT_BUNDLE_IDENTIFIER", value: identifier}, {name: "SDKROOT", value: "watchos"}, {name: "TARGETED_DEVICE_FAMILY", value: IOSDeviceTargets.watchos}, - {name: "WATCHOS_DEPLOYMENT_TARGET", value: 4.1}, //TODO consider WATCHOS_DEPLOYMENT_TARGET in json configuration + {name: "WATCHOS_DEPLOYMENT_TARGET", value: 5.2}, {name: "WK_APP_BUNDLE_IDENTIFIER", value: wkAppBundleIdentifier} ], targetName, project); + this.setConfigurationsFromJsonFile(targetConfigurationJsonPath, target.uuid, targetName, project); project.addToHeaderSearchPaths(targetPath, target.pbxNativeTarget.productName); } } From be2ee2ae20ff503f60d43c65776197995195ae7f Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 25 Apr 2019 18:27:27 +0300 Subject: [PATCH 08/10] chore: remove unnecessary code --- lib/common/definitions/mobile.d.ts | 4 ---- lib/common/mobile/ios/simulator/ios-simulator-device.ts | 1 - lib/definitions/project.d.ts | 3 --- lib/services/ios-native-target-service-base.ts | 2 +- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/common/definitions/mobile.d.ts b/lib/common/definitions/mobile.d.ts index 229c23a939..1ce531beef 100644 --- a/lib/common/definitions/mobile.d.ts +++ b/lib/common/definitions/mobile.d.ts @@ -81,10 +81,6 @@ declare module Mobile { imageIdentifier?: string; } - interface IIOSWatchSimulatorDevice extends IDeviceInfo{ - - } - interface IDeviceError extends Error, IDeviceIdentifier { } interface IDeviceIdentifier { diff --git a/lib/common/mobile/ios/simulator/ios-simulator-device.ts b/lib/common/mobile/ios/simulator/ios-simulator-device.ts index 489712a140..50a178d4f3 100644 --- a/lib/common/mobile/ios/simulator/ios-simulator-device.ts +++ b/lib/common/mobile/ios/simulator/ios-simulator-device.ts @@ -10,7 +10,6 @@ export class IOSSimulator extends IOSDeviceBase implements Mobile.IiOSDevice { public applicationManager: Mobile.IDeviceApplicationManager; public fileSystem: Mobile.IDeviceFileSystem; public deviceInfo: Mobile.IDeviceInfo; - public watchSimulator: Mobile.IIOSWatchSimulatorDevice; constructor(private simulator: Mobile.IiSimDevice, private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants, diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index e5d4254a94..1b52116980 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -592,9 +592,6 @@ interface IIOSExtensionsService { removeExtensions(options: IRemoveExtensionsOptions): void; } -interface IIOSNativeTargetServiceBase { -} - /** * Describes a service used to add and remove iOS extension */ diff --git a/lib/services/ios-native-target-service-base.ts b/lib/services/ios-native-target-service-base.ts index d409adcfaf..5f203d405b 100644 --- a/lib/services/ios-native-target-service-base.ts +++ b/lib/services/ios-native-target-service-base.ts @@ -11,7 +11,7 @@ export interface IXcodeTargetBuildConfigurationProperty { buildNames?: BuildNames[]; } -export abstract class NativeTargetServiceBase implements IIOSNativeTargetServiceBase { +export abstract class NativeTargetServiceBase { constructor(protected $fs: IFileSystem, protected $pbxprojDomXcode: IPbxprojDomXcode, protected $xcode: IXcode) { From 2e5a7e9caf32fc0ff1ac00274b1929c14d83a2ed Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 25 Apr 2019 19:30:24 +0300 Subject: [PATCH 09/10] chore: fix tests --- lib/services/ios-project-service.ts | 17 +++++++++-------- test/ios-project-service.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 3ba70d90b3..e2a4d85b96 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -773,6 +773,8 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f public async prepareProject(projectData: IProjectData, platformSpecificData: IPlatformSpecificData): Promise { const projectRoot = path.join(projectData.platformsDir, "ios"); + const platformData = this.getPlatformData(projectData); + const resourcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); const provision = platformSpecificData && platformSpecificData.provision; const teamId = platformSpecificData && platformSpecificData.teamId; @@ -809,17 +811,16 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f _.each(imagesToRemove, image => project.removeResourceFile(path.join(this.getAppResourcesDestinationDirectoryPath(projectData), image))); this.savePbxProj(project, projectData); + + const resourcesNativeCodePath = path.join( + resourcesDirectoryPath, + platformData.normalizedPlatformName, + constants.NATIVE_SOURCE_FOLDER + ); + await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); } - const platformData = this.getPlatformData(projectData); - const resourcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); const pbxProjPath = this.getPbxProjPath(projectData); - const resourcesNativeCodePath = path.join( - resourcesDirectoryPath, - platformData.normalizedPlatformName, - constants.NATIVE_SOURCE_FOLDER - ); - await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, resourcesNativeCodePath, projectData); this.$iOSWatchAppService.removeWatchApp({ pbxProjPath }); const addedWatchApp = await this.$iOSWatchAppService.addWatchAppFromPath({ watchAppFolderPath: path.join(resourcesDirectoryPath, platformData.normalizedPlatformName), projectData, platformData, pbxProjPath }); diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index d01f8df6c0..71c1fd3061 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -159,6 +159,10 @@ function createTestInjector(projectPath: string, projectName: string, xCode?: IX removeExtensions: () => { /* */ }, addExtensionsFromPath: () => Promise.resolve() }); + testInjector.register("iOSWatchAppService", { + removeWatchApp: () => { /* */ }, + addWatchAppFromPath: () => Promise.resolve() + }); return testInjector; } @@ -1064,6 +1068,7 @@ describe("iOS Project Service Signing", () => { stack.push({ targetName, manualSigning }); }, setManualSigningStyleByTargetProductType: () => ({}), + setManualSigningStyleByTargetProductTypesList: () => ({}), setManualSigningStyleByTargetKey: () => ({}) }; }; @@ -1085,6 +1090,7 @@ describe("iOS Project Service Signing", () => { stack.push({ targetName, manualSigning }); }, setManualSigningStyleByTargetProductType: () => ({}), + setManualSigningStyleByTargetProductTypesList: () => ({}), setManualSigningStyleByTargetKey: () => ({}) }; }; @@ -1106,6 +1112,7 @@ describe("iOS Project Service Signing", () => { stack.push({ targetName, manualSigning }); }, setManualSigningStyleByTargetProductType: () => ({}), + setManualSigningStyleByTargetProductTypesList: () => ({}), setManualSigningStyleByTargetKey: () => ({}) }; }; @@ -1296,6 +1303,7 @@ describe("buildProject", () => { getSigning: () => ({}), setAutomaticSigningStyle: () => ({}), setAutomaticSigningStyleByTargetProductType: () => ({}), + setAutomaticSigningStyleByTargetProductTypesList: () => ({}), setAutomaticSigningStyleByTargetKey: () => ({}), save: () => ({}) }) From 74ace6bba7c2815bab61d176c0c59c64a61f2425 Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Thu, 25 Apr 2019 20:28:21 +0300 Subject: [PATCH 10/10] fix: wrong check for watchapp folder --- lib/services/ios-watch-app-service.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 0a3bbbe8d3..dae287e9fb 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -13,15 +13,14 @@ export class IOSWatchAppService extends NativeTargetServiceBase implements IIOSW public async addWatchAppFromPath({watchAppFolderPath, projectData, platformData, pbxProjPath}: IAddWatchAppFromPathOptions): Promise { const targetUuids: string[] = []; + const appPath = path.join(watchAppFolderPath, IOS_WATCHAPP_FOLDER); + const extensionPath = path.join(watchAppFolderPath, IOS_WATCHAPP_EXTENSION_FOLDER); - if (!this.$fs.exists(watchAppFolderPath)) { + if (!this.$fs.exists(appPath) || !this.$fs.exists(extensionPath)) { return false; } - const appPath = path.join(watchAppFolderPath, IOS_WATCHAPP_FOLDER); const appFolder = this.getTargetDirectories(appPath)[0]; - - const extensionPath = path.join(watchAppFolderPath, IOS_WATCHAPP_EXTENSION_FOLDER); const extensionFolder = this.getTargetDirectories(extensionPath)[0]; const project = new this.$xcode.project(pbxProjPath);