Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

Commit 2b77549

Browse files
author
Dimitar Tachev
authored
Merge pull request #1063 from NativeScript/tachev/aab-improvements
feat: support useLibs though env.compileSnapshot and calculate the NDK path internally
2 parents 2f315a4 + b0436cd commit 2b77549

File tree

9 files changed

+138
-136
lines changed

9 files changed

+138
-136
lines changed

androidProjectHelpers.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ const getMksnapshotParams = (projectDir) => {
4747
}
4848
};
4949

50+
const getRuntimeNdkRevision = (projectDir) => {
51+
try {
52+
const androidSettingsJSON = getAndroidSettingsJson(projectDir);
53+
const result = androidSettingsJSON && androidSettingsJSON.ndkRevision;
54+
return result;
55+
} catch (e) {
56+
return null;
57+
}
58+
};
59+
5060
const getAndroidSettingsJson = projectDir => {
5161
const androidSettingsJsonPath = resolve(projectDir, PLATFORMS_ANDROID, "settings.json");
5262
if (existsSync(androidSettingsJsonPath)) {
@@ -62,5 +72,6 @@ module.exports = {
6272
ANDROID_CONFIGURATIONS_PATH,
6373
getAndroidRuntimeVersion,
6474
getAndroidV8Version,
65-
getMksnapshotParams
66-
};
75+
getMksnapshotParams,
76+
getRuntimeNdkRevision
77+
};

lib/utils.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ function isWinOS() {
1515
return os.type() === "Windows_NT";
1616
}
1717

18+
function warn(message) {
19+
if (message) {
20+
console.log(`\x1B[33;1m${message}\x1B[0m`);
21+
}
22+
}
23+
1824
module.exports = {
1925
shouldSnapshot,
2026
convertToUnixPath,
21-
isWinOS
27+
isWinOS,
28+
warn
2229
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"minimatch": "3.0.4",
5959
"nativescript-hook": "0.2.4",
6060
"nativescript-worker-loader": "~0.9.0",
61+
"properties-reader": "0.3.1",
6162
"proxy-lib": "0.4.0",
6263
"raw-loader": "~0.5.1",
6364
"request": "2.88.0",
Lines changed: 42 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
const { dirname, isAbsolute, join, resolve, sep } = require("path");
2-
const { existsSync, readFileSync, writeFileSync } = require("fs");
1+
const { isAbsolute, join, resolve, sep } = require("path");
2+
const { readFileSync, writeFileSync } = require("fs");
33

44
const shelljs = require("shelljs");
55
const semver = require("semver");
66

77
const SnapshotGenerator = require("./snapshot-generator");
88
const {
9-
CONSTANTS,
10-
createDirectory,
11-
getJsonFile,
9+
CONSTANTS
1210
} = require("./utils");
1311
const {
1412
ANDROID_PROJECT_DIR,
1513
ANDROID_APP_PATH,
1614
ANDROID_CONFIGURATIONS_PATH,
1715
getAndroidRuntimeVersion,
1816
getAndroidV8Version,
17+
getRuntimeNdkRevision,
1918
getMksnapshotParams
2019
} = require("../../androidProjectHelpers");
2120

22-
const MIN_ANDROID_RUNTIME_VERSION = "3.0.0";
21+
// min version with settings.json file specifying the V8 version
22+
const MIN_ANDROID_RUNTIME_VERSION = "5.2.1";
2323
const VALID_ANDROID_RUNTIME_TAGS = Object.freeze(["next", "rc"]);
24-
const V8_VERSIONS_FILE_NAME = "v8-versions.json";
25-
const V8_VERSIONS_URL = `https://raw.githubusercontent.com/NativeScript/android-runtime/master/${V8_VERSIONS_FILE_NAME}`;
26-
const V8_VERSIONS_LOCAL_PATH = resolve(CONSTANTS.SNAPSHOT_TMP_DIR, V8_VERSIONS_FILE_NAME);
2724

2825
const resolveRelativePath = (path) => {
2926
if (path)
@@ -120,73 +117,6 @@ ProjectSnapshotGenerator.installSnapshotArtefacts = function (projectRoot) {
120117
}
121118
}
122119

123-
const versionIsPrerelease = version => version.indexOf("-") > -1;
124-
const v8VersionsFileExists = () => existsSync(V8_VERSIONS_LOCAL_PATH);
125-
const saveV8VersionsFile = versionsMap =>
126-
writeFileSync(V8_VERSIONS_LOCAL_PATH, JSON.stringify(versionsMap));
127-
const readV8VersionsFile = () => JSON.parse(readFileSync(V8_VERSIONS_LOCAL_PATH));
128-
const fetchV8VersionsFile = () =>
129-
new Promise((resolve, reject) => {
130-
getJsonFile(V8_VERSIONS_URL)
131-
.then(versionsMap => {
132-
createDirectory(dirname(V8_VERSIONS_LOCAL_PATH));
133-
saveV8VersionsFile(versionsMap);
134-
return resolve(versionsMap);
135-
})
136-
.catch(reject);
137-
});
138-
139-
const findV8Version = (runtimeVersion, v8VersionsMap) => {
140-
const runtimeRange = Object.keys(v8VersionsMap)
141-
.find(range => semver.satisfies(runtimeVersion, range));
142-
143-
return v8VersionsMap[runtimeRange];
144-
}
145-
146-
const getV8VersionsMap = runtimeVersion =>
147-
new Promise((resolve, reject) => {
148-
if (!v8VersionsFileExists() || versionIsPrerelease(runtimeVersion)) {
149-
fetchV8VersionsFile()
150-
.then(versionsMap => resolve({ versionsMap, latest: true }))
151-
.catch(reject);
152-
} else {
153-
const versionsMap = readV8VersionsFile();
154-
return resolve({ versionsMap, latest: false });
155-
}
156-
});
157-
158-
ProjectSnapshotGenerator.prototype.getV8Version = function (generationOptions) {
159-
return new Promise((resolve, reject) => {
160-
const maybeV8Version = generationOptions.v8Version;
161-
if (maybeV8Version) {
162-
return resolve(maybeV8Version);
163-
}
164-
165-
// try to get the V8 Version from the settings.json file in android runtime folder
166-
const runtimeV8Version = getAndroidV8Version(this.options.projectRoot);
167-
if (runtimeV8Version) {
168-
return resolve(runtimeV8Version);
169-
}
170-
171-
const runtimeVersion = getAndroidRuntimeVersion(this.options.projectRoot);
172-
getV8VersionsMap(runtimeVersion)
173-
.then(({ versionsMap, latest }) => {
174-
const v8Version = findV8Version(runtimeVersion, versionsMap);
175-
176-
if (!v8Version && !latest) {
177-
fetchV8VersionsFile().then(latestVersionsMap => {
178-
const version = findV8Version(runtimeVersion, latestVersionsMap)
179-
return resolve(version);
180-
})
181-
.catch(reject);
182-
} else {
183-
return resolve(v8Version);
184-
}
185-
})
186-
.catch(reject);
187-
});
188-
}
189-
190120
ProjectSnapshotGenerator.prototype.validateAndroidRuntimeVersion = function () {
191121
const currentRuntimeVersion = getAndroidRuntimeVersion(this.options.projectRoot);
192122

@@ -224,53 +154,45 @@ ProjectSnapshotGenerator.prototype.generate = function (generationOptions) {
224154

225155
// Generate snapshots
226156
const generator = new SnapshotGenerator({ buildPath: this.getBuildPath() });
227-
228157
const noV8VersionFoundMessage = `Cannot find suitable v8 version!`;
229-
let shouldRethrow = false;
230-
231158
const mksnapshotParams = getMksnapshotParams(this.options.projectRoot);
159+
const recommendedAndroidNdkRevision = getRuntimeNdkRevision(this.options.projectRoot);
160+
const v8Version = generationOptions.v8Version || getAndroidV8Version(this.options.projectRoot);
161+
if (!v8Version) {
162+
throw new Error(noV8VersionFoundMessage);
163+
}
232164

233-
return this.getV8Version(generationOptions).then(v8Version => {
234-
shouldRethrow = true;
235-
if (!v8Version) {
236-
throw new Error(noV8VersionFoundMessage);
237-
}
165+
// NOTE: Order is important! Add new archs at the end of the array
166+
const defaultTargetArchs = ["arm", "arm64", "ia32", "ia64"];
167+
const runtimeVersion = getAndroidRuntimeVersion(this.options.projectRoot);
168+
if (runtimeVersion && semver.lt(semver.coerce(runtimeVersion), "6.0.2")) {
169+
const indexOfIa64 = defaultTargetArchs.indexOf("ia64");
170+
// Before 6.0.2 version of Android runtime we supported only arm, arm64 and ia32.
171+
defaultTargetArchs.splice(indexOfIa64, defaultTargetArchs.length - indexOfIa64);
172+
}
238173

239-
// NOTE: Order is important! Add new archs at the end of the array
240-
const defaultTargetArchs = ["arm", "arm64", "ia32", "ia64"];
241-
const runtimeVersion = getAndroidRuntimeVersion(this.options.projectRoot);
242-
if (runtimeVersion && semver.lt(semver.coerce(runtimeVersion), "6.0.2")) {
243-
const indexOfIa64 = defaultTargetArchs.indexOf("ia64");
244-
// Before 6.0.2 version of Android runtime we supported only arm, arm64 and ia32.
245-
defaultTargetArchs.splice(indexOfIa64, defaultTargetArchs.length - indexOfIa64);
174+
const options = {
175+
snapshotToolsPath,
176+
targetArchs: generationOptions.targetArchs || defaultTargetArchs,
177+
v8Version: generationOptions.v8Version || v8Version,
178+
preprocessedInputFile: generationOptions.preprocessedInputFile,
179+
useLibs: generationOptions.useLibs || false,
180+
inputFiles: generationOptions.inputFiles || [join(this.options.projectRoot, "__snapshot.js")],
181+
androidNdkPath,
182+
mksnapshotParams: mksnapshotParams,
183+
snapshotInDocker: generationOptions.snapshotInDocker,
184+
recommendedAndroidNdkRevision
185+
};
186+
187+
return generator.generate(options).then(() => {
188+
console.log("Snapshots build finished succesfully!");
189+
190+
if (generationOptions.install) {
191+
ProjectSnapshotGenerator.cleanSnapshotArtefacts(this.options.projectRoot);
192+
ProjectSnapshotGenerator.installSnapshotArtefacts(this.options.projectRoot);
193+
console.log(generationOptions.useLibs ?
194+
"Snapshot is included in the app as dynamically linked library (.so file)." :
195+
"Snapshot is included in the app as binary .blob file. The more space-efficient option is to embed it in a dynamically linked library (.so file).");
246196
}
247-
248-
const options = {
249-
snapshotToolsPath,
250-
targetArchs: generationOptions.targetArchs || defaultTargetArchs,
251-
v8Version: generationOptions.v8Version || v8Version,
252-
preprocessedInputFile: generationOptions.preprocessedInputFile,
253-
useLibs: generationOptions.useLibs || false,
254-
inputFiles: generationOptions.inputFiles || [join(this.options.projectRoot, "__snapshot.js")],
255-
androidNdkPath,
256-
mksnapshotParams: mksnapshotParams,
257-
snapshotInDocker: generationOptions.snapshotInDocker
258-
};
259-
260-
return generator.generate(options).then(() => {
261-
console.log("Snapshots build finished succesfully!");
262-
263-
if (generationOptions.install) {
264-
ProjectSnapshotGenerator.cleanSnapshotArtefacts(this.options.projectRoot);
265-
ProjectSnapshotGenerator.installSnapshotArtefacts(this.options.projectRoot);
266-
console.log(generationOptions.useLibs ?
267-
"Snapshot is included in the app as dynamically linked library (.so file)." :
268-
"Snapshot is included in the app as binary .blob file. The more space-efficient option is to embed it in a dynamically linked library (.so file).");
269-
}
270-
});
271-
}).catch(error => {
272-
throw shouldRethrow ?
273-
error :
274-
new Error(`${noV8VersionFoundMessage} Original error: ${error.message || error}`);
275-
});
197+
});;
276198
}

snapshot/android/snapshot-generator.js

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
const fs = require("fs");
22
const { dirname, relative, join, EOL } = require("path");
33
const child_process = require("child_process");
4-
const { convertToUnixPath } = require("../../lib/utils");
5-
4+
const { convertToUnixPath, warn } = require("../../lib/utils");
5+
const PropertiesReader = require('properties-reader');
66
const shelljs = require("shelljs");
77

88
const { createDirectory, downloadFile, getHostOS, getHostOSArch, CONSTANTS, has32BitArch, isMacOSCatalinaOrHigher, isSubPath } = require("./utils");
@@ -192,8 +192,9 @@ SnapshotGenerator.prototype.setupDocker = function () {
192192
child_process.execSync(`docker pull ${SNAPSHOTS_DOCKER_IMAGE}`);
193193
}
194194

195-
SnapshotGenerator.prototype.buildSnapshotLibs = function (androidNdkBuildPath, targetArchs) {
195+
SnapshotGenerator.prototype.buildSnapshotLibs = function (androidNdkPath, recommendedAndroidNdkRevision, targetArchs) {
196196
// Compile *.c files to produce *.so libraries with ndk-build tool
197+
const androidNdkBuildPath = this.getAndroidNdkBuildPath(androidNdkPath, recommendedAndroidNdkRevision);
197198
const ndkBuildPath = join(this.buildPath, "ndk-build");
198199
const androidArchs = targetArchs.map(arch => this.convertToAndroidArchName(arch));
199200
console.log("Building native libraries for " + androidArchs.join());
@@ -207,6 +208,54 @@ SnapshotGenerator.prototype.buildSnapshotLibs = function (androidNdkBuildPath, t
207208
return join(ndkBuildPath, "libs");
208209
}
209210

211+
SnapshotGenerator.prototype.getAndroidNdkBuildPath = function (androidNdkPath, recommendedAndroidNdkRevision) {
212+
const ndkBuildExecutableName = "ndk-build";
213+
// fallback for Android Runtime < 6.2.0 with the 6.1.0 value
214+
recommendedAndroidNdkRevision = recommendedAndroidNdkRevision || "20.0.5594570";
215+
let androidNdkBuildPath = "";
216+
if (androidNdkPath) {
217+
// specified by the user
218+
const localNdkRevision = this.getAndroidNdkRevision(androidNdkPath);
219+
androidNdkBuildPath = join(androidNdkPath, ndkBuildExecutableName);
220+
if (!fs.existsSync(androidNdkBuildPath)) {
221+
throw new Error(`The provided Android NDK path does not contain ${ndkBuildExecutableName} executable.`);
222+
} else if (localNdkRevision !== recommendedAndroidNdkRevision) {
223+
warn(`The provided Android NDK is v${localNdkRevision} while the recommended one is v${recommendedAndroidNdkRevision}`);
224+
}
225+
} else {
226+
// available globally
227+
let hasAndroidNdkInPath = true;
228+
androidNdkBuildPath = ndkBuildExecutableName;
229+
try {
230+
child_process.execSync(`${androidNdkBuildPath} --version`);
231+
console.log(`Cannot determine the version of the global Android NDK. The recommended versions is v${recommendedAndroidNdkRevision}`);
232+
} catch (_) {
233+
hasAndroidNdkInPath = false;
234+
}
235+
236+
if (!hasAndroidNdkInPath) {
237+
// installed in ANDROID_HOME
238+
const androidHome = process.env.ANDROID_HOME;
239+
androidNdkBuildPath = join(androidHome, "ndk", recommendedAndroidNdkRevision, ndkBuildExecutableName);
240+
if (!fs.existsSync(androidNdkBuildPath)) {
241+
throw new Error(`Android NDK v${recommendedAndroidNdkRevision} is not installed. You can find installation instructions in this article: https://developer.android.com/studio/projects/install-ndk#specific-version`);
242+
}
243+
}
244+
}
245+
246+
return androidNdkBuildPath;
247+
}
248+
249+
SnapshotGenerator.prototype.getAndroidNdkRevision = function (androidNdkPath) {
250+
const ndkPropertiesFile = join(androidNdkPath, "source.properties");
251+
if (fs.existsSync(ndkPropertiesFile)) {
252+
const properties = PropertiesReader(ndkPropertiesFile);
253+
return properties.get("Pkg.Revision");
254+
} else {
255+
return null;
256+
}
257+
}
258+
210259
SnapshotGenerator.prototype.buildIncludeGradle = function () {
211260
shelljs.cp(INCLUDE_GRADLE_PATH, join(this.buildPath, "include.gradle"));
212261
}
@@ -236,8 +285,7 @@ SnapshotGenerator.prototype.generate = function (options) {
236285
).then(() => {
237286
this.buildIncludeGradle();
238287
if (options.useLibs) {
239-
const androidNdkBuildPath = options.androidNdkPath ? join(options.androidNdkPath, "ndk-build") : "ndk-build";
240-
this.buildSnapshotLibs(androidNdkBuildPath, options.targetArchs);
288+
this.buildSnapshotLibs(options.androidNdkPath, options.recommendedAndroidNdkRevision, options.targetArchs);
241289
}
242290
return this.buildPath;
243291
});

templates/webpack.angular.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ module.exports = env => {
5252
unitTesting, // --env.unitTesting
5353
verbose, // --env.verbose
5454
snapshotInDocker, // --env.snapshotInDocker
55-
skipSnapshotTools // --env.skipSnapshotTools
55+
skipSnapshotTools, // --env.skipSnapshotTools
56+
compileSnapshot // --env.compileSnapshot
5657
} = env;
5758

59+
const useLibs = compileSnapshot;
5860
const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap;
5961
const externals = nsWebpack.getConvertedExternals(env.externals);
6062
const appFullPath = resolve(projectRoot, appPath);
@@ -315,7 +317,8 @@ module.exports = env => {
315317
projectRoot,
316318
webpackConfig: config,
317319
snapshotInDocker,
318-
skipSnapshotTools
320+
skipSnapshotTools,
321+
useLibs
319322
}));
320323
}
321324

templates/webpack.javascript.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ module.exports = env => {
4545
unitTesting, // --env.unitTesting,
4646
verbose, // --env.verbose
4747
snapshotInDocker, // --env.snapshotInDocker
48-
skipSnapshotTools // --env.skipSnapshotTools
48+
skipSnapshotTools, // --env.skipSnapshotTools
49+
compileSnapshot // --env.compileSnapshot
4950
} = env;
5051

52+
const useLibs = compileSnapshot;
5153
const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap;
5254
const externals = nsWebpack.getConvertedExternals(env.externals);
5355
const appFullPath = resolve(projectRoot, appPath);
@@ -253,7 +255,8 @@ module.exports = env => {
253255
projectRoot,
254256
webpackConfig: config,
255257
snapshotInDocker,
256-
skipSnapshotTools
258+
skipSnapshotTools,
259+
useLibs
257260
}));
258261
}
259262

0 commit comments

Comments
 (0)