Skip to content

Commit 8cb098b

Browse files
Fatme HavaluovaFatme Havaluova
Fatme Havaluova
authored and
Fatme Havaluova
committed
Gradle support
1 parent 5050178 commit 8cb098b

File tree

2 files changed

+60
-143
lines changed

2 files changed

+60
-143
lines changed

lib/services/android-project-service.ts

+60-140
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
1212
private static MIN_SUPPORTED_VERSION = 17;
1313
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21", "android-22"]; // forbidden for now: "android-MNC"
1414
private static ANDROID_TARGET_PREFIX = "android";
15-
private static RES_DIRNAME = "res";
1615
private static VALUES_DIRNAME = "values";
1716
private static VALUES_VERSION_DIRNAME_PREFIX = AndroidProjectService.VALUES_DIRNAME + "-v";
1817
private static ANDROID_PLATFORM_NAME = "android";
1918
private static LIBS_FOLDER_NAME = "libs";
2019
private static MIN_JAVA_VERSION = "1.7.0";
2120

22-
private targetApi: string;
2321
private _androidProjectPropertiesManagers: IDictionary<IAndroidProjectPropertiesManager>;
2422

2523
constructor(private $androidEmulatorServices: Mobile.IEmulatorPlatformServices,
@@ -30,6 +28,7 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
3028
private $logger: ILogger,
3129
private $options: IOptions,
3230
private $projectData: IProjectData,
31+
private $projectDataService: IProjectDataService,
3332
private $propertiesParser: IPropertiesParser,
3433
private $sysInfo: ISysInfo,
3534
$fs: IFileSystem) {
@@ -45,19 +44,21 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
4544
this._platformData = {
4645
frameworkPackageName: "tns-android",
4746
normalizedPlatformName: "Android",
48-
appDestinationDirectoryPath: path.join(projectRoot, "assets"),
49-
appResourcesDestinationDirectoryPath: path.join(projectRoot, "res"),
47+
appDestinationDirectoryPath: path.join(projectRoot, "src", "main", "assets"),
48+
appResourcesDestinationDirectoryPath: path.join(projectRoot, "src", "main", "res"),
5049
platformProjectService: this,
5150
emulatorServices: this.$androidEmulatorServices,
5251
projectRoot: projectRoot,
53-
deviceBuildOutputPath: path.join(this.$projectData.platformsDir, "android", "bin"),
52+
deviceBuildOutputPath: path.join(projectRoot, "build", "outputs", "apk"),
5453
validPackageNamesForDevice: [
5554
`${this.$projectData.projectName}-debug.apk`,
56-
`${this.$projectData.projectName}-release.apk`
55+
`${this.$projectData.projectName}-release.apk`,
56+
"android-debug.apk",
57+
"android-release.apk"
5758
],
5859
frameworkFilesExtensions: [".jar", ".dat", ".so"],
5960
configurationFileName: "AndroidManifest.xml",
60-
configurationFilePath: path.join(this.$projectData.platformsDir, "android", "AndroidManifest.xml"),
61+
configurationFilePath: path.join(projectRoot, "src", "main", "AndroidManifest.xml"),
6162
mergeXmlConfig: [{ "nodename": "manifest", "attrname": "*" }, {"nodename": "application", "attrname": "*"}]
6263
};
6364
}
@@ -80,38 +81,28 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
8081
return (() => {
8182
this.$fs.ensureDirectoryExists(projectRoot).wait();
8283

83-
let newTarget = this.getAndroidTarget(frameworkDir).wait();
84+
let newTarget = this.getAndroidTarget().wait();
8485
this.$logger.trace(`Using Android SDK '${newTarget}'.`);
8586
let versionNumber = _.last(newTarget.split("-"));
8687
if(this.$options.symlink) {
8788
this.copyResValues(projectRoot, frameworkDir, versionNumber).wait();
88-
this.copy(projectRoot, frameworkDir, ".project AndroidManifest.xml project.properties custom_rules.xml", "-f").wait();
89+
this.copy(projectRoot, frameworkDir, "AndroidManifest.xml custom_rules.xml", "-f");
8990

90-
this.symlinkDirectory("assets", projectRoot, frameworkDir).wait();
91+
this.symlinkDirectory("build-tools", projectRoot, frameworkDir).wait();
9192
this.symlinkDirectory("libs", projectRoot, frameworkDir).wait();
93+
this.symlinkDirectory("src", projectRoot, frameworkDir).wait();
9294
} else {
9395
this.copyResValues(projectRoot, frameworkDir, versionNumber).wait();
94-
this.copy(projectRoot, frameworkDir, "assets libs", "-R").wait();
95-
this.copy(projectRoot, frameworkDir, ".project AndroidManifest.xml project.properties custom_rules.xml", "-f").wait();
96+
this.copy(projectRoot, frameworkDir, "build-tools libs src", "-R");
97+
this.copy(projectRoot, frameworkDir, "build.gradle", "-f");
9698
}
97-
98-
if(newTarget) {
99-
this.updateTarget(projectRoot, newTarget).wait();
100-
}
101-
102-
// Create src folder
103-
let packageName = this.$projectData.projectId;
104-
let packageAsPath = packageName.replace(/\./g, path.sep);
105-
let activityDir = path.join(projectRoot, 'src', packageAsPath);
106-
this.$fs.createDirectory(activityDir).wait();
107-
10899
}).future<any>()();
109100
}
110101

111102
private copyResValues(projectRoot: string, frameworkDir: string, versionNumber: string): IFuture<void> {
112103
return (() => {
113-
let resSourceDir = path.join(frameworkDir, AndroidProjectService.RES_DIRNAME);
114-
let resDestinationDir = path.join(projectRoot, AndroidProjectService.RES_DIRNAME);
104+
let resSourceDir = path.join(frameworkDir, "src", "main", "res");
105+
let resDestinationDir = this.platformData.appResourcesDestinationDirectoryPath;
115106
this.$fs.createDirectory(resDestinationDir).wait();
116107
let versionDirName = AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX + versionNumber;
117108
let directoriesToCopy = [AndroidProjectService.VALUES_DIRNAME];
@@ -133,43 +124,38 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
133124
directoriesToCopy.push(versionDir);
134125
}
135126

136-
this.copy(resDestinationDir, resSourceDir, directoriesToCopy.join(" "), "-R").wait();
127+
this.copy(resDestinationDir, resSourceDir, directoriesToCopy.join(" "), "-R");
137128
}).future<void>()();
138129
}
139130

140131
public interpolateData(projectRoot: string): IFuture<void> {
141132
return (() => {
142133
// Interpolate the activity name and package
143-
let manifestPath = path.join(projectRoot, "AndroidManifest.xml");
134+
let manifestPath = this.platformData.configurationFilePath;
144135
shell.sed('-i', /__PACKAGE__/, this.$projectData.projectId, manifestPath);
145-
shell.sed('-i', /__APILEVEL__/, this.getTarget(projectRoot).wait().split('-')[1], manifestPath);
136+
shell.sed('-i', /__APILEVEL__/, this.getApiLevel().wait(), manifestPath);
146137

147-
let stringsFilePath = path.join(projectRoot, 'res', 'values', 'strings.xml');
138+
let stringsFilePath = path.join(this.platformData.appResourcesDestinationDirectoryPath, 'values', 'strings.xml');
148139
shell.sed('-i', /__NAME__/, this.$projectData.projectName, stringsFilePath);
149140
shell.sed('-i', /__TITLE_ACTIVITY__/, this.$projectData.projectName, stringsFilePath);
150-
shell.sed('-i', /__NAME__/, this.$projectData.projectName, path.join(projectRoot, '.project'));
151141
}).future<void>()();
152142
}
153143

154144
public afterCreateProject(projectRoot: string): IFuture<void> {
155145
return (() => {
156-
let targetApi = this.getTarget(projectRoot).wait();
157-
this.$logger.trace("Android target: %s", targetApi);
158-
this.runAndroidUpdate(projectRoot, targetApi).wait();
159-
this.adjustMinSdk(projectRoot);
146+
let targetApi = this.getAndroidTarget().wait();
147+
this.$logger.trace(`Adroid target: ${targetApi}`);
148+
this.adjustMinSdk(projectRoot).wait();
160149
}).future<void>()();
161150
}
162151

163-
private adjustMinSdk(projectRoot: string): void {
164-
let manifestPath = path.join(projectRoot, "AndroidManifest.xml");
165-
let apiLevel = this.getTarget(projectRoot).wait().split('-')[1];
166-
if (apiLevel === "MNC") { // MNC SDK requires that minSdkVersion is set to "MNC"
167-
shell.sed('-i', /android:minSdkVersion=".*?"/, `android:minSdkVersion="${apiLevel}"`, manifestPath);
168-
}
169-
}
170-
171-
public getDebugOnDeviceSetup(): Mobile.IDebugOnDeviceSetup {
172-
return { };
152+
private adjustMinSdk(projectRoot: string): IFuture<void> {
153+
return (() => {
154+
let apiLevel = this.getApiLevel().wait();
155+
if (apiLevel === "MNC") { // MNC SDK requires that minSdkVersion is set to "MNC"
156+
shell.sed('-i', /android:minSdkVersion=".*?"/, `android:minSdkVersion="${apiLevel}"`, this.platformData.configurationFilePath);
157+
}
158+
}).future<void>()();
173159
}
174160

175161
public canUpdatePlatform(currentVersion: string, newVersion: string): IFuture<boolean> {
@@ -181,13 +167,29 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
181167
}
182168

183169
public buildProject(projectRoot: string): IFuture<void> {
184-
let buildConfiguration = this.$options.release ? "release" : "debug";
185-
let args = this.getAntArgs(buildConfiguration, projectRoot);
186-
return this.spawn('ant', args);
170+
return (() => {
171+
this.$projectDataService.initialize(this.$projectData.projectDir);
172+
let frameworkVersion = this.$projectDataService.getValue(this.platformData.frameworkPackageName).wait().version;
173+
if(semver.lt(frameworkVersion, "1.3.0")) {
174+
let args = this.getAntArgs(this.$options.release ? "release" : "debug", projectRoot);
175+
this.spawn('ant', args).wait();
176+
} else { // Gradle build
177+
let buildOptions = ["buildapk"];
178+
if(this.$options.release) {
179+
buildOptions.push("-Prelease");
180+
buildOptions.push(`-PksPath=${this.$options.keyStorePath}`);
181+
buildOptions.push(`-PksPassword=${this.$options.keyStorePassword}`);
182+
buildOptions.push(`-Palias=${this.$options.keyStoreAlias}`);
183+
buildOptions.push(`-Ppass=${this.$options.keyStoreAliasPassword}`);
184+
}
185+
186+
this.$childProcess.spawnFromEvent("gradle", buildOptions, "close", { stdio: "inherit", cwd: this.platformData.projectRoot }).wait();
187+
}
188+
}).future<void>()();
187189
}
188190

189191
public isPlatformPrepared(projectRoot: string): IFuture<boolean> {
190-
return this.$fs.exists(path.join(projectRoot, "assets", constants.APP_FOLDER_NAME));
192+
return this.$fs.exists(path.join(this.platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME));
191193
}
192194

193195
private getProjectPropertiesManager(filePath: string): IAndroidProjectPropertiesManager {
@@ -197,32 +199,6 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
197199

198200
return this._androidProjectPropertiesManagers[filePath];
199201
}
200-
201-
private parseProjectProperties(projDir: string, destDir: string): IFuture<void> { // projDir is libraryPath, targetPath is the path to lib folder
202-
return (() => {
203-
projDir = projDir.trim();
204-
let projProp = path.join(projDir, "project.properties");
205-
if (!this.$fs.exists(projProp).wait()) {
206-
this.$logger.warn("Warning: File %s does not exist", projProp);
207-
return;
208-
}
209-
210-
let projectPropertiesManager = this.getProjectPropertiesManager(projDir);
211-
let references = projectPropertiesManager.getProjectReferences().wait();
212-
_.each(references, reference => {
213-
let adjustedPath = this.$fs.isRelativePath(reference.path) ? path.join(projDir, reference.path) : reference.path;
214-
this.parseProjectProperties(adjustedPath, destDir).wait();
215-
});
216-
217-
this.$logger.info("Copying %s", projDir);
218-
shell.cp("-Rf", projDir, destDir);
219-
220-
let targetDir = path.join(destDir, path.basename(projDir));
221-
let targetSdk = `android-${this.$options.sdk || AndroidProjectService.MIN_SUPPORTED_VERSION}`;
222-
this.$logger.info("Generate build.xml for %s", targetDir);
223-
this.runAndroidUpdate(targetDir, targetSdk).wait();
224-
}).future<void>()();
225-
}
226202

227203
public addLibrary(libraryPath: string): IFuture<void> {
228204
return (() => {
@@ -232,20 +208,10 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
232208
let targetPath = path.dirname(targetLibPath);
233209
this.$fs.ensureDirectoryExists(targetPath).wait();
234210

235-
if(this.$fs.exists(path.join(libraryPath, "project.properties")).wait()) {
236-
this.parseProjectProperties(libraryPath, targetPath).wait();
237-
}
238-
239211
shell.cp("-f", path.join(libraryPath, "*.jar"), targetPath);
240212
let projectLibsDir = path.join(this.platformData.projectRoot, "libs");
241213
this.$fs.ensureDirectoryExists(projectLibsDir).wait();
242214
shell.cp("-f", path.join(libraryPath, "*.jar"), projectLibsDir);
243-
244-
let libProjProp = path.join(libraryPath, "project.properties");
245-
if (this.$fs.exists(libProjProp).wait()) {
246-
this.updateProjectReferences(this.platformData.projectRoot, targetLibPath).wait();
247-
this.runAndroidUpdate(targetLibPath, this.getTarget(this.platformData.projectRoot).wait()).wait();
248-
}
249215
}).future<void>()();
250216
}
251217

@@ -311,25 +277,16 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
311277
return path.join(this.$projectData.projectDir, "lib", this.platformData.normalizedPlatformName, libraryName);
312278
}
313279

314-
private updateProjectReferences(projDir: string, libraryPath: string): IFuture<void> {
315-
let relLibDir = this.getLibraryRelativePath(projDir, libraryPath);
316-
317-
let projectPropertiesManager = this.getProjectPropertiesManager(projDir);
318-
return projectPropertiesManager.addProjectReference(relLibDir);
319-
}
320-
321280
private getAllLibrariesForPlugin(pluginData: IPluginData): IFuture<string[]> {
322281
return (() => {
323282
let filterCallback = (fileName: string, pluginPlatformsFolderPath: string) => fileName !== AndroidProjectService.LIBS_FOLDER_NAME && this.$fs.exists(path.join(pluginPlatformsFolderPath, fileName, "project.properties")).wait();
324283
return this.getAllNativeLibrariesForPlugin(pluginData, AndroidProjectService.ANDROID_PLATFORM_NAME, filterCallback).wait();
325284
}).future<string[]>()();
326285
}
327286

328-
private copy(projectRoot: string, frameworkDir: string, files: string, cpArg: string): IFuture<void> {
329-
return (() => {
330-
let paths = files.split(' ').map(p => path.join(frameworkDir, p));
331-
shell.cp(cpArg, paths, projectRoot);
332-
}).future<void>()();
287+
private copy(projectRoot: string, frameworkDir: string, files: string, cpArg: string): void {
288+
let paths = files.split(' ').map(p => path.join(frameworkDir, p));
289+
shell.cp(cpArg, paths, projectRoot);
333290
}
334291

335292
private spawn(command: string, args: string[]): IFuture<void> {
@@ -367,16 +324,6 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
367324
return args;
368325
}
369326

370-
private runAndroidUpdate(projectPath: string, targetApi: string): IFuture<void> {
371-
let args = [
372-
"--path", projectPath,
373-
"--target", targetApi,
374-
"--name", this.$projectData.projectName
375-
];
376-
377-
return this.spawn("android", ['update', 'project'].concat(args));
378-
}
379-
380327
private validatePackageName(packageName: string): void {
381328
//Make the package conform to Java package types
382329
//Enforce underscore limitation
@@ -401,9 +348,9 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
401348
}
402349
}
403350

404-
private getAndroidTarget(frameworkDir: string): IFuture<string> {
351+
private getAndroidTarget(): IFuture<string> {
405352
return ((): string => {
406-
let newTarget = this.$options.sdk ? `${AndroidProjectService.ANDROID_TARGET_PREFIX}-${this.$options.sdk}` : this.getLatestValidAndroidTarget(frameworkDir).wait();
353+
let newTarget = this.$options.sdk ? `${AndroidProjectService.ANDROID_TARGET_PREFIX}-${this.$options.sdk}` : this.getLatestValidAndroidTarget().wait();
407354
if(!_.contains(this.SUPPORTED_TARGETS, newTarget)) {
408355
let versionNumber = parseInt(_.last(newTarget.split("-")));
409356
if(versionNumber && (versionNumber < AndroidProjectService.MIN_SUPPORTED_VERSION)) {
@@ -421,7 +368,7 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
421368
}).future<string>()();
422369
}
423370

424-
private getLatestValidAndroidTarget(frameworkDir: string): IFuture<string> {
371+
private getLatestValidAndroidTarget(): IFuture<string> {
425372
return (() => {
426373
let installedTargets = this.getInstalledTargets().wait();
427374

@@ -436,23 +383,11 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
436383
return newTarget;
437384
}).future<string>()();
438385
}
439-
440-
private updateTarget(projectRoot: string, newTarget: string): IFuture<void> {
386+
387+
private getApiLevel(): IFuture<string> {
441388
return (() => {
442-
let file = path.join(projectRoot, "project.properties");
443-
let editor = this.$propertiesParser.createEditor(file).wait();
444-
editor.set("target", newTarget);
445-
let future = new Future<void>();
446-
editor.save((err:any) => {
447-
if (err) {
448-
future.throw(err);
449-
} else {
450-
this.targetApi = null; // so that later we can repopulate the cache
451-
future.return();
452-
}
453-
});
454-
future.wait();
455-
}).future<void>()();
389+
return this.getAndroidTarget().wait().split('-')[1];
390+
}).future<string>()();
456391
}
457392

458393
private installedTargetsCache: string[] = null;
@@ -466,21 +401,6 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
466401
return this.installedTargetsCache;
467402
}).future<string[]>()();
468403
}
469-
470-
private getTarget(projectRoot: string): IFuture<string> {
471-
return (() => {
472-
if(!this.targetApi) {
473-
let projectPropertiesFilePath = path.join(projectRoot, "project.properties");
474-
475-
if (this.$fs.exists(projectPropertiesFilePath).wait()) {
476-
let properties = this.$propertiesParser.createEditor(projectPropertiesFilePath).wait();
477-
this.targetApi = properties.get("target");
478-
}
479-
}
480-
481-
return this.targetApi;
482-
}).future<string>()();
483-
}
484404

485405
private checkJava(): IFuture<void> {
486406
return (() => {

test/stubs.ts

-3
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,6 @@ export class PlatformProjectServiceStub implements IPlatformProjectService {
301301
addLibrary(libraryPath: string): IFuture<void> {
302302
return Future.fromResult();
303303
}
304-
getDebugOnDeviceSetup(): Mobile.IDebugOnDeviceSetup {
305-
return null;
306-
}
307304
canUpdatePlatform(currentVersion: string, newVersion: string): IFuture<boolean> {
308305
return Future.fromResult(false);
309306
}

0 commit comments

Comments
 (0)