Skip to content

Commit e010223

Browse files
Fatme HavaluovaFatme Havaluova
Fatme Havaluova
authored and
Fatme Havaluova
committed
Fixes #1066
1 parent 4e667af commit e010223

10 files changed

+98
-50
lines changed

lib/definitions/platform.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface IPlatformData {
3636
targetedOS?: string[];
3737
configurationFileName?: string;
3838
configurationFilePath?: string;
39+
relativeToFrameworkConfigurationFilePath: string;
3940
mergeXmlConfig?: any[];
4041
}
4142

lib/definitions/project.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ interface IPlatformProjectService {
3636
platformData: IPlatformData;
3737
validate(): IFuture<void>;
3838
createProject(frameworkDir: string, frameworkVersion: string): IFuture<void>;
39-
interpolateData(projectRoot: string): IFuture<void>;
39+
interpolateData(): IFuture<void>;
40+
interpolateConfigurationFile(configurationFilePath?: string): IFuture<void>;
4041
afterCreateProject(projectRoot: string): IFuture<void>;
4142
buildProject(projectRoot: string, buildConfig?: IBuildConfig): IFuture<void>;
4243
prepareProject(): IFuture<void>;

lib/services/android-project-service.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as semver from "semver";
88
import * as projectServiceBaseLib from "./platform-project-service-base";
99
import * as androidDebugBridgePath from "../common/mobile/android/android-debug-bridge";
1010

11-
class AndroidProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
11+
export class AndroidProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
1212
private static VALUES_DIRNAME = "values";
1313
private static VALUES_VERSION_DIRNAME_PREFIX = AndroidProjectService.VALUES_DIRNAME + "-v";
1414
private static ANDROID_PLATFORM_NAME = "android";
@@ -57,6 +57,7 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
5757
frameworkFilesExtensions: [".jar", ".dat", ".so"],
5858
configurationFileName: "AndroidManifest.xml",
5959
configurationFilePath: path.join(projectRoot, "src", "main", "AndroidManifest.xml"),
60+
relativeToFrameworkConfigurationFilePath: path.join("src", "main", "AndroidManifest.xml"),
6061
mergeXmlConfig: [{ "nodename": "manifest", "attrname": "*" }, {"nodename": "application", "attrname": "*"}]
6162
};
6263
}
@@ -134,18 +135,28 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
134135
}).future<void>()();
135136
}
136137

137-
public interpolateData(projectRoot: string): IFuture<void> {
138+
public interpolateData(): IFuture<void> {
138139
return (() => {
139-
// Interpolate the activity name and package
140-
let manifestPath = this.platformData.configurationFilePath;
141-
shell.sed('-i', /__PACKAGE__/, this.$projectData.projectId, manifestPath);
140+
// Interpolate the apilevel and package
141+
this.interpolateConfigurationFile().wait();
142142

143143
let stringsFilePath = path.join(this.getAppResourcesDestinationDirectoryPath().wait(), 'values', 'strings.xml');
144144
shell.sed('-i', /__NAME__/, this.$projectData.projectName, stringsFilePath);
145145
shell.sed('-i', /__TITLE_ACTIVITY__/, this.$projectData.projectName, stringsFilePath);
146146

147147
let gradleSettingsFilePath = path.join(this.platformData.projectRoot, "settings.gradle");
148148
shell.sed('-i', /__PROJECT_NAME__/, this.getProjectNameFromId(), gradleSettingsFilePath);
149+
}).future<void>()();
150+
}
151+
152+
public interpolateConfigurationFile(): IFuture<void> {
153+
return (() => {
154+
let manifestPath = this.platformData.configurationFilePath;
155+
156+
console.log("ANDROID MANIFEST FILE PATH!!!!");
157+
console.log(manifestPath);
158+
159+
shell.sed('-i', /__PACKAGE__/, this.$projectData.projectId, manifestPath);
149160
shell.sed('-i', /__APILEVEL__/, this.$options.sdk || this.$androidToolsInfo.getToolsInfo().wait().compileSdkVersion.toString(), manifestPath);
150161
}).future<void>()();
151162
}

lib/services/ios-project-service.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
6060
targetedOS: ['darwin'],
6161
configurationFileName: "Info.plist",
6262
configurationFilePath: path.join(projectRoot, this.$projectData.projectName, this.$projectData.projectName+"-Info.plist"),
63+
relativeToFrameworkConfigurationFilePath: path.join("__PROJECT_NAME__", "__PROJECT_NAME__-Info.plist"),
6364
mergeXmlConfig: [{ "nodename": "plist", "attrname": "*" }, {"nodename": "dict", "attrname": "*"}]
6465
};
6566
}
@@ -118,20 +119,26 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
118119
}).future<void>()();
119120
}
120121

121-
public interpolateData(projectRoot: string): IFuture<void> {
122+
public interpolateData(): IFuture<void> {
122123
return (() => {
123-
let infoPlistFilePath = path.join(projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, util.format("%s-%s", IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, "Info.plist"));
124-
shell.sed('-i', "__CFBUNDLEIDENTIFIER__", this.$projectData.projectId, infoPlistFilePath);
124+
let infoPlistFilePath = path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, util.format("%s-%s", IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, "Info.plist"));
125+
this.interpolateConfigurationFile(infoPlistFilePath).wait();
125126

126-
this.replaceFileName("-Info.plist", path.join(projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait();
127-
this.replaceFileName("-Prefix.pch", path.join(projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait();
128-
this.replaceFileName(IOSProjectService.XCODE_PROJECT_EXT_NAME, projectRoot).wait();
127+
this.replaceFileName("-Info.plist", path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait();
128+
this.replaceFileName("-Prefix.pch", path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait();
129+
this.replaceFileName(IOSProjectService.XCODE_PROJECT_EXT_NAME, this.platformData.projectRoot).wait();
129130

130-
let pbxprojFilePath = path.join(projectRoot, this.$projectData.projectName + IOSProjectService.XCODE_PROJECT_EXT_NAME, "project.pbxproj");
131+
let pbxprojFilePath = path.join(this.platformData.projectRoot, this.$projectData.projectName + IOSProjectService.XCODE_PROJECT_EXT_NAME, "project.pbxproj");
131132
this.replaceFileContent(pbxprojFilePath).wait();
132133
}).future<void>()();
133134
}
134135

136+
public interpolateConfigurationFile(configurationFilePath?: string): IFuture<void> {
137+
return (() => {
138+
shell.sed('-i', "__CFBUNDLEIDENTIFIER__", this.$projectData.projectId, configurationFilePath || this.platformData.configurationFilePath);
139+
}).future<void>()();
140+
}
141+
135142
public afterCreateProject(projectRoot: string): IFuture<void> {
136143
return (() => {
137144
this.$fs.rename(path.join(projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER),

lib/services/platform-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export class PlatformService implements IPlatformService {
102102
this.$fs.deleteDirectory(path.join(frameworkDir, "../../")).wait();
103103
}
104104

105-
platformData.platformProjectService.interpolateData(platformData.projectRoot).wait();
105+
platformData.platformProjectService.interpolateData().wait();
106106
platformData.platformProjectService.afterCreateProject(platformData.projectRoot).wait();
107107

108108
this.$projectDataService.initialize(this.$projectData.projectDir);

lib/services/plugins-service.ts

+27-23
Original file line numberDiff line numberDiff line change
@@ -86,25 +86,7 @@ export class PluginsService implements IPluginsService {
8686
// Remove the plugin and call merge for another plugins that have configuration file
8787
let pluginConfigurationFilePath = this.getPluginConfigurationFilePath(pluginData, platformData);
8888
if(this.$fs.exists(pluginConfigurationFilePath).wait()) {
89-
let tnsModulesDestinationPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, constants.TNS_MODULES_FOLDER_NAME);
90-
let nodeModules = this.$broccoliBuilder.getChangedNodeModules(tnsModulesDestinationPath, platform).wait();
91-
92-
_(nodeModules)
93-
.map(nodeModule => this.getNodeModuleData(pluginName).wait())
94-
.map(nodeModuleData => this.convertToPluginData(nodeModuleData))
95-
.filter(data => data.isPlugin && this.$fs.exists(this.getPluginConfigurationFilePath(data, platformData)).wait())
96-
.forEach((data, index) => {
97-
executeUninstallCommand().wait();
98-
99-
if(index === 0) {
100-
this.initializeConfigurationFileFromCache(platformData).wait();
101-
}
102-
103-
if(data.name !== pluginName) {
104-
this.merge(data, platformData).wait();
105-
}
106-
})
107-
.value();
89+
this.merge(pluginData, platformData).wait();
10890
}
10991

11092
if(pluginData.pluginVariables) {
@@ -139,13 +121,14 @@ export class PluginsService implements IPluginsService {
139121
let frameworkVersion = this.$projectDataService.getValue(platformData.frameworkPackageName).wait().version;
140122
this.$npm.cache(platformData.frameworkPackageName, frameworkVersion).wait();
141123

142-
let relativeConfigurationFilePath = path.relative(platformData.projectRoot, platformData.configurationFilePath);
143124
// We need to resolve this manager here due to some restrictions from npm api and in order to load PluginsService.NPM_CONFIG config
144125
let npmInstallationManager: INpmInstallationManager = this.$injector.resolve("npmInstallationManager");
145126
let cachedPackagePath = npmInstallationManager.getCachedPackagePath(platformData.frameworkPackageName, frameworkVersion);
146-
let cachedConfigurationFilePath = path.join(cachedPackagePath, constants.PROJECT_FRAMEWORK_FOLDER_NAME, relativeConfigurationFilePath);
127+
let cachedConfigurationFilePath = path.join(cachedPackagePath, constants.PROJECT_FRAMEWORK_FOLDER_NAME, platformData.relativeToFrameworkConfigurationFilePath);
128+
let cachedConfigurationFileContent = this.$fs.readText(cachedConfigurationFilePath).wait();
129+
this.$fs.writeFile(platformData.configurationFilePath, cachedConfigurationFileContent).wait();
147130

148-
shelljs.cp("-f", cachedConfigurationFilePath, path.dirname(platformData.configurationFilePath));
131+
platformData.platformProjectService.interpolateConfigurationFile().wait();
149132
}).future<void>()();
150133
}
151134

@@ -347,7 +330,7 @@ export class PluginsService implements IPluginsService {
347330
doc.parseFromString(xml, 'text/xml');
348331
}
349332

350-
private merge(pluginData: IPluginData, platformData: IPlatformData): IFuture<void> {
333+
private mergeCore(pluginData: IPluginData, platformData: IPlatformData): IFuture<void> {
351334
return (() => {
352335
let pluginConfigurationFilePath = this.getPluginConfigurationFilePath(pluginData, platformData);
353336
let configurationFilePath = platformData.configurationFilePath;
@@ -368,6 +351,27 @@ export class PluginsService implements IPluginsService {
368351
}).future<void>()();
369352
}
370353

354+
private merge(pluginData: IPluginData, platformData: IPlatformData): IFuture<void> {
355+
return (() => {
356+
let tnsModulesDestinationPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, constants.TNS_MODULES_FOLDER_NAME);
357+
let nodeModules = this.$broccoliBuilder.getChangedNodeModules(tnsModulesDestinationPath, platformData.normalizedPlatformName.toLowerCase()).wait();
358+
359+
_(_.keys(nodeModules))
360+
.map(nodeModule => this.getNodeModuleData(path.join(nodeModule, "package.json")).wait())
361+
.map(nodeModuleData => this.convertToPluginData(nodeModuleData))
362+
.filter(data => data.isPlugin && this.$fs.exists(this.getPluginConfigurationFilePath(data, platformData)).wait())
363+
.forEach((data, index) => {
364+
if(index === 0) {
365+
this.initializeConfigurationFileFromCache(platformData).wait();
366+
}
367+
368+
this.mergeCore(data, platformData).wait();
369+
})
370+
.value();
371+
372+
}).future<void>()();
373+
}
374+
371375
private getPluginConfigurationFilePath(pluginData: IPluginData, platformData: IPlatformData): string {
372376
let pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(platformData.normalizedPlatformName.toLowerCase());
373377
let pluginConfigurationFilePath = path.join(pluginPlatformsFolderPath, platformData.configurationFileName);

lib/tools/broccoli/builder.ts

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ let through = require("through2");
1212

1313
export class Builder implements IBroccoliBuilder {
1414
constructor(private $fs: IFileSystem,
15-
private $nodeModulesTree: INodeModulesTree,
1615
private $projectData: IProjectData,
1716
private $projectDataService: IProjectDataService,
1817
private $injector: IInjector,

test/platform-commands.ts

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class PlatformData implements IPlatformData {
2828
frameworkVersion = "";
2929
appDestinationDirectoryPath = "";
3030
appResourcesDestinationDirectoryPath = "";
31+
relativeToFrameworkConfigurationFilePath = "";
3132
}
3233

3334
class ErrorsNoFailStub implements IErrors {

test/plugins-service.ts

+29-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {Yok} from '../lib/common/yok';
55
import future = require("fibers/future");
66
import * as stubs from './stubs';
77
import {NodePackageManager} from "../lib/node-package-manager";
8+
import {NpmInstallationManager} from "../lib/npm-installation-manager";
89
import {FileSystem} from "../lib/common/file-system";
910
import {ProjectData} from "../lib/project-data";
1011
import {ChildProcess} from "../lib/common/child-process";
@@ -23,6 +24,9 @@ import {ResourceLoader} from "../lib/common/resource-loader";
2324
import {EOL} from "os";
2425
import {PluginsService} from "../lib/services/plugins-service";
2526
import {AddPluginCommand} from "../lib/commands/plugin/add-plugin";
27+
import {Builder} from "../lib/tools/broccoli/builder";
28+
import {AndroidProjectService} from "../lib/services/android-project-service";
29+
import {AndroidToolsInfo} from "../lib/android-tools-info";
2630
import {assert} from "chai";
2731
import * as path from "path";
2832
import * as temp from "temp";
@@ -40,13 +44,17 @@ function createTestInjector() {
4044
testInjector.register("childProcess", ChildProcess);
4145
testInjector.register("platformService", PlatformService);
4246
testInjector.register("platformsData", PlatformsData);
43-
testInjector.register("androidProjectService", {});
47+
testInjector.register("androidEmulatorServices", {});
48+
testInjector.register("androidToolsInfo", AndroidToolsInfo);
49+
testInjector.register("sysInfo", {});
50+
testInjector.register("mobileHelper", {});
51+
testInjector.register("androidProjectService", AndroidProjectService);
4452
testInjector.register("iOSProjectService", {});
4553
testInjector.register("devicesServices", {});
4654
testInjector.register("projectDataService", ProjectDataService);
4755
testInjector.register("prompter", {});
4856
testInjector.register("resources", ResourceLoader);
49-
testInjector.register("broccoliBuilder", {});
57+
testInjector.register("broccoliBuilder", Builder);
5058
testInjector.register("options", Options);
5159
testInjector.register("errors", Errors);
5260
testInjector.register("logger", stubs.LoggerStub);
@@ -71,7 +79,7 @@ function createTestInjector() {
7179
savePluginVariablesInProjectFile: (pluginData: IPluginData) => future.fromResult(),
7280
interpolatePluginVariables: (pluginData: IPluginData, pluginConfigurationFileContent: string) => future.fromResult(pluginConfigurationFileContent)
7381
});
74-
testInjector.register("npmInstallationManager", {});
82+
testInjector.register("npmInstallationManager", NpmInstallationManager);
7583

7684
return testInjector;
7785
}
@@ -87,7 +95,7 @@ function createProjectFile(testInjector: IInjector): string {
8795
"nativescript": {
8896
"id": "org.nativescript.Test",
8997
"tns-android": {
90-
"version": "1.0.0"
98+
"version": "1.4.0"
9199
}
92100
}
93101
};
@@ -203,7 +211,7 @@ describe("Plugins service", () => {
203211
});
204212
it("fails when the plugin does not support the installed framework", () => {
205213
let isWarningMessageShown = false;
206-
let expectedWarningMessage = "mySamplePlugin 1.0.1 for android is not compatible with the currently installed framework version 1.0.0.";
214+
let expectedWarningMessage = "mySamplePlugin 1.5.0 for android is not compatible with the currently installed framework version 1.4.0.";
207215

208216
// Creates plugin in temp folder
209217
let pluginName = "mySamplePlugin";
@@ -214,7 +222,7 @@ describe("Plugins service", () => {
214222
"version": "0.0.1",
215223
"nativescript": {
216224
"platforms": {
217-
"android": "1.0.1"
225+
"android": "1.5.0"
218226
}
219227
},
220228
};
@@ -557,23 +565,34 @@ describe("Plugins service", () => {
557565
// Mock platformsData
558566
let platformsData = testInjector.resolve("platformsData");
559567
platformsData.getPlatformData = (platform: string) => {
568+
let androidProjectService = testInjector.resolve("androidProjectService");
569+
560570
return {
561571
appDestinationDirectoryPath: appDestinationDirectoryPath,
562572
frameworkPackageName: "tns-android",
563573
configurationFileName: "AndroidManifest.xml",
564-
configurationFilePath: path.join(appDestinationDirectoryPath, "AndroidManifest.xml"),
574+
configurationFilePath: path.join(appDestinationDirectoryPath, "src", "main", "AndroidManifest.xml"),
575+
relativeToFrameworkConfigurationFilePath: path.join("src", "main", "AndroidManifest.xml"),
565576
mergeXmlConfig: [{ "nodename": "manifest", "attrname": "*" }],
566577
platformProjectService: {
567-
preparePluginNativeCode: (pluginData: IPluginData) => future.fromResult()
578+
preparePluginNativeCode: (pluginData: IPluginData) => future.fromResult(),
579+
interpolateConfigurationFile: () => androidProjectService.interpolateConfigurationFile()
568580
},
569581
normalizedPlatformName: "Android"
570582
};
571583
};
572584

585+
// Mock projectData
586+
let projectData = testInjector.resolve("projectData");
587+
projectData.projectId = "com.example.android.basiccontactables";
588+
573589
// Ensure the pluginDestinationPath folder exists
574590
let pluginPlatformsDirPath = path.join(projectFolder, "node_modules", pluginName, "platforms", "android");
575591
fs.ensureDirectoryExists(pluginPlatformsDirPath).wait();
576592

593+
let shelljs = require("shelljs");
594+
shelljs.cp("-R", path.join(pluginFolderPath, "*"), path.join(projectFolder, "node_modules", pluginName));
595+
577596
// Creates valid plugin's AndroidManifest.xml file
578597
let xml = '<?xml version="1.0" encoding="UTF-8"?>' +
579598
'<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >' +
@@ -584,11 +603,11 @@ describe("Plugins service", () => {
584603

585604
pluginsService.prepare(pluginJsonData).wait();
586605

587-
let expectedXml = '<?xmlversion="1.0"encoding="UTF-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.example.android.basiccontactables"android:versionCode="1"android:versionName="1.0"><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.INTERNET"/><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/Theme.Sample"><activityandroid:name="com.example.android.basiccontactables.MainActivity"android:label="@string/app_name"android:launchMode="singleTop"><meta-dataandroid:name="android.app.searchable"android:resource="@xml/searchable"/><intent-filter><actionandroid:name="android.intent.action.SEARCH"/></intent-filter><intent-filter><actionandroid:name="android.intent.action.MAIN"/></intent-filter></activity></application><uses-permissionandroid:name="android.permission.READ_CONTACTS"/></manifest>';
606+
let expectedXml = '<?xmlversion="1.0"encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.example.android.basiccontactables"android:versionCode="1"android:versionName="1.0"><supports-screensandroid:smallScreens="true"android:normalScreens="true"android:largeScreens="true"android:xlargeScreens="true"/><uses-sdkandroid:minSdkVersion="17"android:targetSdkVersion="23"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.INTERNET"/><applicationandroid:name="com.tns.NativeScriptApplication"android:allowBackup="true"android:icon="@drawable/icon"android:label="@string/app_name"android:theme="@style/AppTheme"><activityandroid:name="com.tns.NativeScriptActivity"android:label="@string/title_activity_kimera"android:configChanges="keyboardHidden|orientation|screenSize"><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity><activityandroid:name="com.tns.ErrorReportActivity"/></application><uses-permissionandroid:name="android.permission.READ_CONTACTS"/></manifest>';
588607
expectedXml = helpers.stringReplaceAll(expectedXml, EOL, "");
589608
expectedXml = helpers.stringReplaceAll(expectedXml, " ", "");
590609

591-
let actualXml = fs.readText(path.join(appDestinationDirectoryPath, "AndroidManifest.xml")).wait();
610+
let actualXml = fs.readText(path.join(appDestinationDirectoryPath, "src", "main", "AndroidManifest.xml")).wait();
592611
actualXml = helpers.stringReplaceAll(actualXml, "\n", "");
593612
actualXml = helpers.stringReplaceAll(actualXml, " ", "");
594613

0 commit comments

Comments
 (0)