@@ -12,6 +12,7 @@ import * as helpers from "../common/helpers";
1212import * as projectServiceBaseLib from "./platform-project-service-base" ;
1313import Future = require( "fibers/future" ) ;
1414import { PlistSession } from "plist-merge-patch" ;
15+ import { EOL } from "os" ;
1516
1617export class IOSProjectService extends projectServiceBaseLib . PlatformProjectServiceBase implements IPlatformProjectService {
1718 private static XCODE_PROJECT_EXT_NAME = ".xcodeproj" ;
@@ -41,8 +42,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
4142 private $mobileHelper : Mobile . IMobileHelper ,
4243 private $pluginVariablesService : IPluginVariablesService ,
4344 private $xcprojService : IXcprojService ) {
44- super ( $fs , $projectData , $projectDataService ) ;
45- }
45+ super ( $fs , $projectData , $projectDataService ) ;
46+ }
4647
4748 public get platformData ( ) : IPlatformData {
4849 let projectRoot = path . join ( this . $projectData . platformsDir , "ios" ) ;
@@ -67,7 +68,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
6768 frameworkDirectoriesNames : [ "Metadata" , "metadataGenerator" , "NativeScript" , "internal" ] ,
6869 targetedOS : [ 'darwin' ] ,
6970 configurationFileName : "Info.plist" ,
70- configurationFilePath : path . join ( projectRoot , this . $projectData . projectName , this . $projectData . projectName + "-Info.plist" ) ,
71+ configurationFilePath : path . join ( projectRoot , this . $projectData . projectName , this . $projectData . projectName + "-Info.plist" ) ,
7172 relativeToFrameworkConfigurationFilePath : path . join ( "__PROJECT_NAME__" , "__PROJECT_NAME__-Info.plist" ) ,
7273 fastLivesyncFileExtensions : [ ".tiff" , ".tif" , ".jpg" , "jpeg" , "gif" , ".png" , ".bmp" , ".BMPf" , ".ico" , ".cur" , ".xbm" ] // https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/
7374 } ;
@@ -77,7 +78,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
7778 return ( ( ) => {
7879 let frameworkVersion = this . getFrameworkVersion ( this . platformData . frameworkPackageName ) . wait ( ) ;
7980
80- if ( semver . lt ( frameworkVersion , "1.3.0" ) ) {
81+ if ( semver . lt ( frameworkVersion , "1.3.0" ) ) {
8182 return path . join ( this . platformData . projectRoot , this . $projectData . projectName , "Resources" , "icons" ) ;
8283 }
8384
@@ -89,17 +90,17 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
8990 return ( ( ) => {
9091 try {
9192 this . $childProcess . exec ( "which xcodebuild" ) . wait ( ) ;
92- } catch ( error ) {
93+ } catch ( error ) {
9394 this . $errors . fail ( "Xcode is not installed. Make sure you have Xcode installed and added to your PATH" ) ;
9495 }
9596
9697 let xcodeBuildVersion = this . $childProcess . exec ( "xcodebuild -version | head -n 1 | sed -e 's/Xcode //'" ) . wait ( ) ;
9798 let splitedXcodeBuildVersion = xcodeBuildVersion . split ( "." ) ;
98- if ( splitedXcodeBuildVersion . length === 3 ) {
99+ if ( splitedXcodeBuildVersion . length === 3 ) {
99100 xcodeBuildVersion = util . format ( "%s.%s" , splitedXcodeBuildVersion [ 0 ] , splitedXcodeBuildVersion [ 1 ] ) ;
100101 }
101102
102- if ( helpers . versionCompare ( xcodeBuildVersion , IOSProjectService . XCODEBUILD_MIN_VERSION ) < 0 ) {
103+ if ( helpers . versionCompare ( xcodeBuildVersion , IOSProjectService . XCODEBUILD_MIN_VERSION ) < 0 ) {
103104 this . $errors . fail ( "NativeScript can only run in Xcode version %s or greater" , IOSProjectService . XCODEBUILD_MIN_VERSION ) ;
104105 }
105106
@@ -109,13 +110,13 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
109110 public createProject ( frameworkDir : string , frameworkVersion : string , pathToTemplate ?: string ) : IFuture < void > {
110111 return ( ( ) => {
111112 this . $fs . ensureDirectoryExists ( path . join ( this . platformData . projectRoot , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ) . wait ( ) ;
112- if ( pathToTemplate ) {
113+ if ( pathToTemplate ) {
113114 // Copy everything except the template from the runtime
114115 this . $fs . readDirectory ( frameworkDir ) . wait ( )
115116 . filter ( dirName => dirName . indexOf ( IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) === - 1 )
116117 . forEach ( dirName => shell . cp ( "-R" , path . join ( frameworkDir , dirName ) , this . platformData . projectRoot ) ) ;
117118 shell . cp ( "-rf" , path . join ( pathToTemplate , "*" ) , this . platformData . projectRoot ) ;
118- } else if ( this . $options . symlink ) {
119+ } else if ( this . $options . symlink ) {
119120 let xcodeProjectName = util . format ( "%s.xcodeproj" , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ;
120121
121122 shell . cp ( "-R" , path . join ( frameworkDir , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER , "*" ) , path . join ( this . platformData . projectRoot , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ) ;
@@ -126,7 +127,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
126127 _ . each ( frameworkFiles , ( file : string ) => {
127128 this . $fs . symlink ( path . join ( frameworkDir , file ) , path . join ( this . platformData . projectRoot , file ) ) . wait ( ) ;
128129 } ) ;
129- } else {
130+ } else {
130131 shell . cp ( "-R" , path . join ( frameworkDir , "*" ) , this . platformData . projectRoot ) ;
131132 }
132133 } ) . future < void > ( ) ( ) ;
@@ -140,7 +141,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
140141 let projectRootFilePath = path . join ( this . platformData . projectRoot , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ;
141142 // Starting with NativeScript for iOS 1.6.0, the project Info.plist file resides not in the platform project,
142143 // but in the hello-world app template as a platform specific resource.
143- if ( this . $fs . exists ( path . join ( projectRootFilePath , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER + "-Info.plist" ) ) . wait ( ) ) {
144+ if ( this . $fs . exists ( path . join ( projectRootFilePath , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER + "-Info.plist" ) ) . wait ( ) ) {
144145 this . replaceFileName ( "-Info.plist" , projectRootFilePath ) . wait ( ) ;
145146 }
146147 this . replaceFileName ( "-Prefix.pch" , projectRootFilePath ) . wait ( ) ;
@@ -173,7 +174,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
173174 ] ;
174175
175176 let xcworkspacePath = path . join ( projectRoot , this . $projectData . projectName + ".xcworkspace" ) ;
176- if ( this . $fs . exists ( xcworkspacePath ) . wait ( ) ) {
177+ if ( this . $fs . exists ( xcworkspacePath ) . wait ( ) ) {
177178 basicArgs . push ( "-workspace" , xcworkspacePath ) ;
178179 basicArgs . push ( "-scheme" , this . $projectData . projectName ) ;
179180 } else {
@@ -219,7 +220,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
219220 args . push ( `PROVISIONING_PROFILE=${ buildConfig . mobileProvisionIdentifier } ` ) ;
220221 }
221222
222- this . $childProcess . spawnFromEvent ( "xcodebuild" , args , "exit" , { cwd : this . $options , stdio : 'inherit' } ) . wait ( ) ;
223+ this . $childProcess . spawnFromEvent ( "xcodebuild" , args , "exit" , { cwd : this . $options , stdio : 'inherit' } ) . wait ( ) ;
223224
224225 if ( buildForDevice ) {
225226 let buildOutputPath = path . join ( projectRoot , "build" , "device" ) ;
@@ -232,7 +233,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
232233 "-o" , path . join ( buildOutputPath , this . $projectData . projectName + ".ipa" )
233234 ] ;
234235
235- this . $childProcess . spawnFromEvent ( "xcrun" , xcrunArgs , "exit" , { cwd : this . $options , stdio : 'inherit' } ) . wait ( ) ;
236+ this . $childProcess . spawnFromEvent ( "xcrun" , xcrunArgs , "exit" , { cwd : this . $options , stdio : 'inherit' } ) . wait ( ) ;
236237 }
237238 } ) . future < void > ( ) ( ) ;
238239 }
@@ -257,7 +258,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
257258 architectures . push ( 'ONLY_ACTIVE_ARCH=NO' ) ;
258259 }
259260
260- buildConfig = buildConfig || { } ;
261+ buildConfig = buildConfig || { } ;
261262 buildConfig . architectures = architectures ;
262263
263264 return this . buildProject ( this . platformData . projectRoot , buildConfig ) ;
@@ -287,7 +288,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
287288
288289 let frameworkAddOptions : xcode . Options = { customFramework : true } ;
289290
290- if ( isDynamic ) {
291+ if ( isDynamic ) {
291292 frameworkAddOptions [ "embed" ] = true ;
292293 project . updateBuildProperty ( "IPHONEOS_DEPLOYMENT_TARGET" , "8.0" ) ;
293294 this . $logger . info ( "The iOS Deployment Target is now 8.0 in order to support Cocoa Touch Frameworks." ) ;
@@ -338,9 +339,9 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
338339
339340 public updatePlatform ( currentVersion : string , newVersion : string , canUpdate : boolean ) : IFuture < boolean > {
340341 return ( ( ) => {
341- if ( ! canUpdate ) {
342+ if ( ! canUpdate ) {
342343 let isUpdateConfirmed = this . $prompter . confirm ( `We need to override xcodeproj file. The old one will be saved at ${ this . $options . profileDir } . Are you sure?` , ( ) => true ) . wait ( ) ;
343- if ( isUpdateConfirmed ) {
344+ if ( isUpdateConfirmed ) {
344345 // Copy old file to options["profile-dir"]
345346 let sourceDir = this . xcodeprojPath ;
346347 let destinationDir = path . join ( this . $options . profileDir , "xcodeproj" ) ;
@@ -370,7 +371,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
370371 let project = this . createPbxProj ( ) ;
371372 let resources = project . pbxGroupByName ( "Resources" ) ;
372373
373- if ( resources ) {
374+ if ( resources ) {
374375 let references = project . pbxFileReferenceSection ( ) ;
375376
376377 let xcodeProjectImages = _ . map ( < any [ ] > resources . children , resource => this . replace ( references [ resource . value ] . name ) ) ;
@@ -430,7 +431,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
430431 this . $logger . trace ( "Info.plist: app/App_Resources/iOS/Info.plist is missing. Upgrading the source of the project with one from the new project template. Copy " + templateInfoPlist + " to " + infoPlistPath ) ;
431432 try {
432433 this . $fs . copyFile ( templateInfoPlist , infoPlistPath ) . wait ( ) ;
433- } catch ( e ) {
434+ } catch ( e ) {
434435 this . $logger . trace ( "Copying template's Info.plist failed. " + e ) ;
435436 }
436437 } else {
@@ -481,7 +482,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
481482 <plist version="1.0">
482483 <dict>
483484 <key>CFBundleIdentifier</key>
484- <string>${ this . $projectData . projectId } </string>
485+ <string>${ this . $projectData . projectId } </string>
485486 </dict>
486487 </plist>`
487488 } ) ;
@@ -516,8 +517,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
516517 }
517518
518519 private replace ( name : string ) : string {
519- if ( _ . startsWith ( name , '"' ) ) {
520- name = name . substr ( 1 , name . length - 2 ) ;
520+ if ( _ . startsWith ( name , '"' ) ) {
521+ name = name . substr ( 1 , name . length - 2 ) ;
521522 }
522523
523524 return name . replace ( / \\ \" / g, "\"" ) ;
@@ -541,7 +542,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
541542 }
542543
543544 private savePbxProj ( project : any ) : IFuture < void > {
544- return this . $fs . writeFile ( this . pbxProjPath , project . writeSync ( ) ) ;
545+ return this . $fs . writeFile ( this . pbxProjPath , project . writeSync ( ) ) ;
545546 }
546547
547548 public preparePluginNativeCode ( pluginData : IPluginData , opts ?: any ) : IFuture < void > {
@@ -566,19 +567,22 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
566567
567568 public afterPrepareAllPlugins ( ) : IFuture < void > {
568569 return ( ( ) => {
569- if ( this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
570+ if ( this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
570571 let projectPodfileContent = this . $fs . readText ( this . projectPodFilePath ) . wait ( ) ;
571572 this . $logger . trace ( "Project Podfile content" ) ;
572573 this . $logger . trace ( projectPodfileContent ) ;
573574
574575 let firstPostInstallIndex = projectPodfileContent . indexOf ( IOSProjectService . PODFILE_POST_INSTALL_SECTION_NAME ) ;
575- if ( firstPostInstallIndex !== - 1 && firstPostInstallIndex !== projectPodfileContent . lastIndexOf ( IOSProjectService . PODFILE_POST_INSTALL_SECTION_NAME ) ) {
576+ if ( firstPostInstallIndex !== - 1 && firstPostInstallIndex !== projectPodfileContent . lastIndexOf ( IOSProjectService . PODFILE_POST_INSTALL_SECTION_NAME ) ) {
576577 this . $logger . warn ( `Podfile contains more than one post_install sections. You need to open ${ this . projectPodFilePath } file and manually resolve this issue.` ) ;
577578 }
578579
579580 let xcuserDataPath = path . join ( this . xcodeprojPath , "xcuserdata" ) ;
580- if ( ! this . $fs . exists ( xcuserDataPath ) . wait ( ) ) {
581+ if ( ! this . $fs . exists ( xcuserDataPath ) . wait ( ) ) {
581582 this . $logger . info ( "Creating project scheme..." ) ;
583+
584+ this . checkIfXcodeprojIsRequired ( ) . wait ( ) ;
585+
582586 let createSchemeRubyScript = `ruby -e "require 'xcodeproj'; xcproj = Xcodeproj::Project.open('${ this . $projectData . projectName } .xcodeproj'); xcproj.recreate_user_schemes; xcproj.save"` ;
583587 this . $childProcess . exec ( createSchemeRubyScript , { cwd : this . platformData . projectRoot } ) . wait ( ) ;
584588 }
@@ -651,15 +655,15 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
651655 try {
652656 this . $childProcess . exec ( "gem which cocoapods" ) . wait ( ) ;
653657 this . $childProcess . exec ( "gem which xcodeproj" ) . wait ( ) ;
654- } catch ( e ) {
658+ } catch ( e ) {
655659 this . $errors . failWithoutHelp ( "CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again." ) ;
656660 }
657661
658662 this . $xcprojService . verifyXcproj ( true ) . wait ( ) ;
659663
660664 this . $logger . info ( "Installing pods..." ) ;
661665 let podTool = this . $config . USE_POD_SANDBOX ? "sandbox-pod" : "pod" ;
662- let childProcess = this . $childProcess . spawnFromEvent ( podTool , [ "install" ] , "close" , { cwd : this . platformData . projectRoot , stdio : [ 'pipe' , process . stdout , 'pipe' ] } ) . wait ( ) ;
666+ let childProcess = this . $childProcess . spawnFromEvent ( podTool , [ "install" ] , "close" , { cwd : this . platformData . projectRoot , stdio : [ 'pipe' , process . stdout , 'pipe' ] } ) . wait ( ) ;
663667 if ( childProcess . stderr ) {
664668 let warnings = childProcess . stderr . match ( / ( \u001b \[ (?: \d * ; ) { 0 , 5 } \d * m [ \s \S ] + ?\u001b \[ (?: \d * ; ) { 0 , 5 } \d * m ) | ( \[ ! \] .* ?\n ) | ( .* ?w a r n i n g .* ) / gi) ;
665669 _ . each ( warnings , ( warning : string ) => {
@@ -671,7 +675,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
671675 errors = errors . replace ( warning , "" ) ;
672676 } ) ;
673677
674- if ( errors . trim ( ) ) {
678+ if ( errors . trim ( ) ) {
675679 this . $errors . failWithoutHelp ( `Pod install command failed. Error output: ${ errors } ` ) ;
676680 }
677681 }
@@ -699,7 +703,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
699703 private prepareCocoapods ( pluginPlatformsFolderPath : string , opts ?: any ) : IFuture < void > {
700704 return ( ( ) => {
701705 let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
702- if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
706+ if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
703707 let pluginPodFileContent = this . $fs . readText ( pluginPodFilePath ) . wait ( ) ,
704708 pluginPodFilePreparedContent = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ,
705709 projectPodFileContent = this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ? this . $fs . readText ( this . projectPodFilePath ) . wait ( ) : "" ;
@@ -726,7 +730,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
726730 }
727731 }
728732
729- if ( opts && opts . executePodInstall && this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
733+ if ( opts && opts . executePodInstall && this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
730734 this . executePodInstall ( ) . wait ( ) ;
731735 }
732736 } ) . future < void > ( ) ( ) ;
@@ -765,12 +769,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
765769 private removeCocoapods ( pluginPlatformsFolderPath : string ) : IFuture < void > {
766770 return ( ( ) => {
767771 let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
768- if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) && this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
772+ if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) && this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
769773 let pluginPodFileContent = this . $fs . readText ( pluginPodFilePath ) . wait ( ) ;
770774 let projectPodFileContent = this . $fs . readText ( this . projectPodFilePath ) . wait ( ) ;
771- let contentToRemove = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ;
775+ let contentToRemove = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ;
772776 projectPodFileContent = helpers . stringReplaceAll ( projectPodFileContent , contentToRemove , "" ) ;
773- if ( projectPodFileContent . trim ( ) === `use_frameworks!${ os . EOL } ${ os . EOL } target "${ this . $projectData . projectName } " do${ os . EOL } ${ os . EOL } end` ) {
777+ if ( projectPodFileContent . trim ( ) === `use_frameworks!${ os . EOL } ${ os . EOL } target "${ this . $projectData . projectName } " do${ os . EOL } ${ os . EOL } end` ) {
774778 this . $fs . deleteFile ( this . projectPodFilePath ) . wait ( ) ;
775779 } else {
776780 this . $fs . writeFile ( this . projectPodFilePath , projectPodFileContent ) . wait ( ) ;
@@ -806,6 +810,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
806810 this . $fs . writeFile ( projectFile , "" ) . wait ( ) ;
807811 }
808812
813+ this . checkIfXcodeprojIsRequired ( ) . wait ( ) ;
809814 let escapedProjectFile = projectFile . replace ( / ' / g, "\\'" ) ,
810815 escapedPluginFile = pluginFile . replace ( / ' / g, "\\'" ) ,
811816 mergeScript = `require 'xcodeproj'; Xcodeproj::Config.new('${ escapedProjectFile } ').merge(Xcodeproj::Config.new('${ escapedPluginFile } ')).save_as(Pathname.new('${ escapedProjectFile } '))` ;
@@ -842,6 +847,19 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
842847 }
843848 } ) . future < void > ( ) ( ) ;
844849 }
850+
851+ private checkIfXcodeprojIsRequired ( ) : IFuture < void > {
852+ return ( ( ) => {
853+ let xcprojInfo = this . $xcprojService . getXcprojInfo ( ) . wait ( ) ;
854+ if ( xcprojInfo . shouldUseXcproj && ! xcprojInfo . xcprojAvailable ) {
855+ let errorMessage = `You are using CocoaPods version ${ xcprojInfo . cocoapodVer } which does not support Xcode ${ xcprojInfo . xcodeVersion . major } .${ xcprojInfo . xcodeVersion . minor } yet.${ EOL } In order for the NativeScript CLI to be able to work correctly with this setup you need to install xcproj command line tool and add it to your PATH. Xcproj can be installed with homebrew by running $ brew install xcproj from the terminal` ;
856+
857+ this . $errors . failWithoutHelp ( errorMessage ) ;
858+
859+ return true ;
860+ }
861+ } ) . future < void > ( ) ( ) ;
862+ }
845863}
846864
847865$injector . register ( "iOSProjectService" , IOSProjectService ) ;
0 commit comments