@@ -10,6 +10,7 @@ import Future = require("fibers/future");
1010import { PlistSession } from "plist-merge-patch" ;
1111import { EOL } from "os" ;
1212import * as temp from "temp" ;
13+ import * as plist from "plist" ;
1314
1415export class IOSProjectService extends projectServiceBaseLib . PlatformProjectServiceBase implements IPlatformProjectService {
1516 private static XCODE_PROJECT_EXT_NAME = ".xcodeproj" ;
@@ -453,9 +454,93 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
453454 } ) . future < boolean > ( ) ( ) ;
454455 }
455456
457+ /**
458+ * Patch **LaunchScreen.xib** so we can be backward compatible for eternity.
459+ * The **xcodeproj** template proior v**2.1.0** had blank white screen launch screen.
460+ * We extended that by adding **app/AppResources/iOS/LaunchScreen.storyboard**
461+ * However for projects created prior **2.1.0** to keep working without the obsolete **LaunchScreen.xib**
462+ * we must still provide it on prepare.
463+ * Here we check if **UILaunchStoryboardName** is set to **LaunchScreen** in the **platform/ios/<proj>/<proj>-Info.plist**.
464+ * If it is, and no **LaunchScreen.storyboard** nor **.xib** is found in the project, we will create one.
465+ */
466+ private provideLaunchScreenIfMissing ( ) : void {
467+ try {
468+ this . $logger . trace ( "Checking if we need to provide compatability LaunchScreen.xib" ) ;
469+ let platformData = this . platformData ;
470+ let projectPath = path . join ( platformData . projectRoot , this . $projectData . projectName ) ;
471+ let projectPlist = this . getInfoPlistPath ( ) ;
472+ let plistContent = plist . parse ( this . $fs . readText ( projectPlist ) . wait ( ) ) ;
473+ let storyName = plistContent [ "UILaunchStoryboardName" ] ;
474+ this . $logger . trace ( `Examining ${ projectPlist } UILaunchStoryboardName: "${ storyName } ".` ) ;
475+ if ( storyName !== "LaunchScreen" ) {
476+ this . $logger . trace ( "The project has its UILaunchStoryboardName set to " + storyName + " which is not the pre v2.1.0 default LaunchScreen, probably the project is migrated so we are good to go." ) ;
477+ return ;
478+ }
479+
480+ let expectedStoryPath = path . join ( projectPath , "Resources" , "LaunchScreen.storyboard" ) ;
481+ if ( this . $fs . exists ( expectedStoryPath ) . wait ( ) ) {
482+ // Found a LaunchScreen on expected path
483+ this . $logger . trace ( "LaunchScreen.storyboard was found. Project is up to date." ) ;
484+ return ;
485+ }
486+ this . $logger . trace ( "LaunchScreen file not found at: " + expectedStoryPath ) ;
487+
488+ let expectedXibPath = path . join ( projectPath , "en.lproj" , "LaunchScreen.xib" ) ;
489+ if ( this . $fs . exists ( expectedXibPath ) . wait ( ) ) {
490+ this . $logger . trace ( "Obsolete LaunchScreen.xib was found. It'k OK, we are probably running with iOS runtime from pre v2.1.0." ) ;
491+ return ;
492+ }
493+ this . $logger . trace ( "LaunchScreen file not found at: " + expectedXibPath ) ;
494+
495+ let isTheLaunchScreenFile = ( fileName : string ) => fileName === "LaunchScreen.xib" || fileName === "LaunchScreen.storyboard" ;
496+ let matches = this . $fs . enumerateFilesInDirectorySync ( projectPath , isTheLaunchScreenFile , { enumerateDirectories : false } ) ;
497+ if ( matches . length > 0 ) {
498+ this . $logger . trace ( "Found LaunchScreen by slowly traversing all files here: " + matches + "\nConsider moving the LaunchScreen so it could be found at: " + expectedStoryPath ) ;
499+ return ;
500+ }
501+
502+ let compatabilityXibPath = path . join ( projectPath , "Resources" , "LaunchScreen.xib" ) ;
503+ this . $logger . warn ( `Failed to find LaunchScreen.storyboard but it was specified in the Info.plist.
504+ Consider updating the resources in app/App_Resources/iOS/.
505+ A good starting point would be to create a new project and diff the changes with your current one.
506+ Also the following repo may be helpful: https://github.com/NativeScript/template-hello-world/tree/master/App_Resources/iOS
507+ We will now place an empty obsolete compatability white screen LauncScreen.xib for you in ${ path . relative ( this . $projectData . projectDir , compatabilityXibPath ) } so your app may appear as it did in pre v2.1.0 versions of the ios runtime.` ) ;
508+
509+ let content = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
510+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6751" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
511+ <dependencies>
512+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
513+ </dependencies>
514+ <objects>
515+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
516+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
517+ <view contentMode="scaleToFill" id="iN0-l3-epB">
518+ <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
519+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
520+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
521+ <nil key="simulatedStatusBarMetrics"/>
522+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
523+ <point key="canvasLocation" x="548" y="455"/>
524+ </view>
525+ </objects>
526+ </document>` ;
527+ try {
528+ this . $fs . createDirectory ( path . dirname ( compatabilityXibPath ) ) . wait ( ) ;
529+ this . $fs . writeFile ( compatabilityXibPath , content ) . wait ( ) ;
530+ } catch ( e ) {
531+ this . $logger . warn ( "We have failed to add compatability LaunchScreen.xib due to: " + e ) ;
532+ }
533+ } catch ( e ) {
534+ this . $logger . warn ( "We have failed to check if we need to add a compatability LaunchScreen.xib due to: " + e ) ;
535+ }
536+ }
537+
456538 public prepareProject ( ) : IFuture < void > {
457539 return ( ( ) => {
458540 let project = this . createPbxProj ( ) ;
541+
542+ this . provideLaunchScreenIfMissing ( ) ;
543+
459544 let resources = project . pbxGroupByName ( "Resources" ) ;
460545
461546 if ( resources ) {
@@ -504,11 +589,19 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
504589 } ) . future < void > ( ) ( ) ;
505590 }
506591
592+ private getInfoPlistPath ( ) : string {
593+ return this . $options . baseConfig ||
594+ path . join (
595+ this . $projectData . projectDir ,
596+ constants . APP_FOLDER_NAME ,
597+ constants . APP_RESOURCES_FOLDER_NAME ,
598+ this . platformData . normalizedPlatformName ,
599+ this . platformData . configurationFileName
600+ ) ;
601+ }
507602 public ensureConfigurationFileInAppResources ( ) : IFuture < void > {
508603 return ( ( ) => {
509- let projectDir = this . $projectData . projectDir ;
510- let infoPlistPath = this . $options . baseConfig || path . join ( projectDir , constants . APP_FOLDER_NAME , constants . APP_RESOURCES_FOLDER_NAME , this . platformData . normalizedPlatformName , this . platformData . configurationFileName ) ;
511-
604+ let infoPlistPath = this . getInfoPlistPath ( ) ;
512605 if ( ! this . $fs . exists ( infoPlistPath ) . wait ( ) ) {
513606 // The project is missing Info.plist, try to populate it from the project template.
514607 let projectTemplateService : IProjectTemplatesService = this . $injector . resolve ( "projectTemplatesService" ) ;
0 commit comments