Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions docs/man_pages/project/configuration/platform-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,28 @@ platform add

Usage | Synopsis
------|-------
Android latest runtime | `$ tns platform add android [--frameworkPath <File Path>] [--symlink] [--sdk <API Level>]`
Android selected runtime | `$ tns platform add android[@<Version>] [--frameworkPath <File Path>] [--symlink] [--sdk <API Level>]`
<% if (isMacOS) { %>iOS latest runtime | `$ tns platform add ios [--frameworkPath <File Path>] [--symlink]`
iOS selected runtime | `$ tns platform add ios[@<Version>] [--frameworkPath <File Path>] [--symlink]`<% } %>
Android latest runtime | `$ tns platform add android [--framework-path <File Path>] [--symlink] [--sdk <API Level>] [--platform-template <Platform Template>]`
Android selected runtime | `$ tns platform add android[@<Version>] [--framework-path <File Path>] [--symlink] [--sdk <API Level>] [--platform-template <Platform Template>]`
<% if (isMacOS) { %>iOS latest runtime | `$ tns platform add ios [--framework-path <File Path>] [--symlink]`
iOS selected runtime | `$ tns platform add ios[@<Version>] [--framework-path <File Path>] [--symlink] [--platform-template <Platform Template>]`<% } %>

Configures the current project to target the selected platform. <% if(isHtml) { %>When you add a target platform, the NativeScript CLI adds a corresponding platform-specific subdirectory under the platforms directory. This platform-specific directory contains the necessary files to let you build your project for the target platform.<% } %>
Configures the current project to target the selected platform. <% if(isHtml) { %>When you add a target platform, the NativeScript CLI creates a corresponding platform-specific subdirectory under the platforms directory. This platform-specific directory contains the necessary files to let you build your project for the target platform.<% } %>

### Options
* `--frameworkPath` - Sets the path to a NativeScript runtime for the specified platform that you want to use instead of the default runtime. If `--symlink` is specified, `<File Path>` must point to directory in which the runtime is already extracted. If `--symlink` is not specified, `<File Path>` must point to a valid npm package.
* `--framework-path` - Sets the path to a NativeScript runtime for the specified platform that you want to use instead of the default runtime. If `--symlink` is specified, `<File Path>` must point to directory in which the runtime is already extracted. If `--symlink` is not specified, `<File Path>` must point to a valid npm package.
* `--symlink` - Creates a symlink to a NativeScript runtime for the specified platform that you want to use instead of the default runtime. If `--frameworkPath` is specified, creates a symlink to the specified directory. If `--frameworkPath` is not specified, creates a symlink to platform runtime installed with your current version of NativeScript.
* `--sdk` - Sets the target Android SDK for the project.
* `--platform-template` - Sets the platform template that will be used for the native application.

### Attributes
* `<API Level>` is a valid Android API level. For example: 17, 19, MNC.<% if(isHtml) { %> For a complete list of the Android API levels and their corresponding Android versions, click [here](http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#platform).<% } %>
* `<File Path>` is the complete path to a valid npm package or a directory that contains a NativeScript runtime for the selected platform.
* `<Version>` is any available version of the respective platform runtime published in npm. <% if(isHtml) { %>If `@<Version>` is not specified, the NativeScript CLI installs the latest stable runtime for the selected platform.
To list all available versions for Android, run `$ npm view tns-android versions`
To list only experimental versions for Android, run `$ npm view tns-android dist-tags`
To list all available versions for iOS, run `$ npm view tns-ios versions`
To list only experimental versions for iOS, run `$ npm view tns-ios dist-tags`
* `<Platform Template>` is a valid npm package, path to directory, .tgz or GitHub URL that contains a native Android or iOS template.
* `<Version>` is any available version of the respective platform runtime published in npm. <% if(isHtml) { %>If `@<Version>` is not specified, the NativeScript CLI installs the latest stable runtime for the selected platform.
To list all available versions for Android, run `$ npm view tns-android versions`
To list only experimental versions for Android, run `$ npm view tns-android dist-tags`
To list all available versions for iOS, run `$ npm view tns-ios versions`
To list only experimental versions for iOS, run `$ npm view tns-ios dist-tags`

### Command Limitations

Expand Down
1 change: 1 addition & 0 deletions lib/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ interface IOptions extends ICommonOptions {
port: Number;
copyTo: string;
baseConfig: string;
platformTemplate: string;
}

interface IInitService {
Expand Down
2 changes: 1 addition & 1 deletion lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ interface IiOSBuildConfig extends IBuildConfig {
interface IPlatformProjectService {
platformData: IPlatformData;
validate(): IFuture<void>;
createProject(frameworkDir: string, frameworkVersion: string): IFuture<void>;
createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture<void>;
interpolateData(): IFuture<void>;
interpolateConfigurationFile(configurationFilePath?: string): IFuture<void>;
afterCreateProject(projectRoot: string): IFuture<void>;
Expand Down
1 change: 1 addition & 0 deletions lib/nativescript-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as fiber from "fibers";
import Future = require("fibers/future");
import * as shelljs from "shelljs";
shelljs.config.silent = true;
shelljs.config.fatal = true;
import {installUncaughtExceptionListener} from "./common/errors";
installUncaughtExceptionListener(process.exit);

Expand Down
3 changes: 2 additions & 1 deletion lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export class Options extends commonOptionsLibPath.OptionsBase {
compileSdk: {type: OptionType.Number },
port: { type: OptionType.Number },
copyTo: { type: OptionType.String },
baseConfig: { type: OptionType.String }
baseConfig: { type: OptionType.String },
platformTemplate: { type: OptionType.String }
},
path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"),
$errors, $staticConfig);
Expand Down
10 changes: 8 additions & 2 deletions lib/services/android-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
}).future<void>()();
}

public createProject(frameworkDir: string, frameworkVersion: string): IFuture<void> {
public createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture<void> {
return (() => {
if(semver.lt(frameworkVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) {
this.$errors.failWithoutHelp(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`);
Expand All @@ -111,7 +111,13 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
}

// These files and directories should not be symlinked as CLI is modifying them and we'll change the original values as well.
this.copy(this.platformData.projectRoot, frameworkDir, "src", "-R");
if(pathToTemplate) {
let mainPath = path.join(this.platformData.projectRoot, "src", "main");
this.$fs.createDirectory(mainPath).wait();
shell.cp("-R", path.join(path.resolve(pathToTemplate), "*"), mainPath);
} else {
this.copy(this.platformData.projectRoot, frameworkDir, "src", "-R");
}
this.copy(this.platformData.projectRoot, frameworkDir, "build.gradle settings.gradle gradle.properties", "-f");

if (this.useGradleWrapper(frameworkDir)) {
Expand Down
11 changes: 8 additions & 3 deletions lib/services/ios-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,16 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
}).future<void>()();
}

public createProject(frameworkDir: string, frameworkVersion: string): IFuture<void> {
public createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture<void> {
return (() => {
this.$fs.ensureDirectoryExists(path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait();
if(this.$options.symlink) {
if(pathToTemplate) {
// Copy everything except the template from the runtime
this.$fs.readDirectory(frameworkDir).wait()
.filter(dirName => dirName.indexOf(IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER) === -1)
.forEach(dirName => shell.cp("-R", path.join(frameworkDir, dirName), this.platformData.projectRoot));
shell.cp("-rf", path.join(pathToTemplate, "*"), this.platformData.projectRoot);
} else if(this.$options.symlink) {
let xcodeProjectName = util.format("%s.xcodeproj", IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER);

shell.cp("-R", path.join(frameworkDir, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, "*"), path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER));
Expand All @@ -118,7 +124,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
_.each(frameworkFiles, (file: string) => {
this.$fs.symlink(path.join(frameworkDir, file), path.join(this.platformData.projectRoot, file)).wait();
});

} else {
shell.cp("-R", path.join(frameworkDir, "*"), this.platformData.projectRoot);
}
Expand Down
50 changes: 46 additions & 4 deletions lib/services/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import * as helpers from "../common/helpers";
import * as semver from "semver";
import * as minimatch from "minimatch";
import Future = require("fibers/future");
import * as temp from "temp";
temp.track();
let clui = require("clui");

export class PlatformService implements IPlatformService {
Expand All @@ -29,7 +31,8 @@ export class PlatformService implements IPlatformService {
private $projectFilesManager: IProjectFilesManager,
private $mobileHelper: Mobile.IMobileHelper,
private $hostInfo: IHostInfo,
private $xmlValidator: IXmlValidator) { }
private $xmlValidator: IXmlValidator,
private $npm: INodePackageManager) { }

public addPlatforms(platforms: string[]): IFuture<void> {
return (() => {
Expand Down Expand Up @@ -114,7 +117,10 @@ export class PlatformService implements IPlatformService {
}

let sourceFrameworkDir = isFrameworkPathDirectory && this.$options.symlink ? path.join(this.$options.frameworkPath, "framework") : frameworkDir;
platformData.platformProjectService.createProject(path.resolve(sourceFrameworkDir), installedVersion).wait();
this.$projectDataService.initialize(this.$projectData.projectDir);
let customTemplateOptions = this.getPathToPlatformTemplate(this.$options.platformTemplate, platformData.frameworkPackageName).wait();
let pathToTemplate = customTemplateOptions && customTemplateOptions.pathToTemplate;
platformData.platformProjectService.createProject(path.resolve(sourceFrameworkDir), installedVersion, pathToTemplate).wait();

if(isFrameworkPathDirectory || isFrameworkPathNotSymlinkedFile) {
// Need to remove unneeded node_modules folder
Expand All @@ -132,12 +138,48 @@ export class PlatformService implements IPlatformService {
this.$fs.copyFile(newConfigFile, platformData.configurationFilePath).wait();
}

this.$projectDataService.initialize(this.$projectData.projectDir);
this.$projectDataService.setValue(platformData.frameworkPackageName, {version: installedVersion}).wait();
let frameworkPackageNameData: any = {version: installedVersion};
if(customTemplateOptions) {
frameworkPackageNameData.template = customTemplateOptions.selectedTemplate;
}
this.$projectDataService.setValue(platformData.frameworkPackageName, frameworkPackageNameData).wait();

}).future<void>()();
}

private getPathToPlatformTemplate(selectedTemplate: string, frameworkPackageName: string): IFuture<any> {
return (() => {
if(!selectedTemplate) {
// read data from package.json's nativescript key
// check the nativescript.tns-<platform>.template value
let nativescriptPlatformData = this.$projectDataService.getValue(frameworkPackageName).wait();
selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template;
}

if(selectedTemplate) {
let tempDir = temp.mkdirSync("platform-template");
try {
/*
* Output of npm.install is array of arrays. For example:
* [ [ 'test-android-platform-template@0.0.1',
* 'C:\\Users\\<USER>~1\\AppData\\Local\\Temp\\1\\platform-template11627-15560-rm3ngx\\node_modules\\test-android-platform-template',
* undefined,
* undefined,
* '..\\..\\..\\android-platform-template' ] ]
* Project successfully created.
*/
let pathToTemplate = this.$npm.install(selectedTemplate, tempDir).wait()[0][1];
return { selectedTemplate, pathToTemplate };
} catch(err) {
this.$logger.trace("Error while trying to install specified template: ", err);
this.$errors.failWithoutHelp(`Unable to install platform template ${selectedTemplate}. Make sure the specified value is valid.`);
}
}

return null;
}).future<any>()();
}

public getInstalledPlatforms(): IFuture<string[]> {
return(() => {
if(!this.$fs.exists(this.$projectData.platformsDir).wait()) {
Expand Down
1 change: 1 addition & 0 deletions test/platform-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ function createTestInjector() {
testInjector.register("mobilePlatformsCapabilities", MobilePlatformsCapabilities);
testInjector.register("devicePlatformsConstants", DevicePlatformsConstants);
testInjector.register("xmlValidator", XmlValidator);
testInjector.register("npm", {});

return testInjector;
}
Expand Down
1 change: 1 addition & 0 deletions test/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function createTestInjector() {
testInjector.register("mobilePlatformsCapabilities", MobilePlatformsCapabilities);
testInjector.register("devicePlatformsConstants", DevicePlatformsConstants);
testInjector.register("xmlValidator", XmlValidator);
testInjector.register("npm", {});

return testInjector;
}
Expand Down