@@ -12,6 +12,7 @@ import * as helpers from "../common/helpers";
12
12
import * as projectServiceBaseLib from "./platform-project-service-base" ;
13
13
import Future = require( "fibers/future" ) ;
14
14
import { PlistSession } from "plist-merge-patch" ;
15
+ import { EOL } from "os" ;
15
16
16
17
export class IOSProjectService extends projectServiceBaseLib . PlatformProjectServiceBase implements IPlatformProjectService {
17
18
private static XCODE_PROJECT_EXT_NAME = ".xcodeproj" ;
@@ -41,8 +42,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
41
42
private $mobileHelper : Mobile . IMobileHelper ,
42
43
private $pluginVariablesService : IPluginVariablesService ,
43
44
private $xcprojService : IXcprojService ) {
44
- super ( $fs , $projectData , $projectDataService ) ;
45
- }
45
+ super ( $fs , $projectData , $projectDataService ) ;
46
+ }
46
47
47
48
public get platformData ( ) : IPlatformData {
48
49
let projectRoot = path . join ( this . $projectData . platformsDir , "ios" ) ;
@@ -67,7 +68,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
67
68
frameworkDirectoriesNames : [ "Metadata" , "metadataGenerator" , "NativeScript" , "internal" ] ,
68
69
targetedOS : [ 'darwin' ] ,
69
70
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" ) ,
71
72
relativeToFrameworkConfigurationFilePath : path . join ( "__PROJECT_NAME__" , "__PROJECT_NAME__-Info.plist" ) ,
72
73
fastLivesyncFileExtensions : [ ".tiff" , ".tif" , ".jpg" , "jpeg" , "gif" , ".png" , ".bmp" , ".BMPf" , ".ico" , ".cur" , ".xbm" ] // https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/
73
74
} ;
@@ -77,7 +78,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
77
78
return ( ( ) => {
78
79
let frameworkVersion = this . getFrameworkVersion ( this . platformData . frameworkPackageName ) . wait ( ) ;
79
80
80
- if ( semver . lt ( frameworkVersion , "1.3.0" ) ) {
81
+ if ( semver . lt ( frameworkVersion , "1.3.0" ) ) {
81
82
return path . join ( this . platformData . projectRoot , this . $projectData . projectName , "Resources" , "icons" ) ;
82
83
}
83
84
@@ -89,17 +90,17 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
89
90
return ( ( ) => {
90
91
try {
91
92
this . $childProcess . exec ( "which xcodebuild" ) . wait ( ) ;
92
- } catch ( error ) {
93
+ } catch ( error ) {
93
94
this . $errors . fail ( "Xcode is not installed. Make sure you have Xcode installed and added to your PATH" ) ;
94
95
}
95
96
96
97
let xcodeBuildVersion = this . $childProcess . exec ( "xcodebuild -version | head -n 1 | sed -e 's/Xcode //'" ) . wait ( ) ;
97
98
let splitedXcodeBuildVersion = xcodeBuildVersion . split ( "." ) ;
98
- if ( splitedXcodeBuildVersion . length === 3 ) {
99
+ if ( splitedXcodeBuildVersion . length === 3 ) {
99
100
xcodeBuildVersion = util . format ( "%s.%s" , splitedXcodeBuildVersion [ 0 ] , splitedXcodeBuildVersion [ 1 ] ) ;
100
101
}
101
102
102
- if ( helpers . versionCompare ( xcodeBuildVersion , IOSProjectService . XCODEBUILD_MIN_VERSION ) < 0 ) {
103
+ if ( helpers . versionCompare ( xcodeBuildVersion , IOSProjectService . XCODEBUILD_MIN_VERSION ) < 0 ) {
103
104
this . $errors . fail ( "NativeScript can only run in Xcode version %s or greater" , IOSProjectService . XCODEBUILD_MIN_VERSION ) ;
104
105
}
105
106
@@ -109,13 +110,13 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
109
110
public createProject ( frameworkDir : string , frameworkVersion : string , pathToTemplate ?: string ) : IFuture < void > {
110
111
return ( ( ) => {
111
112
this . $fs . ensureDirectoryExists ( path . join ( this . platformData . projectRoot , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ) . wait ( ) ;
112
- if ( pathToTemplate ) {
113
+ if ( pathToTemplate ) {
113
114
// Copy everything except the template from the runtime
114
115
this . $fs . readDirectory ( frameworkDir ) . wait ( )
115
116
. filter ( dirName => dirName . indexOf ( IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) === - 1 )
116
117
. forEach ( dirName => shell . cp ( "-R" , path . join ( frameworkDir , dirName ) , this . platformData . projectRoot ) ) ;
117
118
shell . cp ( "-rf" , path . join ( pathToTemplate , "*" ) , this . platformData . projectRoot ) ;
118
- } else if ( this . $options . symlink ) {
119
+ } else if ( this . $options . symlink ) {
119
120
let xcodeProjectName = util . format ( "%s.xcodeproj" , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ;
120
121
121
122
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
126
127
_ . each ( frameworkFiles , ( file : string ) => {
127
128
this . $fs . symlink ( path . join ( frameworkDir , file ) , path . join ( this . platformData . projectRoot , file ) ) . wait ( ) ;
128
129
} ) ;
129
- } else {
130
+ } else {
130
131
shell . cp ( "-R" , path . join ( frameworkDir , "*" ) , this . platformData . projectRoot ) ;
131
132
}
132
133
} ) . future < void > ( ) ( ) ;
@@ -140,7 +141,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
140
141
let projectRootFilePath = path . join ( this . platformData . projectRoot , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) ;
141
142
// Starting with NativeScript for iOS 1.6.0, the project Info.plist file resides not in the platform project,
142
143
// 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 ( ) ) {
144
145
this . replaceFileName ( "-Info.plist" , projectRootFilePath ) . wait ( ) ;
145
146
}
146
147
this . replaceFileName ( "-Prefix.pch" , projectRootFilePath ) . wait ( ) ;
@@ -173,7 +174,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
173
174
] ;
174
175
175
176
let xcworkspacePath = path . join ( projectRoot , this . $projectData . projectName + ".xcworkspace" ) ;
176
- if ( this . $fs . exists ( xcworkspacePath ) . wait ( ) ) {
177
+ if ( this . $fs . exists ( xcworkspacePath ) . wait ( ) ) {
177
178
basicArgs . push ( "-workspace" , xcworkspacePath ) ;
178
179
basicArgs . push ( "-scheme" , this . $projectData . projectName ) ;
179
180
} else {
@@ -219,7 +220,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
219
220
args . push ( `PROVISIONING_PROFILE=${ buildConfig . mobileProvisionIdentifier } ` ) ;
220
221
}
221
222
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 ( ) ;
223
224
224
225
if ( buildForDevice ) {
225
226
let buildOutputPath = path . join ( projectRoot , "build" , "device" ) ;
@@ -232,7 +233,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
232
233
"-o" , path . join ( buildOutputPath , this . $projectData . projectName + ".ipa" )
233
234
] ;
234
235
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 ( ) ;
236
237
}
237
238
} ) . future < void > ( ) ( ) ;
238
239
}
@@ -257,7 +258,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
257
258
architectures . push ( 'ONLY_ACTIVE_ARCH=NO' ) ;
258
259
}
259
260
260
- buildConfig = buildConfig || { } ;
261
+ buildConfig = buildConfig || { } ;
261
262
buildConfig . architectures = architectures ;
262
263
263
264
return this . buildProject ( this . platformData . projectRoot , buildConfig ) ;
@@ -287,7 +288,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
287
288
288
289
let frameworkAddOptions : xcode . Options = { customFramework : true } ;
289
290
290
- if ( isDynamic ) {
291
+ if ( isDynamic ) {
291
292
frameworkAddOptions [ "embed" ] = true ;
292
293
project . updateBuildProperty ( "IPHONEOS_DEPLOYMENT_TARGET" , "8.0" ) ;
293
294
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
338
339
339
340
public updatePlatform ( currentVersion : string , newVersion : string , canUpdate : boolean ) : IFuture < boolean > {
340
341
return ( ( ) => {
341
- if ( ! canUpdate ) {
342
+ if ( ! canUpdate ) {
342
343
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 ) {
344
345
// Copy old file to options["profile-dir"]
345
346
let sourceDir = this . xcodeprojPath ;
346
347
let destinationDir = path . join ( this . $options . profileDir , "xcodeproj" ) ;
@@ -370,7 +371,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
370
371
let project = this . createPbxProj ( ) ;
371
372
let resources = project . pbxGroupByName ( "Resources" ) ;
372
373
373
- if ( resources ) {
374
+ if ( resources ) {
374
375
let references = project . pbxFileReferenceSection ( ) ;
375
376
376
377
let xcodeProjectImages = _ . map ( < any [ ] > resources . children , resource => this . replace ( references [ resource . value ] . name ) ) ;
@@ -430,7 +431,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
430
431
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 ) ;
431
432
try {
432
433
this . $fs . copyFile ( templateInfoPlist , infoPlistPath ) . wait ( ) ;
433
- } catch ( e ) {
434
+ } catch ( e ) {
434
435
this . $logger . trace ( "Copying template's Info.plist failed. " + e ) ;
435
436
}
436
437
} else {
@@ -481,7 +482,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
481
482
<plist version="1.0">
482
483
<dict>
483
484
<key>CFBundleIdentifier</key>
484
- <string>${ this . $projectData . projectId } </string>
485
+ <string>${ this . $projectData . projectId } </string>
485
486
</dict>
486
487
</plist>`
487
488
} ) ;
@@ -516,8 +517,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
516
517
}
517
518
518
519
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 ) ;
521
522
}
522
523
523
524
return name . replace ( / \\ \" / g, "\"" ) ;
@@ -541,7 +542,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
541
542
}
542
543
543
544
private savePbxProj ( project : any ) : IFuture < void > {
544
- return this . $fs . writeFile ( this . pbxProjPath , project . writeSync ( ) ) ;
545
+ return this . $fs . writeFile ( this . pbxProjPath , project . writeSync ( ) ) ;
545
546
}
546
547
547
548
public preparePluginNativeCode ( pluginData : IPluginData , opts ?: any ) : IFuture < void > {
@@ -566,19 +567,22 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
566
567
567
568
public afterPrepareAllPlugins ( ) : IFuture < void > {
568
569
return ( ( ) => {
569
- if ( this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
570
+ if ( this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
570
571
let projectPodfileContent = this . $fs . readText ( this . projectPodFilePath ) . wait ( ) ;
571
572
this . $logger . trace ( "Project Podfile content" ) ;
572
573
this . $logger . trace ( projectPodfileContent ) ;
573
574
574
575
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 ) ) {
576
577
this . $logger . warn ( `Podfile contains more than one post_install sections. You need to open ${ this . projectPodFilePath } file and manually resolve this issue.` ) ;
577
578
}
578
579
579
580
let xcuserDataPath = path . join ( this . xcodeprojPath , "xcuserdata" ) ;
580
- if ( ! this . $fs . exists ( xcuserDataPath ) . wait ( ) ) {
581
+ if ( ! this . $fs . exists ( xcuserDataPath ) . wait ( ) ) {
581
582
this . $logger . info ( "Creating project scheme..." ) ;
583
+
584
+ this . checkIfXcodeprojIsRequired ( ) . wait ( ) ;
585
+
582
586
let createSchemeRubyScript = `ruby -e "require 'xcodeproj'; xcproj = Xcodeproj::Project.open('${ this . $projectData . projectName } .xcodeproj'); xcproj.recreate_user_schemes; xcproj.save"` ;
583
587
this . $childProcess . exec ( createSchemeRubyScript , { cwd : this . platformData . projectRoot } ) . wait ( ) ;
584
588
}
@@ -651,15 +655,15 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
651
655
try {
652
656
this . $childProcess . exec ( "gem which cocoapods" ) . wait ( ) ;
653
657
this . $childProcess . exec ( "gem which xcodeproj" ) . wait ( ) ;
654
- } catch ( e ) {
658
+ } catch ( e ) {
655
659
this . $errors . failWithoutHelp ( "CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again." ) ;
656
660
}
657
661
658
662
this . $xcprojService . verifyXcproj ( true ) . wait ( ) ;
659
663
660
664
this . $logger . info ( "Installing pods..." ) ;
661
665
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 ( ) ;
663
667
if ( childProcess . stderr ) {
664
668
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) ;
665
669
_ . each ( warnings , ( warning : string ) => {
@@ -671,7 +675,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
671
675
errors = errors . replace ( warning , "" ) ;
672
676
} ) ;
673
677
674
- if ( errors . trim ( ) ) {
678
+ if ( errors . trim ( ) ) {
675
679
this . $errors . failWithoutHelp ( `Pod install command failed. Error output: ${ errors } ` ) ;
676
680
}
677
681
}
@@ -699,7 +703,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
699
703
private prepareCocoapods ( pluginPlatformsFolderPath : string , opts ?: any ) : IFuture < void > {
700
704
return ( ( ) => {
701
705
let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
702
- if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
706
+ if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
703
707
let pluginPodFileContent = this . $fs . readText ( pluginPodFilePath ) . wait ( ) ,
704
708
pluginPodFilePreparedContent = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ,
705
709
projectPodFileContent = this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ? this . $fs . readText ( this . projectPodFilePath ) . wait ( ) : "" ;
@@ -726,7 +730,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
726
730
}
727
731
}
728
732
729
- if ( opts && opts . executePodInstall && this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
733
+ if ( opts && opts . executePodInstall && this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
730
734
this . executePodInstall ( ) . wait ( ) ;
731
735
}
732
736
} ) . future < void > ( ) ( ) ;
@@ -765,12 +769,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
765
769
private removeCocoapods ( pluginPlatformsFolderPath : string ) : IFuture < void > {
766
770
return ( ( ) => {
767
771
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 ( ) ) {
769
773
let pluginPodFileContent = this . $fs . readText ( pluginPodFilePath ) . wait ( ) ;
770
774
let projectPodFileContent = this . $fs . readText ( this . projectPodFilePath ) . wait ( ) ;
771
- let contentToRemove = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ;
775
+ let contentToRemove = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ;
772
776
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` ) {
774
778
this . $fs . deleteFile ( this . projectPodFilePath ) . wait ( ) ;
775
779
} else {
776
780
this . $fs . writeFile ( this . projectPodFilePath , projectPodFileContent ) . wait ( ) ;
@@ -806,6 +810,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
806
810
this . $fs . writeFile ( projectFile , "" ) . wait ( ) ;
807
811
}
808
812
813
+ this . checkIfXcodeprojIsRequired ( ) . wait ( ) ;
809
814
let escapedProjectFile = projectFile . replace ( / ' / g, "\\'" ) ,
810
815
escapedPluginFile = pluginFile . replace ( / ' / g, "\\'" ) ,
811
816
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
842
847
}
843
848
} ) . future < void > ( ) ( ) ;
844
849
}
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
+ }
845
863
}
846
864
847
865
$injector . register ( "iOSProjectService" , IOSProjectService ) ;
0 commit comments