@@ -183,24 +183,72 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
183
183
public isPlatformPrepared ( projectRoot : string ) : IFuture < boolean > {
184
184
return this . $fs . exists ( path . join ( projectRoot , this . $projectData . projectName , constants . APP_FOLDER_NAME ) ) ;
185
185
}
186
-
186
+
187
187
public addLibrary ( libraryPath : string ) : IFuture < void > {
188
188
return ( ( ) => {
189
- this . validateDynamicFramework ( libraryPath ) . wait ( ) ;
190
-
189
+ let extension = path . extname ( libraryPath ) ;
190
+ if ( extension === ".framework" ) {
191
+ this . addDynamicFramework ( libraryPath ) ;
192
+ } else if ( extension === ".lib" ) {
193
+ this . addStaticLibrary ( libraryPath ) ;
194
+ } else {
195
+ this . $errors . failWithoutHelp ( "The bundle at %s does not appear to be a dynamic framework or static lib package." , libraryPath ) ;
196
+ }
197
+ } ) . future < void > ( ) ( ) ;
198
+ }
199
+
200
+ private addDynamicFramework ( frameworkPath : string ) : IFuture < void > {
201
+ return ( ( ) => {
202
+ this . validateDynamicFramework ( frameworkPath ) . wait ( ) ;
203
+
191
204
let targetPath = path . join ( "lib" , this . platformData . normalizedPlatformName ) ;
192
205
let fullTargetPath = path . join ( this . $projectData . projectDir , targetPath ) ;
193
206
this . $fs . ensureDirectoryExists ( fullTargetPath ) . wait ( ) ;
194
- shell . cp ( "-R" , libraryPath , fullTargetPath ) ;
207
+ shell . cp ( "-R" , frameworkPath , fullTargetPath ) ;
195
208
196
209
let project = this . createPbxProj ( ) ;
197
- let frameworkPath = this . getFrameworkRelativePath ( libraryPath ) ;
198
- project . addFramework ( frameworkPath , { customFramework : true , embed : true } ) ;
210
+ let frameworkRelativePath = this . getLibSubpathRelativeToProjectPath ( path . basename ( frameworkPath ) ) ;
211
+ project . addFramework ( frameworkRelativePath , { customFramework : true , embed : true } ) ;
199
212
project . updateBuildProperty ( "IPHONEOS_DEPLOYMENT_TARGET" , "8.0" ) ;
200
213
this . savePbxProj ( project ) . wait ( ) ;
201
214
this . $logger . info ( "The iOS Deployment Target is now 8.0 in order to support Cocoa Touch Frameworks." ) ;
202
215
} ) . future < void > ( ) ( ) ;
203
216
}
217
+
218
+ private addStaticLibrary ( libContainingFolderPath : string ) : IFuture < void > {
219
+ return ( ( ) => {
220
+ let project = this . createPbxProj ( ) ;
221
+ project . addPbxGroup ( [ ] , "Plugins" , this . $projectData . projectName , null ) ;
222
+ //Find all static libraries. Assume we have more than one static lib. This should be exception though.
223
+ let libFilter = ( fileName : string , containingFolderPath : string ) => ( path . extname ( fileName ) === ".a" && this . $fs . getFsStats ( path . join ( containingFolderPath , fileName ) ) . wait ( ) . isFile ( ) ) ;
224
+ let libraryPathContents = this . $fs . readDirectory ( libContainingFolderPath ) . wait ( ) ;
225
+ let staticLibs = _ ( libraryPathContents ) . filter ( platformItemName => libFilter ( platformItemName , libContainingFolderPath ) ) . value ( ) ;
226
+ //Copy files to lib folder.
227
+ let libDestinationPath = path . join ( this . $projectData . projectDir , path . join ( "lib" , this . platformData . normalizedPlatformName ) ) ;
228
+ this . $fs . ensureDirectoryExists ( libDestinationPath ) . wait ( ) ;
229
+ shell . cp ( "-R" , libContainingFolderPath , libDestinationPath ) ;
230
+ /*
231
+ 1. Validate each static lib.
232
+ 2. Setup project's header search paths. Add static libs to the project.
233
+ *Libs destination is expected to be at lib/iOS/<library_name>.lib/.
234
+ *Public headers are expected to be at <libs_location>/include/<library_name>/.
235
+ */
236
+
237
+ staticLibs . forEach ( ( staticLib ) => {
238
+ let staticLibPath = path . join ( libContainingFolderPath , staticLib ) ;
239
+ this . validateStaticLibrary ( staticLibPath ) . wait ( ) ;
240
+
241
+ let relativeStaticLibPath = this . getLibSubpathRelativeToProjectPath ( path . join ( path . basename ( libContainingFolderPath ) , staticLib ) ) ;
242
+ project . addFramework ( relativeStaticLibPath ) ;
243
+ //Process header files
244
+ let absoluteHeaderSearchPath = path . join ( path . basename ( libContainingFolderPath ) , "include" , path . basename ( staticLib , ".a" ) ) ;
245
+ let relativeHeaderSearchPath = path . join ( this . getLibSubpathRelativeToProjectPath ( absoluteHeaderSearchPath ) ) ;
246
+ project . addToHeaderSearchPaths ( relativeHeaderSearchPath ) ;
247
+ } ) ;
248
+
249
+ this . savePbxProj ( project ) . wait ( ) ;
250
+ } ) . future < void > ( ) ( ) ;
251
+ }
204
252
205
253
public canUpdatePlatform ( currentVersion : string , newVersion : string ) : IFuture < boolean > {
206
254
return ( ( ) => {
@@ -280,10 +328,9 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
280
328
return name . replace ( / \\ \" / g, "\"" ) ;
281
329
}
282
330
283
- private getFrameworkRelativePath ( libraryPath : string ) : string {
284
- let frameworkName = path . basename ( libraryPath , path . extname ( libraryPath ) ) ;
331
+ private getLibSubpathRelativeToProjectPath ( subPath : string ) : string {
285
332
let targetPath = path . join ( "lib" , this . platformData . normalizedPlatformName ) ;
286
- let frameworkPath = path . relative ( "platforms/ios" , path . join ( targetPath , frameworkName + ".framework" ) ) ;
333
+ let frameworkPath = path . relative ( "platforms/ios" , path . join ( targetPath , subPath ) ) ;
287
334
return frameworkPath ;
288
335
}
289
336
@@ -306,6 +353,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
306
353
return ( ( ) => {
307
354
let pluginPlatformsFolderPath = pluginData . pluginPlatformsFolderPath ( IOSProjectService . IOS_PLATFORM_NAME ) ;
308
355
this . prepareDynamicFrameworks ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
356
+ this . prepareStaticLibs ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
309
357
this . prepareCocoapods ( pluginPlatformsFolderPath ) . wait ( ) ;
310
358
} ) . future < void > ( ) ( ) ;
311
359
}
@@ -314,6 +362,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
314
362
return ( ( ) => {
315
363
let pluginPlatformsFolderPath = pluginData . pluginPlatformsFolderPath ( IOSProjectService . IOS_PLATFORM_NAME ) ;
316
364
this . removeDynamicFrameworks ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
365
+ this . removeStaticLibs ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
317
366
this . removeCocoapods ( pluginPlatformsFolderPath ) . wait ( ) ;
318
367
} ) . future < void > ( ) ( ) ;
319
368
}
@@ -343,11 +392,11 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
343
392
} ) . future < void > ( ) ( ) ;
344
393
}
345
394
346
- private getAllDynamicFrameworksForPlugin ( pluginData : IPluginData ) : IFuture < string [ ] > {
347
- let filterCallback = ( fileName : string , pluginPlatformsFolderPath : string ) => path . extname ( fileName ) === ".framework" ;
395
+ private getAllLibsForPluginAndFileExtension ( pluginData : IPluginData , fileExtension : string ) : IFuture < string [ ] > {
396
+ let filterCallback = ( fileName : string , pluginPlatformsFolderPath : string ) => path . extname ( fileName ) === fileExtension ;
348
397
return this . getAllNativeLibrariesForPlugin ( pluginData , IOSProjectService . IOS_PLATFORM_NAME , filterCallback ) ;
349
- }
350
-
398
+ } ;
399
+
351
400
private buildPathToXcodeProjectFile ( version : string ) : string {
352
401
return path . join ( this . $npmInstallationManager . getCachedPackagePath ( this . platformData . frameworkPackageName , version ) , constants . PROJECT_FRAMEWORK_FOLDER_NAME , util . format ( "%s.xcodeproj" , IOSProjectService . IOS_PROJECT_NAME_PLACEHOLDER ) , "project.pbxproj" ) ;
353
402
}
@@ -365,6 +414,22 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
365
414
}
366
415
} ) . future < void > ( ) ( ) ;
367
416
}
417
+
418
+ private validateStaticLibrary ( libraryPath : string ) : IFuture < void > {
419
+ return ( ( ) => {
420
+ if ( path . extname ( libraryPath ) !== ".a" ) {
421
+ this . $errors . failWithoutHelp ( "The bundle at %s does not contain valid '.a' extension." , libraryPath ) ;
422
+ }
423
+
424
+ let expectedArchs = [ "armv7" , "arm64" , "x86_64" ] ;
425
+ let archsInTheFatFile = this . $childProcess . exec ( "lipo -i " + libraryPath ) . wait ( ) ;
426
+ expectedArchs . forEach ( expectedArch => {
427
+ if ( archsInTheFatFile . indexOf ( expectedArch ) < 0 ) {
428
+ this . $errors . failWithoutHelp ( "The static library at %s is not build for all required architectures - %s." , libraryPath , expectedArchs ) ;
429
+ }
430
+ } ) ;
431
+ } ) . future < void > ( ) ( ) ;
432
+ }
368
433
369
434
private replaceFileContent ( file : string ) : IFuture < void > {
370
435
return ( ( ) => {
@@ -385,13 +450,20 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
385
450
386
451
private prepareDynamicFrameworks ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
387
452
return ( ( ) => {
388
- _ . each ( this . getAllDynamicFrameworksForPlugin ( pluginData ) . wait ( ) , fileName => this . addLibrary ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
453
+ _ . each ( this . getAllLibsForPluginAndFileExtension ( pluginData , ".framework" ) . wait ( ) , fileName => this . addDynamicFramework ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
454
+ } ) . future < void > ( ) ( ) ;
455
+ }
456
+
457
+ private prepareStaticLibs ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
458
+ return ( ( ) => {
459
+ _ . each ( this . getAllLibsForPluginAndFileExtension ( pluginData , ".lib" ) . wait ( ) , fileName => this . addStaticLibrary ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
389
460
} ) . future < void > ( ) ( ) ;
390
461
}
391
462
392
463
private prepareCocoapods ( pluginPlatformsFolderPath : string ) : IFuture < void > {
393
464
return ( ( ) => {
394
465
let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
466
+ console . log ( "prepareCocoapods" + pluginPlatformsFolderPath ) ;
395
467
if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
396
468
let pluginPodFileContent = this . $fs . readText ( pluginPodFilePath ) . wait ( ) ;
397
469
let contentToWrite = this . buildPodfileContent ( pluginPodFilePath , pluginPodFileContent ) ;
@@ -404,15 +476,40 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
404
476
return ( ( ) => {
405
477
let project = this . createPbxProj ( ) ;
406
478
407
- _ . each ( this . getAllDynamicFrameworksForPlugin ( pluginData ) . wait ( ) , fileName => {
408
- let fullFrameworkPath = path . join ( pluginPlatformsFolderPath , fileName ) ;
409
- let relativeFrameworkPath = this . getFrameworkRelativePath ( fullFrameworkPath ) ;
479
+ _ . each ( this . getAllLibsForPluginAndFileExtension ( pluginData , ".framework" ) . wait ( ) , fileName => {
480
+ let relativeFrameworkPath = this . getLibSubpathRelativeToProjectPath ( fileName ) ;
410
481
project . removeFramework ( relativeFrameworkPath , { customFramework : true , embed : true } ) ;
411
482
} ) ;
412
483
413
484
this . savePbxProj ( project ) . wait ( ) ;
414
485
} ) . future < void > ( ) ( ) ;
415
486
}
487
+
488
+ private removeStaticLibs ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
489
+ return ( ( ) => {
490
+ let project = this . createPbxProj ( ) ;
491
+ console . log ( "pluginPlatformsFolderPath is " + pluginPlatformsFolderPath ) ;
492
+
493
+ _ . each ( this . getAllLibsForPluginAndFileExtension ( pluginData , ".lib" ) . wait ( ) , fileName => {
494
+ let libContainingFolderPath = path . join ( pluginPlatformsFolderPath , fileName ) ;
495
+ let libFilter = ( fileName : string , containingFolderPath : string ) => ( path . extname ( fileName ) === ".a" && this . $fs . getFsStats ( path . join ( containingFolderPath , fileName ) ) . wait ( ) . isFile ( ) ) ;
496
+ let libraryPathContents = this . $fs . readDirectory ( libContainingFolderPath ) . wait ( ) ;
497
+ let staticLibs = _ ( libraryPathContents ) . filter ( platformItemName => libFilter ( platformItemName , libContainingFolderPath ) ) . value ( ) ;
498
+
499
+ staticLibs . forEach ( ( staticLib ) => {
500
+ let relativeStaticLibPath = this . getLibSubpathRelativeToProjectPath ( path . join ( fileName , staticLib ) ) ;
501
+ project . removeFramework ( relativeStaticLibPath ) ;
502
+
503
+ let absoluteHeaderSearchPath = path . join ( fileName , "include" , path . basename ( staticLib , ".a" ) ) ;
504
+ let relativeHeaderSearchPath = path . join ( this . getLibSubpathRelativeToProjectPath ( absoluteHeaderSearchPath ) ) ;
505
+ console . log ( "relativeHeaderSearchPath is " + relativeHeaderSearchPath ) ;
506
+ project . removeFromHeaderSearchPaths ( relativeHeaderSearchPath ) ;
507
+ } ) ;
508
+ } ) ;
509
+
510
+ this . savePbxProj ( project ) . wait ( ) ;
511
+ } ) . future < void > ( ) ( ) ;
512
+ }
416
513
417
514
private removeCocoapods ( pluginPlatformsFolderPath : string ) : IFuture < void > {
418
515
return ( ( ) => {
0 commit comments