appium-adb 14.1.0 → 14.1.2

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/adb.d.ts.map +1 -1
  3. package/build/lib/adb.js.map +1 -1
  4. package/build/lib/helpers.d.ts.map +1 -1
  5. package/build/lib/helpers.js +3 -3
  6. package/build/lib/helpers.js.map +1 -1
  7. package/build/lib/logcat.d.ts.map +1 -1
  8. package/build/lib/logcat.js +16 -6
  9. package/build/lib/logcat.js.map +1 -1
  10. package/build/lib/logger.js.map +1 -1
  11. package/build/lib/tools/aab-utils.d.ts.map +1 -1
  12. package/build/lib/tools/aab-utils.js +25 -18
  13. package/build/lib/tools/aab-utils.js.map +1 -1
  14. package/build/lib/tools/android-manifest.d.ts.map +1 -1
  15. package/build/lib/tools/android-manifest.js +36 -24
  16. package/build/lib/tools/android-manifest.js.map +1 -1
  17. package/build/lib/tools/apk-signing.d.ts.map +1 -1
  18. package/build/lib/tools/apk-signing.js +58 -37
  19. package/build/lib/tools/apk-signing.js.map +1 -1
  20. package/build/lib/tools/apk-utils.d.ts.map +1 -1
  21. package/build/lib/tools/apk-utils.js +46 -38
  22. package/build/lib/tools/apk-utils.js.map +1 -1
  23. package/build/lib/tools/apks-utils.d.ts.map +1 -1
  24. package/build/lib/tools/apks-utils.js +21 -14
  25. package/build/lib/tools/apks-utils.js.map +1 -1
  26. package/build/lib/tools/app-commands.d.ts.map +1 -1
  27. package/build/lib/tools/app-commands.js +44 -45
  28. package/build/lib/tools/app-commands.js.map +1 -1
  29. package/build/lib/tools/device-settings.d.ts.map +1 -1
  30. package/build/lib/tools/device-settings.js +38 -32
  31. package/build/lib/tools/device-settings.js.map +1 -1
  32. package/build/lib/tools/emu-constants.d.ts.map +1 -1
  33. package/build/lib/tools/emu-constants.js +4 -4
  34. package/build/lib/tools/emu-constants.js.map +1 -1
  35. package/build/lib/tools/emulator-commands.d.ts.map +1 -1
  36. package/build/lib/tools/emulator-commands.js +20 -17
  37. package/build/lib/tools/emulator-commands.js.map +1 -1
  38. package/build/lib/tools/fs-commands.d.ts.map +1 -1
  39. package/build/lib/tools/fs-commands.js +2 -1
  40. package/build/lib/tools/fs-commands.js.map +1 -1
  41. package/build/lib/tools/general-commands.d.ts.map +1 -1
  42. package/build/lib/tools/general-commands.js +11 -15
  43. package/build/lib/tools/general-commands.js.map +1 -1
  44. package/build/lib/tools/keyboard-commands.d.ts.map +1 -1
  45. package/build/lib/tools/keyboard-commands.js.map +1 -1
  46. package/build/lib/tools/lockmgmt.d.ts.map +1 -1
  47. package/build/lib/tools/lockmgmt.js +24 -23
  48. package/build/lib/tools/lockmgmt.js.map +1 -1
  49. package/build/lib/tools/logcat-commands.d.ts.map +1 -1
  50. package/build/lib/tools/logcat-commands.js.map +1 -1
  51. package/build/lib/tools/network-commands.d.ts.map +1 -1
  52. package/build/lib/tools/network-commands.js +0 -1
  53. package/build/lib/tools/network-commands.js.map +1 -1
  54. package/build/lib/tools/process-commands.d.ts.map +1 -1
  55. package/build/lib/tools/process-commands.js +1 -1
  56. package/build/lib/tools/process-commands.js.map +1 -1
  57. package/build/lib/tools/system-calls.d.ts.map +1 -1
  58. package/build/lib/tools/system-calls.js +30 -36
  59. package/build/lib/tools/system-calls.js.map +1 -1
  60. package/build/lib/tools/types.d.ts +6 -6
  61. package/build/lib/tools/types.d.ts.map +1 -1
  62. package/lib/adb.ts +20 -25
  63. package/lib/helpers.ts +48 -36
  64. package/lib/logcat.ts +32 -22
  65. package/lib/logger.ts +1 -2
  66. package/lib/tools/aab-utils.js +42 -33
  67. package/lib/tools/android-manifest.js +78 -54
  68. package/lib/tools/apk-signing.ts +123 -89
  69. package/lib/tools/apk-utils.ts +206 -109
  70. package/lib/tools/apks-utils.js +50 -40
  71. package/lib/tools/app-commands.ts +220 -135
  72. package/lib/tools/device-settings.ts +154 -124
  73. package/lib/tools/emu-constants.ts +4 -5
  74. package/lib/tools/emulator-commands.ts +113 -65
  75. package/lib/tools/fs-commands.js +9 -8
  76. package/lib/tools/general-commands.js +48 -51
  77. package/lib/tools/keyboard-commands.js +22 -20
  78. package/lib/tools/lockmgmt.js +80 -51
  79. package/lib/tools/logcat-commands.js +6 -6
  80. package/lib/tools/network-commands.js +11 -12
  81. package/lib/tools/process-commands.ts +28 -15
  82. package/lib/tools/system-calls.ts +319 -221
  83. package/lib/tools/types.ts +19 -10
  84. package/package.json +4 -3
package/lib/helpers.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import path from 'path';
2
- import { system, fs, zip, util } from '@appium/support';
3
- import { log } from './logger.js';
2
+ import {system, fs, zip, util} from '@appium/support';
3
+ import {log} from './logger.js';
4
4
  import _ from 'lodash';
5
- import { exec, type ExecError } from 'teen_process';
6
- import type { ADB } from './adb.js';
7
- import type { ApkManifest } from './tools/types.js';
5
+ import {exec, type ExecError} from 'teen_process';
6
+ import type {ADB} from './adb.js';
7
+ import type {ApkManifest} from './tools/types.js';
8
8
 
9
9
  // Declare __filename for CommonJS compatibility
10
10
  declare const __filename: string;
@@ -21,12 +21,16 @@ const MODULE_NAME = 'appium-adb';
21
21
  /**
22
22
  * Calculates the absolute path to the given resource
23
23
  */
24
- export const getResourcePath = _.memoize(async function getResourcePath (relPath: string): Promise<string> {
24
+ export const getResourcePath = _.memoize(async function getResourcePath(
25
+ relPath: string,
26
+ ): Promise<string> {
25
27
  const moduleRoot = await getModuleRoot();
26
28
  const resultPath = path.resolve(moduleRoot, relPath);
27
- if (!await fs.exists(resultPath)) {
28
- throw new Error(`Cannot find the resource '${relPath}' under the '${moduleRoot}' ` +
29
- `folder of ${MODULE_NAME} Node.js module`);
29
+ if (!(await fs.exists(resultPath))) {
30
+ throw new Error(
31
+ `Cannot find the resource '${relPath}' under the '${moduleRoot}' ` +
32
+ `folder of ${MODULE_NAME} Node.js module`,
33
+ );
30
34
  }
31
35
  return resultPath;
32
36
  });
@@ -34,21 +38,26 @@ export const getResourcePath = _.memoize(async function getResourcePath (relPath
34
38
  /**
35
39
  * Retrieves the actual path to SDK root folder from the system environment
36
40
  */
37
- export function getSdkRootFromEnv (): string | undefined {
41
+ export function getSdkRootFromEnv(): string | undefined {
38
42
  return process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
39
43
  }
40
44
 
41
45
  /**
42
46
  * Retrieves the actual path to SDK root folder
43
47
  */
44
- export async function requireSdkRoot (customRoot: string | null = null): Promise<string> {
48
+ export async function requireSdkRoot(customRoot: string | null = null): Promise<string> {
45
49
  const sdkRoot = customRoot || getSdkRootFromEnv();
46
- const docMsg = 'Read https://developer.android.com/studio/command-line/variables for more details';
50
+ const docMsg =
51
+ 'Read https://developer.android.com/studio/command-line/variables for more details';
47
52
  if (!sdkRoot || _.isEmpty(sdkRoot)) {
48
- throw new Error(`Neither ANDROID_HOME nor ANDROID_SDK_ROOT environment variable was exported. ${docMsg}`);
53
+ throw new Error(
54
+ `Neither ANDROID_HOME nor ANDROID_SDK_ROOT environment variable was exported. ${docMsg}`,
55
+ );
49
56
  }
50
- if (!await fs.exists(sdkRoot)) {
51
- throw new Error(`The Android SDK root folder '${sdkRoot}' does not exist on the local file system. ${docMsg}`);
57
+ if (!(await fs.exists(sdkRoot))) {
58
+ throw new Error(
59
+ `The Android SDK root folder '${sdkRoot}' does not exist on the local file system. ${docMsg}`,
60
+ );
52
61
  }
53
62
 
54
63
  const stats = await fs.stat(sdkRoot);
@@ -62,19 +71,22 @@ export async function requireSdkRoot (customRoot: string | null = null): Promise
62
71
  * @param zipPath
63
72
  * @param dstRoot
64
73
  */
65
- export async function unzipFile (zipPath: string, dstRoot: string = path.dirname(zipPath)): Promise<void> {
74
+ export async function unzipFile(
75
+ zipPath: string,
76
+ dstRoot: string = path.dirname(zipPath),
77
+ ): Promise<void> {
66
78
  log.debug(`Unzipping '${zipPath}' to '${dstRoot}'`);
67
79
  await zip.assertValidZip(zipPath);
68
80
  await zip.extractAllTo(zipPath, dstRoot);
69
81
  log.debug('Unzip successful');
70
82
  }
71
83
 
72
- export const getJavaHome = _.memoize(async function getJavaHome (): Promise<string> {
84
+ export const getJavaHome = _.memoize(async function getJavaHome(): Promise<string> {
73
85
  const result = process.env.JAVA_HOME;
74
86
  if (!result) {
75
87
  throw new Error('The JAVA_HOME environment variable is not set for the current process');
76
88
  }
77
- if (!await fs.exists(result)) {
89
+ if (!(await fs.exists(result))) {
78
90
  throw new Error(`The JAVA_HOME location '${result}' must exist`);
79
91
  }
80
92
  const stats = await fs.stat(result);
@@ -84,7 +96,7 @@ export const getJavaHome = _.memoize(async function getJavaHome (): Promise<stri
84
96
  return result;
85
97
  });
86
98
 
87
- export const getJavaForOs = _.memoize(async function getJavaForOs (): Promise<string> {
99
+ export const getJavaForOs = _.memoize(async function getJavaForOs(): Promise<string> {
88
100
  let javaHome: string | undefined;
89
101
  let errMsg: string | undefined;
90
102
  try {
@@ -105,16 +117,18 @@ export const getJavaForOs = _.memoize(async function getJavaForOs (): Promise<st
105
117
  } catch {
106
118
  // Ignore and throw custom error below
107
119
  }
108
- throw new Error(`The '${executableName}' binary could not be found ` +
109
- `neither in PATH nor under JAVA_HOME (${javaHome ? path.resolve(javaHome, 'bin') : errMsg})`);
120
+ throw new Error(
121
+ `The '${executableName}' binary could not be found ` +
122
+ `neither in PATH nor under JAVA_HOME (${javaHome ? path.resolve(javaHome, 'bin') : errMsg})`,
123
+ );
110
124
  });
111
125
 
112
126
  /**
113
127
  * Transforms given options into the list of `adb install.install-multiple` command arguments
114
128
  */
115
- export function buildInstallArgs (
129
+ export function buildInstallArgs(
116
130
  apiLevel: number,
117
- options: BuildInstallArgsOptions = {}
131
+ options: BuildInstallArgsOptions = {},
118
132
  ): string[] {
119
133
  const result: string[] = [];
120
134
 
@@ -129,9 +143,11 @@ export function buildInstallArgs (
129
143
  }
130
144
  if (options.grantPermissions) {
131
145
  if (apiLevel < 23) {
132
- log.debug(`Skipping permissions grant option, since ` +
133
- `the current API level ${apiLevel} does not support applications ` +
134
- `permissions customization`);
146
+ log.debug(
147
+ `Skipping permissions grant option, since ` +
148
+ `the current API level ${apiLevel} does not support applications ` +
149
+ `permissions customization`,
150
+ );
135
151
  } else {
136
152
  result.push('-g');
137
153
  }
@@ -148,7 +164,7 @@ export function buildInstallArgs (
148
164
  * Extracts various package manifest details
149
165
  * from the given application file.
150
166
  */
151
- export async function readPackageManifest (this: ADB, apkPath: string): Promise<ApkManifest> {
167
+ export async function readPackageManifest(this: ADB, apkPath: string): Promise<ApkManifest> {
152
168
  await this.initAapt2();
153
169
  const aapt2Binary = this.binaries?.aapt2;
154
170
  if (!aapt2Binary) {
@@ -173,7 +189,7 @@ export async function readPackageManifest (this: ADB, apkPath: string): Promise<
173
189
  const extractValue = (
174
190
  line: string,
175
191
  propPattern: RegExp,
176
- valueTransformer: ((x: string) => any) | null
192
+ valueTransformer: ((x: string) => any) | null,
177
193
  ): any => {
178
194
  const match = propPattern.exec(line);
179
195
  if (match) {
@@ -184,7 +200,7 @@ export async function readPackageManifest (this: ADB, apkPath: string): Promise<
184
200
  const extractArray = (
185
201
  line: string,
186
202
  propPattern: RegExp,
187
- valueTransformer: ((x: string) => any) | null
203
+ valueTransformer: ((x: string) => any) | null,
188
204
  ): any[] => {
189
205
  let match: RegExpExecArray | null;
190
206
  const resultArray: any[] = [];
@@ -220,11 +236,7 @@ export async function readPackageManifest (this: ADB, apkPath: string): Promise<
220
236
  ['compileSdkVersion', /compileSdkVersion='([^']+)'/, toInt],
221
237
  ['compileSdkVersionCodename', /compileSdkVersionCodename='([^']+)'/, null],
222
238
  ] as const) {
223
- const value = extractValue(
224
- line,
225
- pattern,
226
- transformer
227
- );
239
+ const value = extractValue(line, pattern, transformer);
228
240
  if (!_.isUndefined(value)) {
229
241
  (result as Record<string, any>)[name] = value;
230
242
  }
@@ -271,7 +283,7 @@ export async function readPackageManifest (this: ADB, apkPath: string): Promise<
271
283
  /**
272
284
  * Calculates the absolute path to the current module's root folder
273
285
  */
274
- const getModuleRoot = _.memoize(async function getModuleRoot (): Promise<string> {
286
+ const getModuleRoot = _.memoize(async function getModuleRoot(): Promise<string> {
275
287
  let moduleRoot = path.dirname(path.resolve(__filename));
276
288
  let isAtFsRoot = false;
277
289
  while (!isAtFsRoot) {
@@ -279,7 +291,7 @@ const getModuleRoot = _.memoize(async function getModuleRoot (): Promise<string>
279
291
  try {
280
292
  if (await fs.exists(manifestPath)) {
281
293
  const manifestContent = await fs.readFile(manifestPath, 'utf8');
282
- const manifest = JSON.parse(manifestContent) as { name?: string };
294
+ const manifest = JSON.parse(manifestContent) as {name?: string};
283
295
  if (manifest.name === MODULE_NAME) {
284
296
  return moduleRoot;
285
297
  }
package/lib/logcat.ts CHANGED
@@ -1,20 +1,26 @@
1
- import { logger, util } from '@appium/support';
1
+ import {logger, util} from '@appium/support';
2
2
  import B from 'bluebird';
3
3
  import _ from 'lodash';
4
- import { EventEmitter } from 'node:events';
5
- import { SubProcess, exec } from 'teen_process';
6
- import { LRUCache } from 'lru-cache';
7
- import type { ExecError } from 'teen_process';
8
- import type { ADBExecutable } from './types';
9
- import type {
10
- LogEntry,
11
- LogcatOpts as StartCaptureOptions,
12
- } from './tools/types';
4
+ import {EventEmitter} from 'node:events';
5
+ import {SubProcess, exec} from 'teen_process';
6
+ import {LRUCache} from 'lru-cache';
7
+ import type {ExecError} from 'teen_process';
8
+ import type {ADBExecutable} from './types';
9
+ import type {LogEntry, LogcatOpts as StartCaptureOptions} from './tools/types';
13
10
 
14
11
  const log = logger.getLogger('Logcat');
15
12
  const MAX_BUFFER_SIZE = 10000;
16
13
  const LOGCAT_PROC_STARTUP_TIMEOUT = 10000;
17
- const SUPPORTED_FORMATS = ['brief', 'process', 'tag', 'thread', 'raw', 'time', 'threadtime', 'long'] as const;
14
+ const SUPPORTED_FORMATS = [
15
+ 'brief',
16
+ 'process',
17
+ 'tag',
18
+ 'thread',
19
+ 'raw',
20
+ 'time',
21
+ 'threadtime',
22
+ 'long',
23
+ ] as const;
18
24
  const SUPPORTED_PRIORITIES = ['v', 'd', 'i', 'w', 'e', 'f', 's'] as const;
19
25
  const DEFAULT_PRIORITY = 'v';
20
26
  const DEFAULT_TAG = '*';
@@ -70,14 +76,12 @@ export class Logcat extends EventEmitter {
70
76
  await this.clear();
71
77
  }
72
78
 
73
- const {
74
- format = DEFAULT_FORMAT,
75
- filterSpecs = [],
76
- } = opts;
79
+ const {format = DEFAULT_FORMAT, filterSpecs = []} = opts;
77
80
  const cmd = [
78
81
  ...this.adb.defaultArgs,
79
82
  'logcat',
80
- '-v', requireFormat(format),
83
+ '-v',
84
+ requireFormat(format),
81
85
  ...formatFilterSpecs(filterSpecs),
82
86
  ];
83
87
  log.debug(`Starting logs capture with command: ${util.quote([this.adb.path, ...cmd])}`);
@@ -129,8 +133,10 @@ export class Logcat extends EventEmitter {
129
133
  continue;
130
134
  }
131
135
  const [message, timestamp] = value;
132
- if (this.logIndexSinceLastRequest && index > this.logIndexSinceLastRequest
133
- || !this.logIndexSinceLastRequest) {
136
+ if (
137
+ (this.logIndexSinceLastRequest && index > this.logIndexSinceLastRequest) ||
138
+ !this.logIndexSinceLastRequest
139
+ ) {
134
140
  recentLogIndex = index;
135
141
  result.push(toLogEntry(message, timestamp));
136
142
  }
@@ -185,7 +191,7 @@ export default Logcat;
185
191
 
186
192
  // Private entities
187
193
 
188
- type LogFormat = typeof SUPPORTED_FORMATS[number];
194
+ type LogFormat = (typeof SUPPORTED_FORMATS)[number];
189
195
 
190
196
  function requireFormat(format: string): LogFormat {
191
197
  if (!SUPPORTED_FORMATS.includes(format as LogFormat)) {
@@ -213,11 +219,15 @@ function requireSpec(spec: string): string {
213
219
  resultTag = DEFAULT_TAG;
214
220
  }
215
221
  if (!priority) {
216
- log.info(`The priority value in spec '${spec}' is empty. Defaulting to Verbose (${DEFAULT_PRIORITY})`);
222
+ log.info(
223
+ `The priority value in spec '${spec}' is empty. Defaulting to Verbose (${DEFAULT_PRIORITY})`,
224
+ );
217
225
  return `${resultTag}:${DEFAULT_PRIORITY}`;
218
226
  }
219
227
  if (!SUPPORTED_PRIORITIES.some((p) => _.toLower(priority) === _.toLower(p))) {
220
- log.info(`The priority value in spec '${spec}' is unknown. Supported values are: ${SUPPORTED_PRIORITIES}`);
228
+ log.info(
229
+ `The priority value in spec '${spec}' is unknown. Supported values are: ${SUPPORTED_PRIORITIES}`,
230
+ );
221
231
  log.info(`Defaulting to Verbose (${DEFAULT_PRIORITY})`);
222
232
  return `${resultTag}:${DEFAULT_PRIORITY}`;
223
233
  }
@@ -230,5 +240,5 @@ function formatFilterSpecs(filterSpecs: string | string[]): string[] {
230
240
  }
231
241
  return filterSpecs
232
242
  .filter((spec) => spec && _.isString(spec) && !spec.startsWith('-'))
233
- .map((spec) => spec.includes(':') ? requireSpec(spec) : spec);
243
+ .map((spec) => (spec.includes(':') ? requireSpec(spec) : spec));
234
244
  }
package/lib/logger.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { logger } from '@appium/support';
1
+ import {logger} from '@appium/support';
2
2
 
3
3
  export const log = logger.getLogger('ADB');
4
-
@@ -1,8 +1,8 @@
1
- import { log } from '../logger.js';
1
+ import {log} from '../logger.js';
2
2
  import path from 'path';
3
- import { fs, tempDir, util } from '@appium/support';
4
- import { LRUCache } from 'lru-cache';
5
- import { unzipFile } from '../helpers.js';
3
+ import {fs, tempDir, util} from '@appium/support';
4
+ import {LRUCache} from 'lru-cache';
5
+ import {unzipFile} from '../helpers.js';
6
6
  import AsyncLock from 'async-lock';
7
7
  import B from 'bluebird';
8
8
  import crypto from 'crypto';
@@ -21,19 +21,19 @@ process.on('exit', () => {
21
21
  }
22
22
 
23
23
  const paths = /** @type {string[]} */ ([...AAB_CACHE.values()]);
24
- log.debug(`Performing cleanup of ${paths.length} cached .aab ` +
25
- util.pluralize('package', paths.length));
24
+ log.debug(
25
+ `Performing cleanup of ${paths.length} cached .aab ` + util.pluralize('package', paths.length),
26
+ );
26
27
  for (const appPath of paths) {
27
28
  try {
28
29
  // Asynchronous calls are not supported in onExit handler
29
30
  fs.rimrafSync(appPath);
30
31
  } catch (e) {
31
- log.warn((/** @type {Error} */ (e)).message);
32
+ log.warn(/** @type {Error} */ (e).message);
32
33
  }
33
34
  }
34
35
  });
35
36
 
36
-
37
37
  /**
38
38
  * Builds a universal .apk from the given .aab package. See
39
39
  * https://developer.android.com/studio/command-line/bundletool#generate_apks
@@ -46,8 +46,8 @@ process.on('exit', () => {
46
46
  * by default.
47
47
  * @throws {Error} If there was an error while creating the universal .apk
48
48
  */
49
- export async function extractUniversalApk (aabPath, opts = {}) {
50
- if (!await fs.exists(aabPath)) {
49
+ export async function extractUniversalApk(aabPath, opts = {}) {
50
+ if (!(await fs.exists(aabPath))) {
51
51
  throw new Error(`The file at '${aabPath}' either does not exist or is not accessible`);
52
52
  }
53
53
 
@@ -58,21 +58,19 @@ export async function extractUniversalApk (aabPath, opts = {}) {
58
58
  try {
59
59
  return await AAB_CACHE_GUARD.acquire(aabPath, async () => {
60
60
  const aabHash = await fs.hash(aabPath);
61
- const {
62
- keystore,
63
- keystorePassword,
64
- keyAlias,
65
- keyPassword,
66
- } = opts;
61
+ const {keystore, keystorePassword, keyAlias, keyPassword} = opts;
67
62
  let cacheHash = aabHash;
68
63
  if (keystore) {
69
- if (!await fs.exists(keystore)) {
70
- throw new Error(`The keystore file at '${keystore}' either does not exist ` +
71
- `or is not accessible`);
64
+ if (!(await fs.exists(keystore))) {
65
+ throw new Error(
66
+ `The keystore file at '${keystore}' either does not exist ` + `or is not accessible`,
67
+ );
72
68
  }
73
69
  if (!keystorePassword || !keyAlias || !keyPassword) {
74
- throw new Error('It is mandatory to also provide keystore password, key alias, ' +
75
- 'and key password if the keystore path is set');
70
+ throw new Error(
71
+ 'It is mandatory to also provide keystore password, key alias, ' +
72
+ 'and key password if the keystore path is set',
73
+ );
76
74
  }
77
75
  const keystoreHash = await fs.hash(keystore);
78
76
  const keyAliasHash = crypto.createHash('sha1');
@@ -91,16 +89,25 @@ export async function extractUniversalApk (aabPath, opts = {}) {
91
89
  await this.initAapt2();
92
90
  const args = [
93
91
  'build-apks',
94
- '--aapt2', (/** @type {import('./types').StringRecord} */ (this.binaries)).aapt2,
95
- '--bundle', aabPath,
96
- '--output', tmpApksPath,
97
- ...(keystore ? [
98
- '--ks', keystore,
99
- '--ks-pass', `pass:${keystorePassword}`,
100
- '--ks-key-alias', keyAlias,
101
- '--key-pass', `pass:${keyPassword}`,
102
- ] : []),
103
- '--mode=universal'
92
+ '--aapt2',
93
+ /** @type {import('./types').StringRecord} */ (this.binaries).aapt2,
94
+ '--bundle',
95
+ aabPath,
96
+ '--output',
97
+ tmpApksPath,
98
+ ...(keystore
99
+ ? [
100
+ '--ks',
101
+ keystore,
102
+ '--ks-pass',
103
+ `pass:${keystorePassword}`,
104
+ '--ks-key-alias',
105
+ keyAlias,
106
+ '--key-pass',
107
+ `pass:${keyPassword}`,
108
+ ]
109
+ : []),
110
+ '--mode=universal',
104
111
  ];
105
112
  log.debug(`Preparing universal .apks bundle from '${aabPath}'`);
106
113
  await this.execBundletool(args, `Cannot build a universal .apks bundle from '${aabPath}'`);
@@ -123,8 +130,10 @@ export async function extractUniversalApk (aabPath, opts = {}) {
123
130
  } catch {}
124
131
  if (!universalApkPath) {
125
132
  log.debug(`The following items were extracted from the .aab bundle: ${allFileNames}`);
126
- throw new Error(`${UNIVERSAL_APK} cannot be found in '${aabPath}' bundle. ` +
127
- `Does the archive contain a valid application bundle?`);
133
+ throw new Error(
134
+ `${UNIVERSAL_APK} cannot be found in '${aabPath}' bundle. ` +
135
+ `Does the archive contain a valid application bundle?`,
136
+ );
128
137
  }
129
138
  const resultPath = path.join(tmpRoot, apkName);
130
139
  log.debug(`Found ${UNIVERSAL_APK} at '${universalApkPath}'. Caching it to '${resultPath}'`);
@@ -1,12 +1,8 @@
1
1
  import _ from 'lodash';
2
- import { exec } from 'teen_process';
3
- import { log } from '../logger.js';
4
- import {
5
- unzipFile,
6
- APKS_EXTENSION,
7
- readPackageManifest,
8
- } from '../helpers.js';
9
- import { fs, zip, tempDir, util } from '@appium/support';
2
+ import {exec} from 'teen_process';
3
+ import {log} from '../logger.js';
4
+ import {unzipFile, APKS_EXTENSION, readPackageManifest} from '../helpers.js';
5
+ import {fs, zip, tempDir, util} from '@appium/support';
10
6
  import path from 'path';
11
7
 
12
8
  /**
@@ -18,16 +14,14 @@ import path from 'path';
18
14
  * @throws {error} If there was an error while getting the data from the given
19
15
  * application package.
20
16
  */
21
- export async function packageAndLaunchActivityFromManifest (appPath) {
17
+ export async function packageAndLaunchActivityFromManifest(appPath) {
22
18
  if (appPath.endsWith(APKS_EXTENSION)) {
23
19
  appPath = await this.extractBaseApk(appPath);
24
20
  }
25
21
 
26
22
  const {
27
23
  name: apkPackage,
28
- launchableActivity: {
29
- name: apkActivity,
30
- },
24
+ launchableActivity: {name: apkActivity},
31
25
  } = await readPackageManifest.bind(this)(appPath);
32
26
  log.info(`Package name: '${apkPackage}'`);
33
27
  log.info(`Main activity name: '${apkActivity}'`);
@@ -43,7 +37,7 @@ export async function packageAndLaunchActivityFromManifest (appPath) {
43
37
  * @throws {error} If there was an error while getting the data from the given
44
38
  * application package.
45
39
  */
46
- export async function targetSdkVersionFromManifest (appPath) {
40
+ export async function targetSdkVersionFromManifest(appPath) {
47
41
  log.debug(`Extracting target SDK version of '${appPath}'`);
48
42
  const originalAppPath = appPath;
49
43
  if (appPath.endsWith(APKS_EXTENSION)) {
@@ -54,7 +48,7 @@ export async function targetSdkVersionFromManifest (appPath) {
54
48
  if (!targetSdkVersion) {
55
49
  throw new Error(
56
50
  `Cannot extract targetSdkVersion of '${originalAppPath}'. Does ` +
57
- `the package manifest define it?`
51
+ `the package manifest define it?`,
58
52
  );
59
53
  }
60
54
  return targetSdkVersion;
@@ -69,8 +63,8 @@ export async function targetSdkVersionFromManifest (appPath) {
69
63
  * _dumpsys package_ command. It may speed up the method execution.
70
64
  * @return {Promise<number>} The version of the target SDK.
71
65
  */
72
- export async function targetSdkVersionUsingPKG (pkg, cmdOutput = null) {
73
- const stdout = cmdOutput || await this.shell(['dumpsys', 'package', pkg]);
66
+ export async function targetSdkVersionUsingPKG(pkg, cmdOutput = null) {
67
+ const stdout = cmdOutput || (await this.shell(['dumpsys', 'package', pkg]));
74
68
  const targetSdkVersionMatch = new RegExp(/targetSdk=([^\s\s]+)/g).exec(stdout);
75
69
  return targetSdkVersionMatch && targetSdkVersionMatch.length >= 2
76
70
  ? parseInt(targetSdkVersionMatch[1], 10)
@@ -87,10 +81,14 @@ export async function targetSdkVersionUsingPKG (pkg, cmdOutput = null) {
87
81
  * @param {string} manifestPackage - The name of the manifest package
88
82
  * @param {string} targetPackage - The name of the destination package
89
83
  */
90
- export async function compileManifest (manifest, manifestPackage, targetPackage) {
91
- const {platform, platformPath} = await getAndroidPlatformAndPath(/** @type {string} */ (this.sdkRoot));
84
+ export async function compileManifest(manifest, manifestPackage, targetPackage) {
85
+ const {platform, platformPath} = await getAndroidPlatformAndPath(
86
+ /** @type {string} */ (this.sdkRoot),
87
+ );
92
88
  if (!platform || !platformPath) {
93
- throw new Error('Cannot compile the manifest. The required platform does not exist (API level >= 17)');
89
+ throw new Error(
90
+ 'Cannot compile the manifest. The required platform does not exist (API level >= 17)',
91
+ );
94
92
  }
95
93
  const resultPath = `${manifest}.apk`;
96
94
  const androidJarPath = path.resolve(platformPath, 'android.jar');
@@ -102,37 +100,53 @@ export async function compileManifest (manifest, manifestPackage, targetPackage)
102
100
  // https://developer.android.com/studio/command-line/aapt2
103
101
  const args = [
104
102
  'link',
105
- '-o', resultPath,
106
- '--manifest', manifest,
107
- '--rename-manifest-package', manifestPackage,
108
- '--rename-instrumentation-target-package', targetPackage,
109
- '-I', androidJarPath,
103
+ '-o',
104
+ resultPath,
105
+ '--manifest',
106
+ manifest,
107
+ '--rename-manifest-package',
108
+ manifestPackage,
109
+ '--rename-instrumentation-target-package',
110
+ targetPackage,
111
+ '-I',
112
+ androidJarPath,
110
113
  '-v',
111
114
  ];
112
- log.debug(`Compiling the manifest using '${util.quote([
113
- (/** @type {import('./types').StringRecord} */ (this.binaries)).aapt2,
114
- ...args
115
- ])}'`);
116
- await exec((/** @type {import('./types').StringRecord} */ (this.binaries)).aapt2, args);
115
+ log.debug(
116
+ `Compiling the manifest using '${util.quote([
117
+ /** @type {import('./types').StringRecord} */ (this.binaries).aapt2,
118
+ ...args,
119
+ ])}'`,
120
+ );
121
+ await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt2, args);
117
122
  } catch (e) {
118
- log.debug('Cannot compile the manifest using aapt2. Defaulting to aapt. ' +
119
- `Original error: ${e.stderr || e.message}`);
123
+ log.debug(
124
+ 'Cannot compile the manifest using aapt2. Defaulting to aapt. ' +
125
+ `Original error: ${e.stderr || e.message}`,
126
+ );
120
127
  await this.initAapt();
121
128
  const args = [
122
129
  'package',
123
- '-M', manifest,
124
- '--rename-manifest-package', manifestPackage,
125
- '--rename-instrumentation-target-package', targetPackage,
126
- '-I', androidJarPath,
127
- '-F', resultPath,
130
+ '-M',
131
+ manifest,
132
+ '--rename-manifest-package',
133
+ manifestPackage,
134
+ '--rename-instrumentation-target-package',
135
+ targetPackage,
136
+ '-I',
137
+ androidJarPath,
138
+ '-F',
139
+ resultPath,
128
140
  '-f',
129
141
  ];
130
- log.debug(`Compiling the manifest using '${util.quote([
131
- (/** @type {import('./types').StringRecord} */ (this.binaries)).aapt,
132
- ...args
133
- ])}'`);
142
+ log.debug(
143
+ `Compiling the manifest using '${util.quote([
144
+ /** @type {import('./types').StringRecord} */ (this.binaries).aapt,
145
+ ...args,
146
+ ])}'`,
147
+ );
134
148
  try {
135
- await exec((/** @type {import('./types').StringRecord} */ (this.binaries)).aapt, args);
149
+ await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt, args);
136
150
  } catch (e1) {
137
151
  throw new Error(`Cannot compile the manifest. Original error: ${e1.stderr || e1.message}`);
138
152
  }
@@ -154,7 +168,7 @@ export async function compileManifest (manifest, manifestPackage, targetPackage)
154
168
  * @param {string} dstApk - Full path to the resulting package.
155
169
  * The file will be overridden if it already exists.
156
170
  */
157
- export async function insertManifest (manifest, srcApk, dstApk) {
171
+ export async function insertManifest(manifest, srcApk, dstApk) {
158
172
  log.debug(`Inserting manifest '${manifest}', src: '${srcApk}', dst: '${dstApk}'`);
159
173
  await zip.assertValidZip(srcApk);
160
174
  await unzipFile(`${manifest}.apk`);
@@ -164,16 +178,22 @@ export async function insertManifest (manifest, srcApk, dstApk) {
164
178
  await fs.copyFile(srcApk, dstApk);
165
179
  log.debug('Moving manifest');
166
180
  try {
167
- await exec((/** @type {import('./types').StringRecord} */ (this.binaries)).aapt, [
168
- 'remove', dstApk, manifestName
181
+ await exec(/** @type {import('./types').StringRecord} */ (this.binaries).aapt, [
182
+ 'remove',
183
+ dstApk,
184
+ manifestName,
169
185
  ]);
170
186
  } catch {}
171
- await exec((/** @type {import('./types').StringRecord} */ (this.binaries)).aapt, [
172
- 'add', dstApk, manifestName
173
- ], {cwd: path.dirname(manifest)});
187
+ await exec(
188
+ /** @type {import('./types').StringRecord} */ (this.binaries).aapt,
189
+ ['add', dstApk, manifestName],
190
+ {cwd: path.dirname(manifest)},
191
+ );
174
192
  } catch (e) {
175
- log.debug('Cannot insert manifest using aapt. Defaulting to zip. ' +
176
- `Original error: ${e.stderr || e.message}`);
193
+ log.debug(
194
+ 'Cannot insert manifest using aapt. Defaulting to zip. ' +
195
+ `Original error: ${e.stderr || e.message}`,
196
+ );
177
197
  const tmpRoot = await tempDir.openDir();
178
198
  try {
179
199
  // Unfortunately NodeJS does not provide any reliable methods
@@ -201,14 +221,16 @@ export async function insertManifest (manifest, srcApk, dstApk) {
201
221
  * @param {string} appPath - The full path to .apk(s) package.
202
222
  * @return {Promise<boolean>} True if the manifest requires Internet access permission.
203
223
  */
204
- export async function hasInternetPermissionFromManifest (appPath) {
224
+ export async function hasInternetPermissionFromManifest(appPath) {
205
225
  log.debug(`Checking if '${appPath}' requires internet access permission in the manifest`);
206
226
  if (appPath.endsWith(APKS_EXTENSION)) {
207
227
  appPath = await this.extractBaseApk(appPath);
208
228
  }
209
229
 
210
230
  const {usesPermissions} = await readPackageManifest.bind(this)(appPath);
211
- return usesPermissions.some((/** @type {string} */ name) => name === 'android.permission.INTERNET');
231
+ return usesPermissions.some(
232
+ (/** @type {string} */ name) => name === 'android.permission.INTERNET',
233
+ );
212
234
  }
213
235
 
214
236
  // #region Private functions
@@ -219,7 +241,7 @@ export async function hasInternetPermissionFromManifest (appPath) {
219
241
  * @param {string} sdkRoot
220
242
  * @return {Promise<import('./types').PlatformInfo>} The resulting path to the newest installed platform.
221
243
  */
222
- export async function getAndroidPlatformAndPath (sdkRoot) {
244
+ export async function getAndroidPlatformAndPath(sdkRoot) {
223
245
  const propsPaths = await fs.glob('*/build.prop', {
224
246
  cwd: path.resolve(sdkRoot, 'platforms'),
225
247
  absolute: true,
@@ -241,8 +263,10 @@ export async function getAndroidPlatformAndPath (sdkRoot) {
241
263
  };
242
264
  }
243
265
  if (_.isEmpty(platformsMapping)) {
244
- log.warn(`Found zero platform folders at '${path.resolve(sdkRoot, 'platforms')}'. ` +
245
- `Do you have any Android SDKs installed?`);
266
+ log.warn(
267
+ `Found zero platform folders at '${path.resolve(sdkRoot, 'platforms')}'. ` +
268
+ `Do you have any Android SDKs installed?`,
269
+ );
246
270
  return {
247
271
  platform: null,
248
272
  platformPath: null,