Skip to content

Commit 76d8967

Browse files
committed
Allow updating target android sdk during "platform add"
The tns-android template uses by default sdk 17. If the user does not have it installed, we try to update it. To do so safely, we have a white list of well-tested sdks. We match the white list with the installed sdks and take the newest one. This commit depends on https://github.com/telerik/tns-android/commit/990f725d845364e33ca77d4e54212e0c2342bc55 Implements #173
1 parent 64bc613 commit 76d8967

File tree

1 file changed

+57
-7
lines changed

1 file changed

+57
-7
lines changed

lib/services/android-project-service.ts

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
import path = require("path");
44
import shell = require("shelljs");
55
import util = require("util");
6+
import Future = require("fibers/future");
67
import options = require("./../options");
78
import constants = require("./../constants");
89
import hostInfo = require("../common/host-info");
910
import helpers = require("./../common/helpers");
1011

1112
class AndroidProjectService implements IPlatformProjectService {
13+
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21"];
1214
private targetApi: string;
1315

1416
constructor(private $androidEmulatorServices: Mobile.IEmulatorPlatformServices,
@@ -50,7 +52,7 @@ class AndroidProjectService implements IPlatformProjectService {
5052
return (() => {
5153
this.$fs.ensureDirectoryExists(projectRoot).wait();
5254

53-
this.validateAndroidTarget(frameworkDir); // We need framework to be installed to validate android target so we can't call this method in validate()
55+
var newTarget = this.validateAndroidTarget(frameworkDir); // We need framework to be installed to validate android target so we can't call this method in validate()
5456

5557
if(options.symlink) {
5658
this.copy(projectRoot, frameworkDir, "res", "-R").wait();
@@ -63,6 +65,10 @@ class AndroidProjectService implements IPlatformProjectService {
6365
this.copy(projectRoot, frameworkDir, ".project AndroidManifest.xml project.properties", "-f").wait();
6466
}
6567

68+
if(newTarget) {
69+
this.updateTarget(projectRoot, newTarget).wait();
70+
}
71+
6672
// Create src folder
6773
var packageName = this.$projectData.projectId;
6874
var packageAsPath = packageName.replace(/\./g, path.sep);
@@ -78,7 +84,6 @@ class AndroidProjectService implements IPlatformProjectService {
7884
var manifestPath = path.join(projectRoot, "AndroidManifest.xml");
7985
var safeActivityName = this.$projectData.projectName.replace(/\W/g, '');
8086
shell.sed('-i', /__PACKAGE__/, this.$projectData.projectId, manifestPath);
81-
shell.sed('-i', /__ACTIVITY__/, safeActivityName, manifestPath);
8287
shell.sed('-i', /__APILEVEL__/, this.getTarget(projectRoot).wait().split('-')[1], manifestPath);
8388

8489
var stringsFilePath = path.join(projectRoot, 'res', 'values', 'strings.xml');
@@ -196,13 +201,58 @@ class AndroidProjectService implements IPlatformProjectService {
196201
}
197202
}
198203

199-
private validateAndroidTarget(frameworkDir: string) {
204+
private validateAndroidTarget(frameworkDir: string): string {
200205
var validTarget = this.getTarget(frameworkDir).wait();
201-
var output = this.$childProcess.exec('android list targets').wait();
202-
if (!output.match(validTarget)) {
203-
this.$errors.fail("Please install Android target %s the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.",
204-
validTarget.split('-')[1]);
206+
var installedTargets = this.getInstalledTargets().wait();
207+
var newTarget: string = undefined;
208+
var match = _.contains(installedTargets, validTarget);
209+
if (!match) {
210+
// adjust to the latest available version
211+
newTarget = this.getCompatibleTarget();
212+
if (!newTarget) {
213+
this.$errors.fail("Please install Android target %s. Make sure you have the latest Android tools installed as well." +
214+
" Run \"android\" from your command-line to install/update any missing SDKs or tools.",
215+
validTarget.split('-')[1]);
216+
}
205217
}
218+
219+
return newTarget;
220+
}
221+
222+
private getCompatibleTarget(): string {
223+
var installedTargets = this.getInstalledTargets().wait();
224+
var compatibleTarget = _(this.SUPPORTED_TARGETS).sort().findLast(supportedTarget => _.contains(installedTargets, supportedTarget));
225+
return compatibleTarget;
226+
}
227+
228+
private updateTarget(projectRoot: string, newTarget: string): IFuture<void> {
229+
return (() => {
230+
var file = path.join(projectRoot, "project.properties");
231+
var editor = this.$propertiesParser.createEditor(file).wait();
232+
editor.set("target", newTarget);
233+
var future = new Future<void>();
234+
editor.save((err:any) => {
235+
if (err) {
236+
future.throw(err);
237+
} else {
238+
this.targetApi = null; // so that later we can repopulate the cache
239+
future.return();
240+
}
241+
});
242+
future.wait();
243+
}).future<void>()();
244+
}
245+
246+
private installedTargetsCache: string[] = null;
247+
private getInstalledTargets(): IFuture<string[]> {
248+
return (() => {
249+
if (!this.installedTargetsCache) {
250+
this.installedTargetsCache = [];
251+
var output = this.$childProcess.exec('android list targets').wait();
252+
output.replace(/id: \d+ or "(.+)"/g, (m:string, p1:string) => (this.installedTargetsCache.push(p1), m));
253+
}
254+
return this.installedTargetsCache;
255+
}).future<string[]>()();
206256
}
207257

208258
private getTarget(projectRoot: string): IFuture<string> {

0 commit comments

Comments
 (0)