Skip to content

Commit 13faa66

Browse files
Merge pull request #1875 from NativeScript/cankov/launchscreen-compatability
Add LaunchScreen.xib in the Resources in case it is missing in pre v2.1.0 projects
2 parents 64d9df8 + ba38b17 commit 13faa66

File tree

1 file changed

+96
-3
lines changed

1 file changed

+96
-3
lines changed

lib/services/ios-project-service.ts

+96-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Future = require("fibers/future");
1010
import { PlistSession } from "plist-merge-patch";
1111
import {EOL} from "os";
1212
import * as temp from "temp";
13+
import * as plist from "plist";
1314

1415
export 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

Comments
 (0)