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