|
| 1 | +import * as path from "path"; |
| 2 | + |
| 3 | +export class IOSWatchAppService implements IIOSExtensionsService { |
| 4 | + constructor(private $fs: IFileSystem, |
| 5 | + private $pbxprojDomXcode: IPbxprojDomXcode, |
| 6 | + private $xcode: IXcode) { |
| 7 | + } |
| 8 | + |
| 9 | + public async addExtensionsFromPath({extensionsFolderPath, projectData, platformData, pbxProjPath}: IAddExtensionsFromPathOptions): Promise<boolean> { |
| 10 | + const targetUuids: string[] = []; |
| 11 | + let addedExtensions = false; |
| 12 | + if (!this.$fs.exists(extensionsFolderPath)) { |
| 13 | + return false; |
| 14 | + } |
| 15 | + const project = new this.$xcode.project(pbxProjPath); |
| 16 | + const appPath = path.join(extensionsFolderPath, "watchapp"); |
| 17 | + const extensionPath = path.join(extensionsFolderPath, "watchextension"); |
| 18 | + project.parseSync(); |
| 19 | + const appFolder = this.$fs.readDirectory(appPath) |
| 20 | + .filter(fileName => { |
| 21 | + const filePath = path.join(appPath, fileName); |
| 22 | + const stats = this.$fs.getFsStats(filePath); |
| 23 | + |
| 24 | + return stats.isDirectory() && !fileName.startsWith("."); |
| 25 | + })[0]; |
| 26 | + |
| 27 | + const extensionFolder = this.$fs.readDirectory(extensionPath) |
| 28 | + .filter(fileName => { |
| 29 | + const filePath = path.join(extensionPath, fileName); |
| 30 | + const stats = this.$fs.getFsStats(filePath); |
| 31 | + |
| 32 | + return stats.isDirectory() && !fileName.startsWith("."); |
| 33 | + })[0]; |
| 34 | + |
| 35 | + let targetUuid = this.addExtensionToProject(appPath, appFolder, project, projectData, platformData, "watch_app", `${projectData.projectIdentifiers.ios}.watchkitapp`, project.getFirstTarget().uuid); |
| 36 | + targetUuids.push(targetUuid); |
| 37 | + targetUuid = this.addExtensionToProject(extensionPath, extensionFolder, project, projectData, platformData, "watch_extension", `${projectData.projectIdentifiers.ios}.watchkitapp.watchkitextension`, targetUuid); |
| 38 | + targetUuids.push(targetUuid); |
| 39 | + addedExtensions = true; |
| 40 | + |
| 41 | + this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); |
| 42 | + this.prepareExtensionSigning(targetUuids, projectData, pbxProjPath); |
| 43 | + |
| 44 | + return addedExtensions; |
| 45 | + } |
| 46 | + |
| 47 | + private addExtensionToProject(extensionsFolderPath: string, extensionFolder: string, project: IXcode.project, projectData: IProjectData, platformData: IPlatformData, targetType: string, identifier: string, parentTarget: string): string { |
| 48 | + const extensionPath = path.join(extensionsFolderPath, extensionFolder); |
| 49 | + const extensionRelativePath = path.relative(platformData.projectRoot, extensionPath); |
| 50 | + const files = this.$fs.readDirectory(extensionPath) |
| 51 | + .filter(filePath => !filePath.startsWith(".")) |
| 52 | + .map(filePath => path.join(extensionPath, filePath)); |
| 53 | + const target = project.addTarget(extensionFolder, targetType, extensionRelativePath, parentTarget); |
| 54 | + project.addBuildPhase([], 'PBXSourcesBuildPhase', 'Sources', target.uuid); |
| 55 | + project.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', target.uuid); |
| 56 | + project.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target.uuid); |
| 57 | + |
| 58 | + const extJsonPath = path.join(extensionsFolderPath, extensionFolder, "extension.json"); |
| 59 | + if (this.$fs.exists(extJsonPath)) { |
| 60 | + const extensionJson = this.$fs.readJson(extJsonPath); |
| 61 | + _.forEach(extensionJson.frameworks, framework => { |
| 62 | + project.addFramework( |
| 63 | + framework, |
| 64 | + { target: target.uuid } |
| 65 | + ); |
| 66 | + }); |
| 67 | + if (extensionJson.assetcatalogCompilerAppiconName) { |
| 68 | + project.addToBuildSettings("ASSETCATALOG_COMPILER_APPICON_NAME", extensionJson.assetcatalogCompilerAppiconName, target.uuid); |
| 69 | + } |
| 70 | + } |
| 71 | + const identifierParts = identifier.split("."); |
| 72 | + identifierParts.pop(); |
| 73 | + const wkAppBundleIdentifier = identifierParts.join("."); |
| 74 | + project.addPbxGroup(files, extensionFolder, extensionPath, null, { isMain: true, target: target.uuid, filesRelativeToProject: true }); |
| 75 | + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Debug", extensionFolder); |
| 76 | + project.addBuildProperty("PRODUCT_BUNDLE_IDENTIFIER", identifier, "Release", extensionFolder); |
| 77 | + project.addBuildProperty("SDKROOT", "watchos", "Debug", extensionFolder); |
| 78 | + project.addBuildProperty("SDKROOT", "watchos", "Release", extensionFolder); |
| 79 | + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Debug", extensionFolder); |
| 80 | + project.addBuildProperty("TARGETED_DEVICE_FAMILY", 4, "Release", extensionFolder); |
| 81 | + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Debug", extensionFolder); |
| 82 | + project.addBuildProperty("WATCHOS_DEPLOYMENT_TARGET", 4.1, "Release", extensionFolder); |
| 83 | + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Debug", extensionFolder); |
| 84 | + project.addBuildProperty("WK_APP_BUNDLE_IDENTIFIER", wkAppBundleIdentifier, "Release", extensionFolder); |
| 85 | + project.addToHeaderSearchPaths(extensionPath, target.pbxNativeTarget.productName); |
| 86 | + |
| 87 | + return target.uuid; |
| 88 | + } |
| 89 | + |
| 90 | + private prepareExtensionSigning(targetUuids: string[], projectData:IProjectData, projectPath: string) { |
| 91 | + const xcode = this.$pbxprojDomXcode.Xcode.open(projectPath); |
| 92 | + const signing = xcode.getSigning(projectData.projectName); |
| 93 | + if (signing !== undefined) { |
| 94 | + _.forEach(targetUuids, targetUuid => { |
| 95 | + if (signing.style === "Automatic") { |
| 96 | + xcode.setAutomaticSigningStyleByTargetKey(targetUuid, signing.team); |
| 97 | + } else { |
| 98 | + for (const config in signing.configurations) { |
| 99 | + const signingConfiguration = signing.configurations[config]; |
| 100 | + xcode.setManualSigningStyleByTargetKey(targetUuid, signingConfiguration); |
| 101 | + break; |
| 102 | + } |
| 103 | + } |
| 104 | + }); |
| 105 | + } |
| 106 | + xcode.save(); |
| 107 | + } |
| 108 | + |
| 109 | + public removeExtensions({pbxProjPath}: IRemoveExtensionsOptions): void { |
| 110 | + const project = new this.$xcode.project(pbxProjPath); |
| 111 | + project.parseSync(); |
| 112 | + project.removeTargetsByProductType("com.apple.product-type.app-extension"); |
| 113 | + this.$fs.writeFile(pbxProjPath, project.writeSync({omitEmptyValues: true})); |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +$injector.register("iOSWatchAppService", IOSWatchAppService); |
0 commit comments