@@ -200,29 +200,63 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
200
200
201
201
public addLibrary ( libraryPath : string ) : IFuture < void > {
202
202
return ( ( ) => {
203
- this . validateFramework ( libraryPath ) . wait ( ) ;
203
+ let extension = path . extname ( libraryPath ) ;
204
+ if ( extension === ".framework" ) {
205
+ this . addDynamicFramework ( libraryPath ) ;
206
+ } else {
207
+ this . $errors . failWithoutHelp ( `The bundle at ${ libraryPath } does not appear to be a dynamic framework package.` ) ;
208
+ }
209
+ } ) . future < void > ( ) ( ) ;
210
+ }
211
+
212
+ private addDynamicFramework ( frameworkPath : string ) : IFuture < void > {
213
+ return ( ( ) => {
214
+ this . validateFramework ( frameworkPath ) . wait ( ) ;
204
215
205
216
let targetPath = path . join ( "lib" , this . platformData . normalizedPlatformName ) ;
206
217
let fullTargetPath = path . join ( this . $projectData . projectDir , targetPath ) ;
207
218
this . $fs . ensureDirectoryExists ( fullTargetPath ) . wait ( ) ;
208
- shell . cp ( "-R" , libraryPath , fullTargetPath ) ;
219
+ shell . cp ( "-R" , frameworkPath , fullTargetPath ) ;
209
220
210
221
let project = this . createPbxProj ( ) ;
211
-
212
- let frameworkName = path . basename ( libraryPath , path . extname ( libraryPath ) ) ;
213
- let frameworkBinaryPath = path . join ( libraryPath , frameworkName ) ;
222
+ let frameworkName = path . basename ( frameworkPath , path . extname ( frameworkPath ) ) ;
223
+ let frameworkBinaryPath = path . join ( frameworkPath , frameworkName ) ;
214
224
let isDynamic = _ . contains ( this . $childProcess . exec ( `otool -Vh ${ frameworkBinaryPath } ` ) . wait ( ) , " DYLIB " ) ;
215
225
216
- let frameworkAddOptions : xcode . FrameworkOptions = { customFramework : true } ;
226
+ let frameworkAddOptions : xcode . Options = { customFramework : true } ;
217
227
218
228
if ( isDynamic ) {
219
229
frameworkAddOptions [ "embed" ] = true ;
220
230
project . updateBuildProperty ( "IPHONEOS_DEPLOYMENT_TARGET" , "8.0" ) ;
221
231
this . $logger . info ( "The iOS Deployment Target is now 8.0 in order to support Cocoa Touch Frameworks." ) ;
222
232
}
223
233
224
- let frameworkPath = this . getFrameworkRelativePath ( libraryPath ) ;
225
- project . addFramework ( frameworkPath , frameworkAddOptions ) ;
234
+ let frameworkRelativePath = this . getLibSubpathRelativeToProjectPath ( path . basename ( frameworkPath ) ) ;
235
+ project . addFramework ( frameworkRelativePath , frameworkAddOptions ) ;
236
+ this . savePbxProj ( project ) . wait ( ) ;
237
+ } ) . future < void > ( ) ( ) ;
238
+ }
239
+
240
+ private addStaticLibrary ( staticLibPath : string ) : IFuture < void > {
241
+ return ( ( ) => {
242
+ this . validateStaticLibrary ( staticLibPath ) . wait ( ) ;
243
+ // Copy files to lib folder.
244
+ let libraryName = path . basename ( staticLibPath , ".a" ) ;
245
+ let libDestinationPath = path . join ( this . $projectData . projectDir , path . join ( "lib" , this . platformData . normalizedPlatformName ) ) ;
246
+ let headersSubpath = path . join ( "include" , libraryName ) ;
247
+ this . $fs . ensureDirectoryExists ( path . join ( libDestinationPath , headersSubpath ) ) . wait ( ) ;
248
+ shell . cp ( "-Rf" , staticLibPath , libDestinationPath ) ;
249
+ shell . cp ( "-Rf" , path . join ( path . dirname ( staticLibPath ) , headersSubpath ) , path . join ( libDestinationPath , "include" ) ) ;
250
+
251
+ // Add static library to project file and setup header search paths
252
+ let project = this . createPbxProj ( ) ;
253
+ let relativeStaticLibPath = this . getLibSubpathRelativeToProjectPath ( path . basename ( staticLibPath ) ) ;
254
+ project . addFramework ( relativeStaticLibPath ) ;
255
+
256
+ let relativeHeaderSearchPath = path . join ( this . getLibSubpathRelativeToProjectPath ( headersSubpath ) ) ;
257
+ project . addToHeaderSearchPaths ( { relativePath : relativeHeaderSearchPath } ) ;
258
+
259
+ this . generateMobulemap ( path . join ( libDestinationPath , headersSubpath ) , libraryName ) ;
226
260
this . savePbxProj ( project ) . wait ( ) ;
227
261
} ) . future < void > ( ) ( ) ;
228
262
}
@@ -307,10 +341,9 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
307
341
return name . replace ( / \\ \" / g, "\"" ) ;
308
342
}
309
343
310
- private getFrameworkRelativePath ( libraryPath : string ) : string {
311
- let frameworkName = path . basename ( libraryPath , path . extname ( libraryPath ) ) ;
344
+ private getLibSubpathRelativeToProjectPath ( subPath : string ) : string {
312
345
let targetPath = path . join ( "lib" , this . platformData . normalizedPlatformName ) ;
313
- let frameworkPath = path . relative ( "platforms/ios" , path . join ( targetPath , frameworkName + ".framework" ) ) ;
346
+ let frameworkPath = path . relative ( "platforms/ios" , path . join ( targetPath , subPath ) ) ;
314
347
return frameworkPath ;
315
348
}
316
349
@@ -332,15 +365,19 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
332
365
public preparePluginNativeCode ( pluginData : IPluginData , opts ?: any ) : IFuture < void > {
333
366
return ( ( ) => {
334
367
let pluginPlatformsFolderPath = pluginData . pluginPlatformsFolderPath ( IOSProjectService . IOS_PLATFORM_NAME ) ;
368
+
335
369
this . prepareFrameworks ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
336
- this . prepareCocoapods ( pluginPlatformsFolderPath , opts ) . wait ( ) ;
370
+ this . prepareStaticLibs ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
371
+ this . prepareCocoapods ( pluginPlatformsFolderPath ) . wait ( ) ;
337
372
} ) . future < void > ( ) ( ) ;
338
373
}
339
374
340
375
public removePluginNativeCode ( pluginData : IPluginData ) : IFuture < void > {
341
376
return ( ( ) => {
342
377
let pluginPlatformsFolderPath = pluginData . pluginPlatformsFolderPath ( IOSProjectService . IOS_PLATFORM_NAME ) ;
378
+
343
379
this . removeFrameworks ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
380
+ this . removeStaticLibs ( pluginPlatformsFolderPath , pluginData ) . wait ( ) ;
344
381
this . removeCocoapods ( pluginPlatformsFolderPath ) . wait ( ) ;
345
382
} ) . future < void > ( ) ( ) ;
346
383
}
@@ -377,10 +414,10 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
377
414
} ) . future < void > ( ) ( ) ;
378
415
}
379
416
380
- private getAllFrameworksForPlugin ( pluginData : IPluginData ) : IFuture < string [ ] > {
381
- let filterCallback = ( fileName : string , pluginPlatformsFolderPath : string ) => path . extname ( fileName ) === ".framework" ;
417
+ private getAllLibsForPluginWithFileExtension ( pluginData : IPluginData , fileExtension : string ) : IFuture < string [ ] > {
418
+ let filterCallback = ( fileName : string , pluginPlatformsFolderPath : string ) => path . extname ( fileName ) === fileExtension ;
382
419
return this . getAllNativeLibrariesForPlugin ( pluginData , IOSProjectService . IOS_PLATFORM_NAME , filterCallback ) ;
383
- }
420
+ } ;
384
421
385
422
private buildPathToXcodeProjectFile ( version : string ) : string {
386
423
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" ) ;
@@ -400,6 +437,24 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
400
437
} ) . future < void > ( ) ( ) ;
401
438
}
402
439
440
+ private validateStaticLibrary ( libraryPath : string ) : IFuture < void > {
441
+ return ( ( ) => {
442
+ if ( path . extname ( libraryPath ) !== ".a" ) {
443
+ this . $errors . failWithoutHelp ( `The bundle at ${ libraryPath } does not contain a valid static library in the '.a' file format.` ) ;
444
+ }
445
+
446
+ let expectedArchs = [ "armv7" , "arm64" , "i386" ] ;
447
+ let archsInTheFatFile = this . $childProcess . exec ( "lipo -i " + libraryPath ) . wait ( ) ;
448
+
449
+ expectedArchs . forEach ( expectedArch => {
450
+ if ( archsInTheFatFile . indexOf ( expectedArch ) < 0 ) {
451
+ this . $errors . failWithoutHelp ( `The static library at ${ libraryPath } is not built for one or more of the following required architectures:
452
+ ${ expectedArchs . join ( ", " ) } . The static library must be built for all required architectures.` ) ;
453
+ }
454
+ } ) ;
455
+ } ) . future < void > ( ) ( ) ;
456
+ }
457
+
403
458
private replaceFileContent ( file : string ) : IFuture < void > {
404
459
return ( ( ) => {
405
460
let fileContent = this . $fs . readText ( file ) . wait ( ) ;
@@ -424,13 +479,20 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
424
479
425
480
private prepareFrameworks ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
426
481
return ( ( ) => {
427
- _ . each ( this . getAllFrameworksForPlugin ( pluginData ) . wait ( ) , fileName => this . addLibrary ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
482
+ _ . each ( this . getAllLibsForPluginWithFileExtension ( pluginData , ".framework" ) . wait ( ) , fileName => this . addDynamicFramework ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
483
+ } ) . future < void > ( ) ( ) ;
484
+ }
485
+
486
+ private prepareStaticLibs ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
487
+ return ( ( ) => {
488
+ _ . each ( this . getAllLibsForPluginWithFileExtension ( pluginData , ".a" ) . wait ( ) , fileName => this . addStaticLibrary ( path . join ( pluginPlatformsFolderPath , fileName ) ) . wait ( ) ) ;
428
489
} ) . future < void > ( ) ( ) ;
429
490
}
430
491
431
492
private prepareCocoapods ( pluginPlatformsFolderPath : string , opts ?: any ) : IFuture < void > {
432
493
return ( ( ) => {
433
494
let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
495
+
434
496
if ( this . $fs . exists ( pluginPodFilePath ) . wait ( ) ) {
435
497
if ( ! this . $fs . exists ( this . projectPodFilePath ) . wait ( ) ) {
436
498
this . $fs . writeFile ( this . projectPodFilePath , "use_frameworks!\n" ) . wait ( ) ;
@@ -450,17 +512,33 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
450
512
private removeFrameworks ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
451
513
return ( ( ) => {
452
514
let project = this . createPbxProj ( ) ;
453
-
454
- _ . each ( this . getAllFrameworksForPlugin ( pluginData ) . wait ( ) , fileName => {
455
- let fullFrameworkPath = path . join ( pluginPlatformsFolderPath , fileName ) ;
456
- let relativeFrameworkPath = this . getFrameworkRelativePath ( fullFrameworkPath ) ;
515
+ _ . each ( this . getAllLibsForPluginWithFileExtension ( pluginData , ".framework" ) . wait ( ) , fileName => {
516
+ let relativeFrameworkPath = this . getLibSubpathRelativeToProjectPath ( fileName ) ;
457
517
project . removeFramework ( relativeFrameworkPath , { customFramework : true , embed : true } ) ;
458
518
} ) ;
459
519
460
520
this . savePbxProj ( project ) . wait ( ) ;
461
521
} ) . future < void > ( ) ( ) ;
462
522
}
463
523
524
+ private removeStaticLibs ( pluginPlatformsFolderPath : string , pluginData : IPluginData ) : IFuture < void > {
525
+ return ( ( ) => {
526
+ let project = this . createPbxProj ( ) ;
527
+
528
+ _ . each ( this . getAllLibsForPluginWithFileExtension ( pluginData , ".a" ) . wait ( ) , fileName => {
529
+ let staticLibPath = path . join ( pluginPlatformsFolderPath , fileName ) ;
530
+ let relativeStaticLibPath = this . getLibSubpathRelativeToProjectPath ( path . basename ( staticLibPath ) ) ;
531
+ project . removeFramework ( relativeStaticLibPath ) ;
532
+
533
+ let headersSubpath = path . join ( "include" , path . basename ( staticLibPath , ".a" ) ) ;
534
+ let relativeHeaderSearchPath = path . join ( this . getLibSubpathRelativeToProjectPath ( headersSubpath ) ) ;
535
+ project . removeFromHeaderSearchPaths ( { relativePath : relativeHeaderSearchPath } ) ;
536
+ } ) ;
537
+
538
+ this . savePbxProj ( project ) . wait ( ) ;
539
+ } ) . future < void > ( ) ( ) ;
540
+ }
541
+
464
542
private removeCocoapods ( pluginPlatformsFolderPath : string ) : IFuture < void > {
465
543
return ( ( ) => {
466
544
let pluginPodFilePath = path . join ( pluginPlatformsFolderPath , "Podfile" ) ;
@@ -481,5 +559,22 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
481
559
private buildPodfileContent ( pluginPodFilePath : string , pluginPodFileContent : string ) : string {
482
560
return `# Begin Podfile - ${ pluginPodFilePath } ${ os . EOL } ${ pluginPodFileContent } ${ os . EOL } # End Podfile ${ os . EOL } ` ;
483
561
}
562
+
563
+ private generateMobulemap ( headersFolderPath : string , libraryName : string ) : void {
564
+ let headersFilter = ( fileName : string , containingFolderPath : string ) => ( path . extname ( fileName ) === ".h" && this . $fs . getFsStats ( path . join ( containingFolderPath , fileName ) ) . wait ( ) . isFile ( ) ) ;
565
+ let headersFolderContents = this . $fs . readDirectory ( headersFolderPath ) . wait ( ) ;
566
+ let headers = _ ( headersFolderContents ) . filter ( item => headersFilter ( item , headersFolderPath ) ) . value ( ) ;
567
+
568
+ if ( ! headers . length ) {
569
+ this . $fs . deleteFile ( path . join ( headersFolderPath , "module.modulemap" ) ) . wait ( ) ;
570
+ return ;
571
+ }
572
+
573
+ headers = _ . map ( headers , value => `header "${ value } "` ) ;
574
+
575
+ let modulemap = `module ${ libraryName } { explicit module ${ libraryName } { ${ headers . join ( " " ) } } }` ;
576
+ this . $fs . writeFile ( path . join ( headersFolderPath , "module.modulemap" ) , modulemap ) . wait ( ) ;
577
+ }
484
578
}
579
+
485
580
$injector . register ( "iOSProjectService" , IOSProjectService ) ;
0 commit comments