Skip to content

Commit 17b3acb

Browse files
committed
Support for android MNC
Whitelist MNC SDK change all vars to lets When building with MNC SDK, change minSdkVersion to be MNC, required for succesful build See #507
1 parent 8309939 commit 17b3acb

File tree

2 files changed

+73
-70
lines changed

2 files changed

+73
-70
lines changed

lib/services/android-project-service.ts

Lines changed: 72 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import fs = require("fs");
1010
import os = require("os");
1111

1212
class AndroidProjectService implements IPlatformProjectService {
13-
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21"];
14-
private static METADATA_DIRNAME = "__metadata";
13+
private SUPPORTED_TARGETS = ["android-17", "android-18", "android-19", "android-21", "android-MNC"];
1514
private static RES_DIRNAME = "res";
1615
private static VALUES_DIRNAME = "values";
1716
private static VALUES_VERSION_DIRNAME_PREFIX = AndroidProjectService.VALUES_DIRNAME + "-v";
@@ -32,7 +31,7 @@ class AndroidProjectService implements IPlatformProjectService {
3231
private _platformData: IPlatformData = null;
3332
public get platformData(): IPlatformData {
3433
if (!this._platformData) {
35-
var projectRoot = path.join(this.$projectData.platformsDir, "android");
34+
let projectRoot = path.join(this.$projectData.platformsDir, "android");
3635

3736
this._platformData = {
3837
frameworkPackageName: "tns-android",
@@ -66,8 +65,8 @@ class AndroidProjectService implements IPlatformProjectService {
6665
public createProject(projectRoot: string, frameworkDir: string): IFuture<void> {
6766
return (() => {
6867
this.$fs.ensureDirectoryExists(projectRoot).wait();
69-
var newTarget = this.getLatestValidAndroidTarget(frameworkDir).wait();
70-
var versionNumber = _.last(newTarget.split("-"));
68+
let newTarget = this.getLatestValidAndroidTarget(frameworkDir).wait();
69+
let versionNumber = _.last(newTarget.split("-"));
7170
if(this.$options.symlink) {
7271
this.copyResValues(projectRoot, frameworkDir, versionNumber).wait();
7372
this.copy(projectRoot, frameworkDir, ".project AndroidManifest.xml project.properties custom_rules.xml", "-f").wait();
@@ -85,21 +84,21 @@ class AndroidProjectService implements IPlatformProjectService {
8584
}
8685

8786
// Create src folder
88-
var packageName = this.$projectData.projectId;
89-
var packageAsPath = packageName.replace(/\./g, path.sep);
90-
var activityDir = path.join(projectRoot, 'src', packageAsPath);
87+
let packageName = this.$projectData.projectId;
88+
let packageAsPath = packageName.replace(/\./g, path.sep);
89+
let activityDir = path.join(projectRoot, 'src', packageAsPath);
9190
this.$fs.createDirectory(activityDir).wait();
9291

9392
}).future<any>()();
9493
}
9594

9695
private copyResValues(projectRoot: string, frameworkDir: string, versionNumber: string): IFuture<void> {
9796
return (() => {
98-
var resSourceDir = path.join(frameworkDir, AndroidProjectService.RES_DIRNAME);
99-
var resDestinationDir = path.join(projectRoot, AndroidProjectService.RES_DIRNAME);
97+
let resSourceDir = path.join(frameworkDir, AndroidProjectService.RES_DIRNAME);
98+
let resDestinationDir = path.join(projectRoot, AndroidProjectService.RES_DIRNAME);
10099
this.$fs.createDirectory(resDestinationDir).wait();
101-
var versionDirName = AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX + versionNumber;
102-
var directoriesToCopy = [AndroidProjectService.VALUES_DIRNAME];
100+
let versionDirName = AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX + versionNumber;
101+
let directoriesToCopy = [AndroidProjectService.VALUES_DIRNAME];
103102
if(this.$fs.exists(path.join(resSourceDir, versionDirName)).wait()) {
104103
directoriesToCopy.push(versionDirName);
105104
}
@@ -111,27 +110,35 @@ class AndroidProjectService implements IPlatformProjectService {
111110
public interpolateData(projectRoot: string): IFuture<void> {
112111
return (() => {
113112
// Interpolate the activity name and package
114-
var manifestPath = path.join(projectRoot, "AndroidManifest.xml");
115-
var safeActivityName = this.$projectData.projectName.replace(/\W/g, '');
113+
let manifestPath = path.join(projectRoot, "AndroidManifest.xml");
114+
let safeActivityName = this.$projectData.projectName.replace(/\W/g, '');
116115
shell.sed('-i', /__PACKAGE__/, this.$projectData.projectId, manifestPath);
117116
shell.sed('-i', /__APILEVEL__/, this.getTarget(projectRoot).wait().split('-')[1], manifestPath);
118117

119-
var stringsFilePath = path.join(projectRoot, 'res', 'values', 'strings.xml');
118+
let stringsFilePath = path.join(projectRoot, 'res', 'values', 'strings.xml');
120119
shell.sed('-i', /__NAME__/, this.$projectData.projectName, stringsFilePath);
121120
shell.sed('-i', /__TITLE_ACTIVITY__/, this.$projectData.projectName, stringsFilePath);
122121
shell.sed('-i', /__NAME__/, this.$projectData.projectName, path.join(projectRoot, '.project'));
123-
124122
}).future<void>()();
125123
}
126124

127125
public afterCreateProject(projectRoot: string): IFuture<void> {
128126
return (() => {
129-
var targetApi = this.getTarget(projectRoot).wait();
127+
let targetApi = this.getTarget(projectRoot).wait();
130128
this.$logger.trace("Android target: %s", targetApi);
131129
this.runAndroidUpdate(projectRoot, targetApi).wait();
130+
this.adjustMinSdk(projectRoot);
132131
}).future<void>()();
133132
}
134133

134+
private adjustMinSdk(projectRoot: string): void {
135+
let manifestPath = path.join(projectRoot, "AndroidManifest.xml");
136+
let apiLevel = this.getTarget(projectRoot).wait().split('-')[1];
137+
if (apiLevel === "MNC") { // MNC SDK requires that minSdkVersion is set to "MNC"
138+
shell.sed('-i', /android:minSdkVersion=".*?"/, `android:minSdkVersion="${apiLevel}"`, manifestPath);
139+
}
140+
}
141+
135142
public getDebugOnDeviceSetup(): Mobile.IDebugOnDeviceSetup {
136143
return { };
137144
}
@@ -145,32 +152,30 @@ class AndroidProjectService implements IPlatformProjectService {
145152
}
146153

147154
public buildProject(projectRoot: string): IFuture<void> {
148-
return (() => {
149-
var buildConfiguration = this.$options.release ? "release" : "debug";
150-
var args = this.getAntArgs(buildConfiguration, projectRoot);
151-
this.spawn('ant', args).wait();
152-
}).future<void>()();
155+
let buildConfiguration = this.$options.release ? "release" : "debug";
156+
let args = this.getAntArgs(buildConfiguration, projectRoot);
157+
return this.spawn('ant', args);
153158
}
154159

155160
public isPlatformPrepared(projectRoot: string): IFuture<boolean> {
156161
return this.$fs.exists(path.join(projectRoot, "assets", constants.APP_FOLDER_NAME));
157162
}
158163

159164
private parseProjectProperties(projDir: string, destDir: string): void {
160-
var projProp = path.join(projDir, "project.properties");
165+
let projProp = path.join(projDir, "project.properties");
161166

162167
if (!this.$fs.exists(projProp).wait()) {
163168
this.$logger.warn("Warning: File %s does not exist", projProp);
164169
return;
165170
}
166171

167-
var lines = this.$fs.readText(projProp, "utf-8").wait().split(os.EOL);
172+
let lines = this.$fs.readText(projProp, "utf-8").wait().split(os.EOL);
168173

169-
var regEx = /android\.library\.reference\.(\d+)=(.*)/;
174+
let regEx = /android\.library\.reference\.(\d+)=(.*)/;
170175
lines.forEach(elem => {
171-
var match = elem.match(regEx);
176+
let match = elem.match(regEx);
172177
if (match) {
173-
var libRef: ILibRef = { idx: parseInt(match[1]), path: match[2].trim() };
178+
let libRef: ILibRef = { idx: parseInt(match[1]), path: match[2].trim() };
174179
libRef.adjustedPath = this.$fs.isRelativePath(libRef.path) ? path.join(projDir, libRef.path) : libRef.path;
175180
this.parseProjectProperties(libRef.adjustedPath, destDir);
176181
}
@@ -179,25 +184,25 @@ class AndroidProjectService implements IPlatformProjectService {
179184
this.$logger.info("Copying %s", projDir);
180185
shell.cp("-Rf", projDir, destDir);
181186

182-
var targetDir = path.join(destDir, path.basename(projDir));
187+
let targetDir = path.join(destDir, path.basename(projDir));
183188
// TODO: parametrize targetSdk
184-
var targetSdk = "android-17";
189+
let targetSdk = "android-17";
185190
this.$logger.info("Generate build.xml for %s", targetDir);
186191
this.runAndroidUpdate(targetDir, targetSdk).wait();
187192
}
188193

189194
private getProjectReferences(projDir: string): ILibRef[]{
190-
var projProp = path.join(projDir, "project.properties");
195+
let projProp = path.join(projDir, "project.properties");
191196

192-
var lines = this.$fs.readText(projProp, "utf-8").wait().split(os.EOL);
197+
let lines = this.$fs.readText(projProp, "utf-8").wait().split(os.EOL);
193198

194-
var refs: ILibRef[] = [];
199+
let refs: ILibRef[] = [];
195200

196-
var regEx = /android\.library\.reference\.(\d+)=(.*)/;
201+
let regEx = /android\.library\.reference\.(\d+)=(.*)/;
197202
lines.forEach(elem => {
198-
var match = elem.match(regEx);
203+
let match = elem.match(regEx);
199204
if (match) {
200-
var libRef: ILibRef = { idx: parseInt(match[1]), path: match[2] };
205+
let libRef: ILibRef = { idx: parseInt(match[1]), path: match[2] };
201206
libRef.adjustedPath = path.join(projDir, libRef.path);
202207
refs.push(libRef);
203208
}
@@ -207,37 +212,37 @@ class AndroidProjectService implements IPlatformProjectService {
207212
}
208213

209214
private updateProjectReferences(projDir: string, libraryPath: string): void {
210-
var refs = this.getProjectReferences(projDir);
211-
var maxIdx = refs.length > 0 ? _.max(refs, r => r.idx).idx : 0;
215+
let refs = this.getProjectReferences(projDir);
216+
let maxIdx = refs.length > 0 ? _.max(refs, r => r.idx).idx : 0;
212217

213-
var relLibDir = path.relative(projDir, libraryPath).split("\\").join("/");
218+
let relLibDir = path.relative(projDir, libraryPath).split("\\").join("/");
214219

215-
var libRefExists = _.any(refs, r => path.normalize(r.path) === path.normalize(relLibDir));
220+
let libRefExists = _.any(refs, r => path.normalize(r.path) === path.normalize(relLibDir));
216221

217222
if (!libRefExists) {
218-
var projRef = util.format("%sandroid.library.reference.%d=%s", os.EOL, maxIdx + 1, relLibDir);
219-
var projProp = path.join(projDir, "project.properties");
223+
let projRef = util.format("%sandroid.library.reference.%d=%s", os.EOL, maxIdx + 1, relLibDir);
224+
let projProp = path.join(projDir, "project.properties");
220225
fs.appendFileSync(projProp, projRef, { encoding: "utf-8" });
221226
}
222227
}
223228

224229
public addLibrary(platformData: IPlatformData, libraryPath: string): IFuture<void> {
225230
return (() => {
226-
var name = path.basename(libraryPath);
227-
var projDir = this.$projectData.projectDir;
228-
var targetPath = path.join(projDir, "lib", platformData.normalizedPlatformName);
231+
let name = path.basename(libraryPath);
232+
let projDir = this.$projectData.projectDir;
233+
let targetPath = path.join(projDir, "lib", platformData.normalizedPlatformName);
229234
this.$fs.ensureDirectoryExists(targetPath).wait();
230235

231236
this.parseProjectProperties(libraryPath, targetPath);
232237

233238
shell.cp("-f", path.join(libraryPath, "*.jar"), targetPath);
234-
var projectLibsDir = path.join(platformData.projectRoot, "libs");
239+
let projectLibsDir = path.join(platformData.projectRoot, "libs");
235240
this.$fs.ensureDirectoryExists(projectLibsDir).wait();
236241
shell.cp("-f", path.join(libraryPath, "*.jar"), projectLibsDir);
237242

238-
var targetLibPath = path.join(targetPath, path.basename(libraryPath));
243+
let targetLibPath = path.join(targetPath, path.basename(libraryPath));
239244

240-
var libProjProp = path.join(libraryPath, "project.properties");
245+
let libProjProp = path.join(libraryPath, "project.properties");
241246
if (this.$fs.exists(libProjProp).wait()) {
242247
this.updateProjectReferences(platformData.projectRoot, targetLibPath);
243248
}
@@ -250,7 +255,7 @@ class AndroidProjectService implements IPlatformProjectService {
250255

251256
private copy(projectRoot: string, frameworkDir: string, files: string, cpArg: string): IFuture<void> {
252257
return (() => {
253-
var paths = files.split(' ').map(p => path.join(frameworkDir, p));
258+
let paths = files.split(' ').map(p => path.join(frameworkDir, p));
254259
shell.cp(cpArg, paths, projectRoot);
255260
}).future<void>()();
256261
}
@@ -265,7 +270,7 @@ class AndroidProjectService implements IPlatformProjectService {
265270
}
266271

267272
private getAntArgs(configuration: string, projectRoot: string): string[] {
268-
var args = [configuration, "-f", path.join(projectRoot, "build.xml")];
273+
let args = [configuration, "-f", path.join(projectRoot, "build.xml")];
269274
if(configuration === "release") {
270275
if(this.$options.keyStorePath) {
271276
args = args.concat(["-Dkey.store", this.$options.keyStorePath]);
@@ -291,15 +296,13 @@ class AndroidProjectService implements IPlatformProjectService {
291296
}
292297

293298
private runAndroidUpdate(projectPath: string, targetApi: string): IFuture<void> {
294-
return (() => {
295-
var args = [
296-
"--path", projectPath,
297-
"--target", targetApi,
298-
"--name", this.$projectData.projectName
299-
];
299+
let args = [
300+
"--path", projectPath,
301+
"--target", targetApi,
302+
"--name", this.$projectData.projectName
303+
];
300304

301-
this.spawn("android", ['update', 'project'].concat(args)).wait();
302-
}).future<void>()();
305+
return this.spawn("android", ['update', 'project'].concat(args));
303306
}
304307

305308
private validatePackageName(packageName: string): void {
@@ -328,8 +331,8 @@ class AndroidProjectService implements IPlatformProjectService {
328331

329332
private getLatestValidAndroidTarget(frameworkDir: string): IFuture<string> {
330333
return (() => {
331-
var validTarget = this.getTarget(frameworkDir).wait();
332-
var installedTargets = this.getInstalledTargets().wait();
334+
let validTarget = this.getTarget(frameworkDir).wait();
335+
let installedTargets = this.getInstalledTargets().wait();
333336

334337
// adjust to the latest available version
335338
var newTarget = _(this.SUPPORTED_TARGETS).sort().findLast(supportedTarget => _.contains(installedTargets, supportedTarget));
@@ -345,10 +348,10 @@ class AndroidProjectService implements IPlatformProjectService {
345348

346349
private updateTarget(projectRoot: string, newTarget: string): IFuture<void> {
347350
return (() => {
348-
var file = path.join(projectRoot, "project.properties");
349-
var editor = this.$propertiesParser.createEditor(file).wait();
351+
let file = path.join(projectRoot, "project.properties");
352+
let editor = this.$propertiesParser.createEditor(file).wait();
350353
editor.set("target", newTarget);
351-
var future = new Future<void>();
354+
let future = new Future<void>();
352355
editor.save((err:any) => {
353356
if (err) {
354357
future.throw(err);
@@ -366,7 +369,7 @@ class AndroidProjectService implements IPlatformProjectService {
366369
return (() => {
367370
if (!this.installedTargetsCache) {
368371
this.installedTargetsCache = [];
369-
var output = this.$childProcess.exec('android list targets').wait();
372+
let output = this.$childProcess.exec('android list targets').wait();
370373
output.replace(/id: \d+ or "(.+)"/g, (m:string, p1:string) => (this.installedTargetsCache.push(p1), m));
371374
}
372375
return this.installedTargetsCache;
@@ -376,10 +379,10 @@ class AndroidProjectService implements IPlatformProjectService {
376379
private getTarget(projectRoot: string): IFuture<string> {
377380
return (() => {
378381
if(!this.targetApi) {
379-
var projectPropertiesFilePath = path.join(projectRoot, "project.properties");
382+
let projectPropertiesFilePath = path.join(projectRoot, "project.properties");
380383

381384
if (this.$fs.exists(projectPropertiesFilePath).wait()) {
382-
var properties = this.$propertiesParser.createEditor(projectPropertiesFilePath).wait();
385+
let properties = this.$propertiesParser.createEditor(projectPropertiesFilePath).wait();
383386
this.targetApi = properties.get("target");
384387
}
385388
}
@@ -393,7 +396,7 @@ class AndroidProjectService implements IPlatformProjectService {
393396
try {
394397
this.$childProcess.exec("ant -version").wait();
395398
} catch(error) {
396-
this.$errors.fail("Error executing commands 'ant', make sure you have ant installed and added to your PATH.")
399+
this.$errors.fail("Error executing commands 'ant', make sure you have ant installed and added to your PATH.");
397400
}
398401
}).future<void>()();
399402
}
@@ -415,11 +418,11 @@ class AndroidProjectService implements IPlatformProjectService {
415418
private symlinkDirectory(directoryName: string, projectRoot: string, frameworkDir: string): IFuture<void> {
416419
return (() => {
417420
this.$fs.createDirectory(path.join(projectRoot, directoryName)).wait();
418-
var directoryContent = this.$fs.readDirectory(path.join(frameworkDir, directoryName)).wait();
421+
let directoryContent = this.$fs.readDirectory(path.join(frameworkDir, directoryName)).wait();
419422

420423
_.each(directoryContent, (file: string) => {
421-
var sourceFilePath = path.join(frameworkDir, directoryName, file);
422-
var destinationFilePath = path.join(projectRoot, directoryName, file);
424+
let sourceFilePath = path.join(frameworkDir, directoryName, file);
425+
let destinationFilePath = path.join(projectRoot, directoryName, file);
423426
if(this.$fs.getFsStats(sourceFilePath).wait().isFile()) {
424427
this.$fs.symlink(sourceFilePath, destinationFilePath).wait();
425428
} else {

0 commit comments

Comments
 (0)