appium-adb 14.3.4 → 14.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/build/lib/adb.d.ts +9 -4
- package/build/lib/adb.d.ts.map +1 -1
- package/build/lib/adb.js +8 -9
- package/build/lib/adb.js.map +1 -1
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +2 -2
- package/build/lib/index.js.map +1 -1
- package/build/lib/logcat.d.ts.map +1 -1
- package/build/lib/logcat.js +6 -14
- package/build/lib/logcat.js.map +1 -1
- package/build/lib/tools/aab-utils.d.ts.map +1 -1
- package/build/lib/tools/aab-utils.js +2 -2
- package/build/lib/tools/aab-utils.js.map +1 -1
- package/build/lib/tools/android-manifest.d.ts.map +1 -1
- package/build/lib/tools/android-manifest.js +11 -12
- package/build/lib/tools/android-manifest.js.map +1 -1
- package/build/lib/tools/apk-signing.d.ts.map +1 -1
- package/build/lib/tools/apk-signing.js +18 -19
- package/build/lib/tools/apk-signing.js.map +1 -1
- package/build/lib/tools/apk-utils.d.ts.map +1 -1
- package/build/lib/tools/apk-utils.js +39 -40
- package/build/lib/tools/apk-utils.js.map +1 -1
- package/build/lib/tools/apks-utils.d.ts.map +1 -1
- package/build/lib/tools/apks-utils.js +8 -9
- package/build/lib/tools/apks-utils.js.map +1 -1
- package/build/lib/tools/app-commands.d.ts.map +1 -1
- package/build/lib/tools/app-commands.js +37 -36
- package/build/lib/tools/app-commands.js.map +1 -1
- package/build/lib/tools/device-settings.d.ts.map +1 -1
- package/build/lib/tools/device-settings.js +17 -18
- package/build/lib/tools/device-settings.js.map +1 -1
- package/build/lib/tools/emulator-commands.d.ts.map +1 -1
- package/build/lib/tools/emulator-commands.js +22 -23
- package/build/lib/tools/emulator-commands.js.map +1 -1
- package/build/lib/tools/fs-commands.d.ts.map +1 -1
- package/build/lib/tools/fs-commands.js +5 -4
- package/build/lib/tools/fs-commands.js.map +1 -1
- package/build/lib/tools/general-commands.d.ts.map +1 -1
- package/build/lib/tools/general-commands.js +29 -29
- package/build/lib/tools/general-commands.js.map +1 -1
- package/build/lib/tools/keyboard-commands.d.ts.map +1 -1
- package/build/lib/tools/keyboard-commands.js +6 -4
- package/build/lib/tools/keyboard-commands.js.map +1 -1
- package/build/lib/tools/lockmgmt.d.ts.map +1 -1
- package/build/lib/tools/lockmgmt.js +17 -20
- package/build/lib/tools/lockmgmt.js.map +1 -1
- package/build/lib/tools/logcat-commands.d.ts.map +1 -1
- package/build/lib/tools/logcat-commands.js +5 -9
- package/build/lib/tools/logcat-commands.js.map +1 -1
- package/build/lib/tools/network-commands.d.ts.map +1 -1
- package/build/lib/tools/network-commands.js +1 -5
- package/build/lib/tools/network-commands.js.map +1 -1
- package/build/lib/tools/process-commands.d.ts.map +1 -1
- package/build/lib/tools/process-commands.js +11 -12
- package/build/lib/tools/process-commands.js.map +1 -1
- package/build/lib/tools/system-calls.d.ts +12 -5
- package/build/lib/tools/system-calls.d.ts.map +1 -1
- package/build/lib/tools/system-calls.js +56 -50
- package/build/lib/tools/system-calls.js.map +1 -1
- package/build/lib/tools/types.d.ts +1 -1
- package/build/lib/tools/types.d.ts.map +1 -1
- package/build/lib/utils/helpers/constants.d.ts +6 -0
- package/build/lib/utils/helpers/constants.d.ts.map +1 -0
- package/build/lib/utils/helpers/constants.js +9 -0
- package/build/lib/utils/helpers/constants.js.map +1 -0
- package/build/lib/utils/helpers/index.d.ts +6 -0
- package/build/lib/utils/helpers/index.d.ts.map +1 -0
- package/build/lib/utils/helpers/index.js +21 -0
- package/build/lib/utils/helpers/index.js.map +1 -0
- package/build/lib/utils/helpers/install.d.ts +16 -0
- package/build/lib/utils/helpers/install.d.ts.map +1 -0
- package/build/lib/utils/helpers/install.js +39 -0
- package/build/lib/utils/helpers/install.js.map +1 -0
- package/build/lib/utils/helpers/manifest.d.ts +10 -0
- package/build/lib/utils/helpers/manifest.d.ts.map +1 -0
- package/build/lib/utils/helpers/manifest.js +124 -0
- package/build/lib/utils/helpers/manifest.js.map +1 -0
- package/build/lib/utils/helpers/resource.d.ts +11 -0
- package/build/lib/utils/helpers/resource.d.ts.map +1 -0
- package/build/lib/utils/helpers/resource.js +59 -0
- package/build/lib/utils/helpers/resource.js.map +1 -0
- package/build/lib/utils/helpers/sdk.d.ts +20 -0
- package/build/lib/utils/helpers/sdk.d.ts.map +1 -0
- package/build/lib/utils/helpers/sdk.js +80 -0
- package/build/lib/utils/helpers/sdk.js.map +1 -0
- package/build/lib/utils/index.d.ts +40 -0
- package/build/lib/utils/index.d.ts.map +1 -0
- package/build/lib/utils/index.js +58 -0
- package/build/lib/utils/index.js.map +1 -0
- package/build/lib/utils/lodash/core.d.ts +9 -0
- package/build/lib/utils/lodash/core.d.ts.map +1 -0
- package/build/lib/utils/lodash/core.js +60 -0
- package/build/lib/utils/lodash/core.js.map +1 -0
- package/build/lib/utils/lodash/index.d.ts +2 -0
- package/build/lib/utils/lodash/index.d.ts.map +1 -0
- package/build/lib/utils/lodash/index.js +18 -0
- package/build/lib/utils/lodash/index.js.map +1 -0
- package/lib/adb.ts +14 -6
- package/lib/index.ts +1 -1
- package/lib/logcat.ts +6 -11
- package/lib/tools/aab-utils.ts +1 -1
- package/lib/tools/android-manifest.ts +4 -4
- package/lib/tools/apk-signing.ts +11 -7
- package/lib/tools/apk-utils.ts +41 -42
- package/lib/tools/apks-utils.ts +4 -5
- package/lib/tools/app-commands.ts +40 -34
- package/lib/tools/device-settings.ts +17 -15
- package/lib/tools/emulator-commands.ts +22 -23
- package/lib/tools/fs-commands.ts +5 -4
- package/lib/tools/general-commands.ts +32 -27
- package/lib/tools/keyboard-commands.ts +6 -4
- package/lib/tools/lockmgmt.ts +17 -13
- package/lib/tools/logcat-commands.ts +5 -6
- package/lib/tools/network-commands.ts +1 -2
- package/lib/tools/process-commands.ts +11 -9
- package/lib/tools/system-calls.ts +54 -46
- package/lib/tools/types.ts +1 -1
- package/lib/utils/helpers/constants.ts +6 -0
- package/lib/utils/helpers/index.ts +10 -0
- package/lib/utils/helpers/install.ts +50 -0
- package/lib/utils/helpers/manifest.ts +127 -0
- package/lib/utils/helpers/resource.ts +63 -0
- package/lib/utils/helpers/sdk.ts +81 -0
- package/lib/utils/index.ts +25 -0
- package/lib/utils/lodash/core.ts +65 -0
- package/lib/utils/lodash/index.ts +1 -0
- package/package.json +3 -5
- package/build/lib/helpers.d.ts +0 -47
- package/build/lib/helpers.d.ts.map +0 -1
- package/build/lib/helpers.js +0 -283
- package/build/lib/helpers.js.map +0 -1
- package/lib/helpers.ts +0 -323
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultsDeep = exports.pick = exports.zip = exports.intersectionWith = exports.defaults = exports.cloneDeep = void 0;
|
|
4
|
+
const support_1 = require("@appium/support");
|
|
5
|
+
const cloneDeep = (value) => {
|
|
6
|
+
if (typeof globalThis.structuredClone === 'function') {
|
|
7
|
+
return globalThis.structuredClone(value);
|
|
8
|
+
}
|
|
9
|
+
return JSON.parse(JSON.stringify(value));
|
|
10
|
+
};
|
|
11
|
+
exports.cloneDeep = cloneDeep;
|
|
12
|
+
const defaults = (target, ...sources) => {
|
|
13
|
+
for (const source of sources) {
|
|
14
|
+
if (!source) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
for (const [key, value] of Object.entries(source)) {
|
|
18
|
+
if (target[key] === undefined) {
|
|
19
|
+
target[key] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return target;
|
|
24
|
+
};
|
|
25
|
+
exports.defaults = defaults;
|
|
26
|
+
const _defaultsDeep = (target, ...sources) => {
|
|
27
|
+
for (const source of sources) {
|
|
28
|
+
if (!source) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
for (const [key, value] of Object.entries(source)) {
|
|
32
|
+
const current = target[key];
|
|
33
|
+
if (current === undefined) {
|
|
34
|
+
target[key] = support_1.util.isPlainObject(value) || Array.isArray(value) ? (0, exports.cloneDeep)(value) : value;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (support_1.util.isPlainObject(current) && support_1.util.isPlainObject(value)) {
|
|
38
|
+
_defaultsDeep(current, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return target;
|
|
43
|
+
};
|
|
44
|
+
const intersectionWith = (first, second, comparator) => first.filter((item) => second.some((other) => comparator(item, other)));
|
|
45
|
+
exports.intersectionWith = intersectionWith;
|
|
46
|
+
const zip = (arrA, arrB) => {
|
|
47
|
+
const length = Math.max(arrA.length, arrB.length);
|
|
48
|
+
return Array.from({ length }, (_, idx) => [arrA[idx], arrB[idx]]);
|
|
49
|
+
};
|
|
50
|
+
exports.zip = zip;
|
|
51
|
+
const pick = (obj, keysArg) => keysArg.reduce((acc, key) => {
|
|
52
|
+
if (key in obj) {
|
|
53
|
+
acc[key] = obj[key];
|
|
54
|
+
}
|
|
55
|
+
return acc;
|
|
56
|
+
}, {});
|
|
57
|
+
exports.pick = pick;
|
|
58
|
+
const defaultsDeep = (target, ...sources) => _defaultsDeep(target, ...sources);
|
|
59
|
+
exports.defaultsDeep = defaultsDeep;
|
|
60
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../lib/utils/lodash/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../lib/utils/lodash/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./core"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/utils/lodash/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB"}
|
package/lib/adb.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import os from 'node:os';
|
|
3
|
-
import {DEFAULT_ADB_EXEC_TIMEOUT, requireSdkRoot, getSdkRootFromEnv} from './helpers';
|
|
4
2
|
import {log} from './logger';
|
|
5
3
|
import type {ADBOptions, ADBExecutable} from './types';
|
|
6
4
|
import type {Logcat} from './logcat';
|
|
@@ -25,6 +23,14 @@ import * as appCommands from './tools/app-commands';
|
|
|
25
23
|
import * as networkCommands from './tools/network-commands';
|
|
26
24
|
import * as logcatCommands from './tools/logcat-commands';
|
|
27
25
|
import * as processCommands from './tools/process-commands';
|
|
26
|
+
import {
|
|
27
|
+
DEFAULT_ADB_EXEC_TIMEOUT,
|
|
28
|
+
cloneDeep,
|
|
29
|
+
defaultsDeep,
|
|
30
|
+
getSdkRootFromEnv,
|
|
31
|
+
pick,
|
|
32
|
+
requireSdkRoot,
|
|
33
|
+
} from './utils';
|
|
28
34
|
|
|
29
35
|
export const DEFAULT_ADB_PORT = 5037;
|
|
30
36
|
export const DEFAULT_OPTS = {
|
|
@@ -320,8 +326,8 @@ export class ADB implements ADBOptions {
|
|
|
320
326
|
getScreenOrientation = deviceSettingsCommands.getScreenOrientation;
|
|
321
327
|
|
|
322
328
|
constructor(opts: ADBOptions = {} as ADBOptions) {
|
|
323
|
-
const options: ADBOptions =
|
|
324
|
-
|
|
329
|
+
const options: ADBOptions = defaultsDeep(opts, cloneDeep(DEFAULT_OPTS));
|
|
330
|
+
defaultsDeep(this, options);
|
|
325
331
|
|
|
326
332
|
// The above defaultsDeep call guarantees the 'executable' field to be always assigned
|
|
327
333
|
this.executable = options.executable as ADBExecutable;
|
|
@@ -372,8 +378,10 @@ export class ADB implements ADBOptions {
|
|
|
372
378
|
* @returns The resulting class instance.
|
|
373
379
|
*/
|
|
374
380
|
clone(opts: ADBOptions = {} as ADBOptions): ADB {
|
|
375
|
-
const originalOptions =
|
|
376
|
-
const cloneOptions =
|
|
381
|
+
const originalOptions = cloneDeep(pick(this, Object.keys(DEFAULT_OPTS)));
|
|
382
|
+
const cloneOptions = defaultsDeep(opts, originalOptions) as ADBOptions & {
|
|
383
|
+
executable: ADBExecutable;
|
|
384
|
+
};
|
|
377
385
|
|
|
378
386
|
// Reset default arguments created in the constructor.
|
|
379
387
|
// Without this code, -H and -P can be injected into defaultArgs multiple times.
|
package/lib/index.ts
CHANGED
package/lib/logcat.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {logger, util} from '@appium/support';
|
|
2
|
-
import _ from 'lodash';
|
|
3
2
|
import {EventEmitter} from 'node:events';
|
|
4
3
|
import {SubProcess, exec} from 'teen_process';
|
|
5
4
|
import {LRUCache} from 'lru-cache';
|
|
@@ -148,7 +147,7 @@ export class Logcat extends EventEmitter {
|
|
|
148
147
|
result.push(toLogEntry(message, timestamp));
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
|
-
if (
|
|
150
|
+
if (Number.isInteger(recentLogIndex)) {
|
|
152
151
|
this.logIndexSinceLastRequest = recentLogIndex;
|
|
153
152
|
}
|
|
154
153
|
return result;
|
|
@@ -179,12 +178,8 @@ export class Logcat extends EventEmitter {
|
|
|
179
178
|
|
|
180
179
|
private outputHandler(logLine: string, prefix: string = ''): void {
|
|
181
180
|
const timestamp = Date.now();
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
recentIndex = key;
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
this.logs.set(++recentIndex, [logLine, timestamp]);
|
|
181
|
+
const recentIndex = this.logs.keys().next().value ?? -1;
|
|
182
|
+
this.logs.set(recentIndex + 1, [logLine, timestamp]);
|
|
188
183
|
if (this.listenerCount('output')) {
|
|
189
184
|
this.emit('output', toLogEntry(logLine, timestamp));
|
|
190
185
|
}
|
|
@@ -225,7 +220,7 @@ function requireSpec(spec: string): string {
|
|
|
225
220
|
);
|
|
226
221
|
return `${resultTag}:${DEFAULT_PRIORITY}`;
|
|
227
222
|
}
|
|
228
|
-
if (!SUPPORTED_PRIORITIES.some((p) =>
|
|
223
|
+
if (!SUPPORTED_PRIORITIES.some((p) => priority.toLowerCase() === p.toLowerCase())) {
|
|
229
224
|
log.info(
|
|
230
225
|
`The priority value in spec '${spec}' is unknown. Supported values are: ${SUPPORTED_PRIORITIES}`,
|
|
231
226
|
);
|
|
@@ -236,11 +231,11 @@ function requireSpec(spec: string): string {
|
|
|
236
231
|
}
|
|
237
232
|
|
|
238
233
|
function formatFilterSpecs(filterSpecs: string | string[]): string[] {
|
|
239
|
-
if (!
|
|
234
|
+
if (!Array.isArray(filterSpecs)) {
|
|
240
235
|
filterSpecs = [filterSpecs];
|
|
241
236
|
}
|
|
242
237
|
return filterSpecs
|
|
243
|
-
.filter((spec) => spec &&
|
|
238
|
+
.filter((spec) => spec && typeof spec === 'string' && !spec.startsWith('-'))
|
|
244
239
|
.map((spec) => (spec.includes(':') ? requireSpec(spec) : spec));
|
|
245
240
|
}
|
|
246
241
|
|
package/lib/tools/aab-utils.ts
CHANGED
|
@@ -2,11 +2,11 @@ import {log} from '../logger';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import {fs, tempDir, util} from '@appium/support';
|
|
4
4
|
import {LRUCache} from 'lru-cache';
|
|
5
|
-
import {unzipFile} from '../helpers';
|
|
6
5
|
import AsyncLock from 'async-lock';
|
|
7
6
|
import crypto from 'node:crypto';
|
|
8
7
|
import type {ADB} from '../adb';
|
|
9
8
|
import type {ApkCreationOptions, StringRecord} from './types';
|
|
9
|
+
import {unzipFile} from '../utils';
|
|
10
10
|
|
|
11
11
|
const AAB_CACHE = new LRUCache<string, string>({
|
|
12
12
|
max: 10,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {exec} from 'teen_process';
|
|
3
2
|
import {log} from '../logger';
|
|
4
|
-
import {unzipFile, APKS_EXTENSION, readPackageManifest} from '../helpers';
|
|
5
3
|
import {fs, zip, tempDir, util} from '@appium/support';
|
|
6
4
|
import path from 'node:path';
|
|
7
5
|
import type {ADB} from '../adb';
|
|
8
6
|
import type {APKInfo, PlatformInfo, StringRecord} from './types';
|
|
7
|
+
import {APKS_EXTENSION, readPackageManifest, unzipFile} from '../utils';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Extract package and main activity name from application manifest.
|
|
@@ -150,6 +149,7 @@ export async function compileManifest(
|
|
|
150
149
|
} catch (e1) {
|
|
151
150
|
throw new Error(
|
|
152
151
|
`Cannot compile the manifest. Original error: ${(e1 as Error).message || (e1 as {stderr?: string}).stderr}`,
|
|
152
|
+
{cause: e1},
|
|
153
153
|
);
|
|
154
154
|
}
|
|
155
155
|
}
|
|
@@ -262,7 +262,7 @@ export async function getAndroidPlatformAndPath(sdkRoot: string): Promise<Platfo
|
|
|
262
262
|
platformPath,
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
if (
|
|
265
|
+
if (util.isEmpty(platformsMapping)) {
|
|
266
266
|
log.warn(
|
|
267
267
|
`Found zero platform folders at '${path.resolve(sdkRoot, 'platforms')}'. ` +
|
|
268
268
|
`Do you have any Android SDKs installed?`,
|
|
@@ -273,7 +273,7 @@ export async function getAndroidPlatformAndPath(sdkRoot: string): Promise<Platfo
|
|
|
273
273
|
};
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
const recentSdkVersion =
|
|
276
|
+
const recentSdkVersion = Object.keys(platformsMapping).sort().reverse()[0];
|
|
277
277
|
const result = platformsMapping[recentSdkVersion];
|
|
278
278
|
log.debug(`Found the most recent Android platform: ${JSON.stringify(result)}`);
|
|
279
279
|
return result;
|
package/lib/tools/apk-signing.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import _fs from 'node:fs';
|
|
3
2
|
import {exec, type ExecError} from 'teen_process';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
import {log} from '../logger';
|
|
6
5
|
import {tempDir, system, mkdirp, fs, util, zip} from '@appium/support';
|
|
7
6
|
import {LRUCache} from 'lru-cache';
|
|
8
|
-
import {getJavaForOs, getJavaHome, APKS_EXTENSION, getResourcePath} from '../helpers';
|
|
9
7
|
import type {ADB} from '../adb';
|
|
10
8
|
import type {StringRecord, SignedAppCacheValue, CertCheckOptions, KeystoreHash} from './types';
|
|
9
|
+
import {APKS_EXTENSION, getJavaForOs, getJavaHome, getResourcePath} from '../utils';
|
|
11
10
|
|
|
12
11
|
const DEFAULT_PRIVATE_KEY = path.join('keys', 'testkey.pk8');
|
|
13
12
|
const DEFAULT_CERTIFICATE = path.join('keys', 'testkey.x509.pem');
|
|
@@ -45,7 +44,7 @@ export async function executeApksigner(this: ADB, args: string[]): Promise<strin
|
|
|
45
44
|
['stdout', stdout],
|
|
46
45
|
['stderr', stderr],
|
|
47
46
|
] as const) {
|
|
48
|
-
if (!
|
|
47
|
+
if (!stream?.trim()) {
|
|
49
48
|
continue;
|
|
50
49
|
}
|
|
51
50
|
|
|
@@ -90,6 +89,7 @@ export async function signWithDefaultCert(this: ADB, apk: string): Promise<void>
|
|
|
90
89
|
throw new Error(
|
|
91
90
|
`Could not sign '${apk}' with the default certificate. ` +
|
|
92
91
|
`Original error: ${err.stderr || err.stdout || err.message}`,
|
|
92
|
+
{cause: e},
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -161,6 +161,7 @@ export async function signWithCustomCert(this: ADB, apk: string): Promise<void>
|
|
|
161
161
|
throw new Error(
|
|
162
162
|
`Could not sign with custom certificate. ` +
|
|
163
163
|
`Original error: ${execErr.stderr || execErr.message}`,
|
|
164
|
+
{cause: e},
|
|
164
165
|
);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
@@ -240,6 +241,7 @@ export async function zipAlignApk(this: ADB, apk: string): Promise<boolean> {
|
|
|
240
241
|
}
|
|
241
242
|
throw new Error(
|
|
242
243
|
`zipAlignApk failed. Original error: ${err.message || (err as ExecError).stderr}`,
|
|
244
|
+
{cause: e},
|
|
243
245
|
);
|
|
244
246
|
}
|
|
245
247
|
}
|
|
@@ -270,7 +272,7 @@ export async function checkApkCert(
|
|
|
270
272
|
}
|
|
271
273
|
|
|
272
274
|
const hashMatches = (apksignerOutput: string, expectedHashes: KeystoreHash): boolean => {
|
|
273
|
-
for (const [name, value] of
|
|
275
|
+
for (const [name, value] of Object.entries(expectedHashes)) {
|
|
274
276
|
if (value && new RegExp(`digest:\\s+${value}\\b`, 'i').test(apksignerOutput)) {
|
|
275
277
|
log.debug(`${name} hash did match for '${path.basename(actualAppPath)}'`);
|
|
276
278
|
return true;
|
|
@@ -321,12 +323,12 @@ export async function checkApkCert(
|
|
|
321
323
|
} catch (err) {
|
|
322
324
|
const error = err as ExecError;
|
|
323
325
|
// check if there is no signature
|
|
324
|
-
if (
|
|
326
|
+
if ((error.stderr ?? '').includes(APKSIGNER_VERIFY_FAIL)) {
|
|
325
327
|
log.info(`'${actualAppPath}' is not signed`);
|
|
326
328
|
return false;
|
|
327
329
|
}
|
|
328
330
|
const errMsg = error.stderr || error.stdout || error.message;
|
|
329
|
-
if (
|
|
331
|
+
if (`${errMsg}`.includes(JAVA_PROPS_INIT_ERROR)) {
|
|
330
332
|
// This error pops up randomly and we are not quite sure why.
|
|
331
333
|
// My guess - a race condition in java vm initialization.
|
|
332
334
|
// Nevertheless, lets make Appium to believe the file is already signed,
|
|
@@ -341,6 +343,7 @@ export async function checkApkCert(
|
|
|
341
343
|
}
|
|
342
344
|
throw new Error(
|
|
343
345
|
`Cannot verify the signature of '${actualAppPath}'. ` + `Original error: ${errMsg}`,
|
|
346
|
+
{cause: err},
|
|
344
347
|
);
|
|
345
348
|
}
|
|
346
349
|
}
|
|
@@ -383,7 +386,7 @@ export async function getKeystoreHash(this: ADB): Promise<KeystoreHash> {
|
|
|
383
386
|
}
|
|
384
387
|
result[hashName] = match[1].replace(/:/g, '').toLowerCase();
|
|
385
388
|
}
|
|
386
|
-
if (
|
|
389
|
+
if (util.isEmpty(result)) {
|
|
387
390
|
log.debug(stdout);
|
|
388
391
|
throw new Error('Cannot parse the hash value from the keytool output');
|
|
389
392
|
}
|
|
@@ -394,6 +397,7 @@ export async function getKeystoreHash(this: ADB): Promise<KeystoreHash> {
|
|
|
394
397
|
throw new Error(
|
|
395
398
|
`Cannot get the hash of '${this.keystorePath}' keystore. ` +
|
|
396
399
|
`Original error: ${err.stderr || err.message}`,
|
|
400
|
+
{cause: e},
|
|
397
401
|
);
|
|
398
402
|
}
|
|
399
403
|
}
|
package/lib/tools/apk-utils.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
APKS_EXTENSION,
|
|
3
|
-
buildInstallArgs,
|
|
4
|
-
APK_INSTALL_TIMEOUT,
|
|
5
|
-
DEFAULT_ADB_EXEC_TIMEOUT,
|
|
6
|
-
readPackageManifest,
|
|
7
|
-
} from '../helpers';
|
|
8
1
|
import {exec, type ExecError} from 'teen_process';
|
|
9
2
|
import {log} from '../logger';
|
|
10
3
|
import path from 'node:path';
|
|
11
|
-
import _ from 'lodash';
|
|
12
4
|
import {fs, util, mkdirp, timing} from '@appium/support';
|
|
13
5
|
import * as semver from 'semver';
|
|
14
6
|
import os from 'node:os';
|
|
15
7
|
import {LRUCache} from 'lru-cache';
|
|
16
8
|
import type {ADB} from '../adb';
|
|
9
|
+
import {
|
|
10
|
+
APKS_EXTENSION,
|
|
11
|
+
APK_INSTALL_TIMEOUT,
|
|
12
|
+
DEFAULT_ADB_EXEC_TIMEOUT,
|
|
13
|
+
buildInstallArgs,
|
|
14
|
+
cloneDeep,
|
|
15
|
+
defaults,
|
|
16
|
+
readPackageManifest,
|
|
17
|
+
} from '../utils';
|
|
17
18
|
import type {
|
|
18
19
|
UninstallOptions,
|
|
19
20
|
ShellExecOptions,
|
|
@@ -60,7 +61,7 @@ export async function uninstallApk(
|
|
|
60
61
|
stdout = (await this.adbExec(cmd, {timeout: options.timeout})).trim();
|
|
61
62
|
} catch (e) {
|
|
62
63
|
const err = e as Error;
|
|
63
|
-
throw new Error(`Unable to uninstall APK. Original error: ${err.message}
|
|
64
|
+
throw new Error(`Unable to uninstall APK. Original error: ${err.message}`, {cause: e});
|
|
64
65
|
}
|
|
65
66
|
log.debug(`'adb ${cmd.join(' ')}' command output: ${stdout}`);
|
|
66
67
|
if (stdout.includes('Success')) {
|
|
@@ -111,15 +112,15 @@ export async function cacheApk(
|
|
|
111
112
|
let lsOutput: string | null = null;
|
|
112
113
|
if (
|
|
113
114
|
this._areExtendedLsOptionsSupported === true ||
|
|
114
|
-
|
|
115
|
+
typeof this._areExtendedLsOptionsSupported !== 'boolean'
|
|
115
116
|
) {
|
|
116
117
|
lsOutput = await this.shell([`ls -t -1 ${REMOTE_CACHE_ROOT} 2>&1 || echo ${errorMarker}`]);
|
|
117
118
|
}
|
|
118
119
|
if (
|
|
119
|
-
|
|
120
|
+
typeof lsOutput !== 'string' ||
|
|
120
121
|
(lsOutput.includes(errorMarker) && !lsOutput.includes(REMOTE_CACHE_ROOT))
|
|
121
122
|
) {
|
|
122
|
-
if (
|
|
123
|
+
if (typeof this._areExtendedLsOptionsSupported !== 'boolean') {
|
|
123
124
|
log.debug(
|
|
124
125
|
'The current Android API does not support extended ls options. ' +
|
|
125
126
|
'Defaulting to no-options call',
|
|
@@ -172,9 +173,10 @@ export async function cacheApk(
|
|
|
172
173
|
});
|
|
173
174
|
}
|
|
174
175
|
// Cleanup the invalid entries from the cache
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
const remoteCachedHashes = new Set(remoteCachedFiles.map(toHash));
|
|
177
|
+
[...this.remoteAppsCache.keys()]
|
|
178
|
+
.filter((cacheKey) => !remoteCachedHashes.has(cacheKey))
|
|
179
|
+
.forEach((hash) => (this.remoteAppsCache as LRUCache<string, string>).delete(hash));
|
|
178
180
|
// Bump the cache record for the recently cached item
|
|
179
181
|
this.remoteAppsCache.set(appHash, remotePath);
|
|
180
182
|
// If the remote cache exceeds this.remoteAppsCacheLimit, remove the least recently used entries
|
|
@@ -182,7 +184,7 @@ export async function cacheApk(
|
|
|
182
184
|
.map((x) => path.posix.join(REMOTE_CACHE_ROOT, x))
|
|
183
185
|
.filter((x) => !(this.remoteAppsCache as LRUCache<string, string>).has(toHash(x)))
|
|
184
186
|
.slice((this.remoteAppsCacheLimit as number) - [...this.remoteAppsCache.keys()].length);
|
|
185
|
-
if (!
|
|
187
|
+
if (!util.isEmpty(entriesToCleanup)) {
|
|
186
188
|
try {
|
|
187
189
|
await this.shell(['rm', '-f', ...entriesToCleanup]);
|
|
188
190
|
log.debug(`Deleted ${entriesToCleanup.length} expired application cache entries`);
|
|
@@ -213,8 +215,8 @@ export async function install(
|
|
|
213
215
|
return await this.installApks(appPath, options);
|
|
214
216
|
}
|
|
215
217
|
|
|
216
|
-
options =
|
|
217
|
-
|
|
218
|
+
options = cloneDeep(options);
|
|
219
|
+
defaults(options, {
|
|
218
220
|
replace: true,
|
|
219
221
|
timeout:
|
|
220
222
|
this.adbExecTimeout === DEFAULT_ADB_EXEC_TIMEOUT ? APK_INSTALL_TIMEOUT : this.adbExecTimeout,
|
|
@@ -238,11 +240,7 @@ export async function install(
|
|
|
238
240
|
log.info(
|
|
239
241
|
`The installation of '${path.basename(appPath)}' took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`,
|
|
240
242
|
);
|
|
241
|
-
|
|
242
|
-
!_.isString(output) || output.length <= 300
|
|
243
|
-
? output
|
|
244
|
-
: `${output.substring(0, 150)}...${output.substring(output.length - 150)}`;
|
|
245
|
-
log.debug(`Install command stdout: ${truncatedOutput}`);
|
|
243
|
+
log.debug(`Install command stdout: ${util.truncateString(output, {length: 300})}`);
|
|
246
244
|
if (/\[INSTALL[A-Z_]+FAILED[A-Z_]+\]/.test(output)) {
|
|
247
245
|
if (this.isTestPackageOnlyError(output)) {
|
|
248
246
|
const msg = `Set 'allowTestPackages' capability to true in order to allow test packages installation.`;
|
|
@@ -302,14 +300,14 @@ export async function getApplicationInstallState(
|
|
|
302
300
|
const {versionCode: apkVersionCode, versionName: apkVersionNameStr} = apkInfo || {};
|
|
303
301
|
const apkVersionName = semver.valid(semver.coerce(apkVersionNameStr));
|
|
304
302
|
|
|
305
|
-
if (!
|
|
303
|
+
if (!Number.isInteger(apkVersionCode) || !Number.isInteger(pkgVersionCode)) {
|
|
306
304
|
log.warn(`Cannot read version codes of '${appPath}' and/or '${pkg}'`);
|
|
307
|
-
if (
|
|
305
|
+
if (typeof apkVersionName !== 'string' || typeof pkgVersionName !== 'string') {
|
|
308
306
|
log.warn(`Cannot read version names of '${appPath}' and/or '${pkg}'`);
|
|
309
307
|
return this.APP_INSTALL_STATE.UNKNOWN;
|
|
310
308
|
}
|
|
311
309
|
}
|
|
312
|
-
if (
|
|
310
|
+
if (Number.isInteger(apkVersionCode) && Number.isInteger(pkgVersionCode)) {
|
|
313
311
|
if ((pkgVersionCode as number) > (apkVersionCode as number)) {
|
|
314
312
|
log.debug(
|
|
315
313
|
`The version code of the installed '${pkg}' is greater than the application version code (${pkgVersionCode} > ${apkVersionCode})`,
|
|
@@ -319,8 +317,8 @@ export async function getApplicationInstallState(
|
|
|
319
317
|
// Version codes might not be maintained. Check version names.
|
|
320
318
|
if (pkgVersionCode === apkVersionCode) {
|
|
321
319
|
if (
|
|
322
|
-
|
|
323
|
-
|
|
320
|
+
typeof apkVersionName === 'string' &&
|
|
321
|
+
typeof pkgVersionName === 'string' &&
|
|
324
322
|
semver.satisfies(pkgVersionName, `>=${apkVersionName}`)
|
|
325
323
|
) {
|
|
326
324
|
log.debug(
|
|
@@ -330,7 +328,7 @@ export async function getApplicationInstallState(
|
|
|
330
328
|
? this.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED
|
|
331
329
|
: this.APP_INSTALL_STATE.SAME_VERSION_INSTALLED;
|
|
332
330
|
}
|
|
333
|
-
if (
|
|
331
|
+
if (typeof apkVersionName !== 'string' || typeof pkgVersionName !== 'string') {
|
|
334
332
|
log.debug(
|
|
335
333
|
`The version name of the installed '${pkg}' is equal to application version name (${pkgVersionCode} === ${apkVersionCode})`,
|
|
336
334
|
);
|
|
@@ -338,8 +336,8 @@ export async function getApplicationInstallState(
|
|
|
338
336
|
}
|
|
339
337
|
}
|
|
340
338
|
} else if (
|
|
341
|
-
|
|
342
|
-
|
|
339
|
+
typeof apkVersionName === 'string' &&
|
|
340
|
+
typeof pkgVersionName === 'string' &&
|
|
343
341
|
semver.satisfies(pkgVersionName, `>=${apkVersionName}`)
|
|
344
342
|
) {
|
|
345
343
|
log.debug(
|
|
@@ -467,7 +465,7 @@ export async function extractStringsFromApk(
|
|
|
467
465
|
appPath = await this.extractLanguageApk(appPath, language);
|
|
468
466
|
}
|
|
469
467
|
|
|
470
|
-
let apkStrings: StringRecord
|
|
468
|
+
let apkStrings: StringRecord;
|
|
471
469
|
let configMarker: string;
|
|
472
470
|
try {
|
|
473
471
|
await this.initAapt();
|
|
@@ -479,7 +477,7 @@ export async function extractStringsFromApk(
|
|
|
479
477
|
'configurations',
|
|
480
478
|
appPath,
|
|
481
479
|
]);
|
|
482
|
-
return
|
|
480
|
+
return util.uniq(stdout.split(os.EOL));
|
|
483
481
|
},
|
|
484
482
|
language,
|
|
485
483
|
'(default)',
|
|
@@ -508,7 +506,7 @@ export async function extractStringsFromApk(
|
|
|
508
506
|
'configurations',
|
|
509
507
|
appPath,
|
|
510
508
|
]);
|
|
511
|
-
return
|
|
509
|
+
return util.uniq(stdout.split(os.EOL));
|
|
512
510
|
},
|
|
513
511
|
language,
|
|
514
512
|
'',
|
|
@@ -525,18 +523,19 @@ export async function extractStringsFromApk(
|
|
|
525
523
|
const error = e as Error;
|
|
526
524
|
throw new Error(
|
|
527
525
|
`Cannot extract resources from '${originalAppPath}'. ` + `Original error: ${error.message}`,
|
|
526
|
+
{cause: e},
|
|
528
527
|
);
|
|
529
528
|
}
|
|
530
529
|
}
|
|
531
530
|
|
|
532
|
-
if (
|
|
531
|
+
if (util.isEmpty(apkStrings)) {
|
|
533
532
|
log.warn(
|
|
534
533
|
`No strings have been found in '${originalAppPath}' resources ` +
|
|
535
534
|
`for '${configMarker || 'default'}' configuration`,
|
|
536
535
|
);
|
|
537
536
|
} else {
|
|
538
537
|
log.info(
|
|
539
|
-
`Successfully extracted ${
|
|
538
|
+
`Successfully extracted ${Object.keys(apkStrings).length} strings from ` +
|
|
540
539
|
`'${originalAppPath}' resources for '${configMarker || 'default'}' configuration`,
|
|
541
540
|
);
|
|
542
541
|
}
|
|
@@ -609,10 +608,10 @@ export function parseAapt2Strings(rawOutput: string, configMarker: string): Stri
|
|
|
609
608
|
if (startIdx === idx) {
|
|
610
609
|
return [allLines[idx].substring(startCharPos + 1, terminationCharPos), idx];
|
|
611
610
|
}
|
|
612
|
-
return [`${result}\\n${
|
|
611
|
+
return [`${result}\\n${allLines[idx].substring(0, terminationCharPos).trimStart()}`, idx];
|
|
613
612
|
}
|
|
614
613
|
if (idx > startIdx) {
|
|
615
|
-
result += `\\n${
|
|
614
|
+
result += `\\n${allLines[idx].trimStart()}`;
|
|
616
615
|
} else {
|
|
617
616
|
result += allLines[idx].substring(startCharPos + 1);
|
|
618
617
|
}
|
|
@@ -628,7 +627,7 @@ export function parseAapt2Strings(rawOutput: string, configMarker: string): Stri
|
|
|
628
627
|
let lineIndex = 0;
|
|
629
628
|
while (lineIndex < allLines.length) {
|
|
630
629
|
const trimmedLine = allLines[lineIndex].trim();
|
|
631
|
-
if (
|
|
630
|
+
if (util.isEmpty(trimmedLine)) {
|
|
632
631
|
++lineIndex;
|
|
633
632
|
continue;
|
|
634
633
|
}
|
|
@@ -672,7 +671,7 @@ export function parseAapt2Strings(rawOutput: string, configMarker: string): Stri
|
|
|
672
671
|
if (isInCurrentConfig) {
|
|
673
672
|
const [content, idx] = extractContent(lineIndex);
|
|
674
673
|
lineIndex = idx;
|
|
675
|
-
if (
|
|
674
|
+
if (typeof content === 'string') {
|
|
676
675
|
apkStrings[currentResourceId] = [
|
|
677
676
|
...(Array.isArray(apkStrings[currentResourceId])
|
|
678
677
|
? apkStrings[currentResourceId]
|
|
@@ -684,7 +683,7 @@ export function parseAapt2Strings(rawOutput: string, configMarker: string): Stri
|
|
|
684
683
|
} else if (trimmedLine.startsWith(`(${configMarker})`)) {
|
|
685
684
|
const [content, idx] = extractContent(lineIndex);
|
|
686
685
|
lineIndex = idx;
|
|
687
|
-
if (
|
|
686
|
+
if (typeof content === 'string') {
|
|
688
687
|
apkStrings[currentResourceId] = content;
|
|
689
688
|
}
|
|
690
689
|
currentResourceId = null;
|
|
@@ -718,7 +717,7 @@ export function parseAaptStrings(rawOutput: string, configMarker: string): Strin
|
|
|
718
717
|
const quotedStringPattern = /"[^"\\]*(?:\\.[^"\\]*)*"/;
|
|
719
718
|
for (const line of rawOutput.split(os.EOL)) {
|
|
720
719
|
const trimmedLine = line.trim();
|
|
721
|
-
if (
|
|
720
|
+
if (util.isEmpty(trimmedLine)) {
|
|
722
721
|
continue;
|
|
723
722
|
}
|
|
724
723
|
|
package/lib/tools/apks-utils.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import {exec} from 'teen_process';
|
|
2
2
|
import {log} from '../logger';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import _ from 'lodash';
|
|
5
4
|
import {fs, tempDir, util} from '@appium/support';
|
|
6
5
|
import {LRUCache} from 'lru-cache';
|
|
7
|
-
import {getJavaForOs, unzipFile, buildInstallArgs, APK_INSTALL_TIMEOUT} from '../helpers';
|
|
8
6
|
import AsyncLock from 'async-lock';
|
|
9
7
|
import type {ADB} from '../adb';
|
|
10
8
|
import type {InstallMultipleApksOptions, InstallApksOptions, StringRecord} from './types';
|
|
9
|
+
import {APK_INSTALL_TIMEOUT, buildInstallArgs, getJavaForOs, unzipFile} from '../utils';
|
|
11
10
|
|
|
12
11
|
const BASE_APK = 'base-master.apk';
|
|
13
12
|
const LANGUAGE_APK = (lang: string) => `base-${lang}.apk`;
|
|
@@ -65,7 +64,7 @@ export async function execBundletool(this: ADB, args: string[], errorMsg: string
|
|
|
65
64
|
env,
|
|
66
65
|
timeout: BUNDLETOOL_TIMEOUT_MS,
|
|
67
66
|
}));
|
|
68
|
-
log.debug(`Command stdout: ${
|
|
67
|
+
log.debug(`Command stdout: ${util.truncateString(stdout, {length: 300})}`);
|
|
69
68
|
return stdout;
|
|
70
69
|
} catch (e) {
|
|
71
70
|
const err = e as Error & {stdout?: string; stderr?: string};
|
|
@@ -75,7 +74,7 @@ export async function execBundletool(this: ADB, args: string[], errorMsg: string
|
|
|
75
74
|
if (err.stderr) {
|
|
76
75
|
log.debug(`Command stderr: ${err.stderr}`);
|
|
77
76
|
}
|
|
78
|
-
throw new Error(`${errorMsg}. Original error: ${err.message}
|
|
77
|
+
throw new Error(`${errorMsg}. Original error: ${err.message}`, {cause: e});
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -240,7 +239,7 @@ export function isTestPackageOnlyError(output: string): boolean {
|
|
|
240
239
|
* apks file is not a valid bundle
|
|
241
240
|
*/
|
|
242
241
|
async function extractFromApks(apks: string, dstPath: string | string[]): Promise<string> {
|
|
243
|
-
const normalizedDstPath =
|
|
242
|
+
const normalizedDstPath = Array.isArray(dstPath) ? dstPath : [dstPath];
|
|
244
243
|
|
|
245
244
|
return await APKS_CACHE_GUARD.acquire(apks, async () => {
|
|
246
245
|
// It might be that the original file has been replaced,
|