@yume-chan/android-bin 0.0.21 → 0.0.23
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.json +36 -0
- package/CHANGELOG.md +19 -1
- package/README.md +40 -14
- package/esm/am.d.ts +17 -0
- package/esm/am.d.ts.map +1 -0
- package/esm/am.js +42 -0
- package/esm/am.js.map +1 -0
- package/esm/bu.js.map +1 -1
- package/esm/bug-report.js.map +1 -1
- package/esm/cmd.js +4 -4
- package/esm/cmd.js.map +1 -1
- package/esm/demo-mode.js.map +1 -1
- package/esm/dumpsys.d.ts +22 -0
- package/esm/dumpsys.d.ts.map +1 -1
- package/esm/dumpsys.js +34 -1
- package/esm/dumpsys.js.map +1 -1
- package/esm/index.d.ts +3 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -1
- package/esm/intent.d.ts +10 -0
- package/esm/intent.d.ts.map +1 -0
- package/esm/intent.js +51 -0
- package/esm/intent.js.map +1 -0
- package/esm/logcat.d.ts.map +1 -1
- package/esm/logcat.js +5 -5
- package/esm/logcat.js.map +1 -1
- package/esm/overlay-display.js.map +1 -1
- package/esm/pm.d.ts +54 -5
- package/esm/pm.d.ts.map +1 -1
- package/esm/pm.js +209 -46
- package/esm/pm.js.map +1 -1
- package/esm/settings.d.ts +2 -1
- package/esm/settings.d.ts.map +1 -1
- package/esm/settings.js.map +1 -1
- package/esm/string-format.d.ts.map +1 -1
- package/esm/string-format.js.map +1 -1
- package/esm/utils.d.ts +4 -0
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js +23 -0
- package/esm/utils.js.map +1 -0
- package/package.json +12 -12
- package/src/am.ts +69 -0
- package/src/cmd.ts +4 -4
- package/src/dumpsys.ts +39 -1
- package/src/index.ts +3 -0
- package/src/intent.ts +63 -0
- package/src/logcat.ts +7 -6
- package/src/pm.ts +309 -67
- package/src/settings.ts +2 -1
- package/src/utils.ts +29 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/pm.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
// cspell:ignore dont
|
|
2
2
|
// cspell:ignore instantapp
|
|
3
3
|
// cspell:ignore apks
|
|
4
|
+
// cspell:ignore versioncode
|
|
4
5
|
|
|
5
6
|
import type { Adb } from "@yume-chan/adb";
|
|
6
|
-
import {
|
|
7
|
-
AdbCommandBase,
|
|
8
|
-
AdbSubprocessNoneProtocol,
|
|
9
|
-
escapeArg,
|
|
10
|
-
} from "@yume-chan/adb";
|
|
7
|
+
import { AdbCommandBase, escapeArg } from "@yume-chan/adb";
|
|
11
8
|
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
12
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ConcatStringStream,
|
|
11
|
+
DecodeUtf8Stream,
|
|
12
|
+
SplitStringStream,
|
|
13
|
+
} from "@yume-chan/stream-extra";
|
|
13
14
|
|
|
14
15
|
import { Cmd } from "./cmd.js";
|
|
16
|
+
import type { IntentBuilder } from "./intent.js";
|
|
17
|
+
import type { SingleUserOrAll } from "./utils.js";
|
|
18
|
+
import { buildArguments } from "./utils.js";
|
|
15
19
|
|
|
16
20
|
export enum PackageManagerInstallLocation {
|
|
17
21
|
Auto,
|
|
@@ -96,7 +100,7 @@ export interface PackageManagerInstallOptions {
|
|
|
96
100
|
/**
|
|
97
101
|
* `--user`
|
|
98
102
|
*/
|
|
99
|
-
|
|
103
|
+
user: SingleUserOrAll;
|
|
100
104
|
/**
|
|
101
105
|
* `--install-location`
|
|
102
106
|
*/
|
|
@@ -163,7 +167,7 @@ export const PACKAGE_MANAGER_INSTALL_OPTIONS_MAP: Record<
|
|
|
163
167
|
instantApp: "--instant",
|
|
164
168
|
full: "--full",
|
|
165
169
|
preload: "--preload",
|
|
166
|
-
|
|
170
|
+
user: "--user",
|
|
167
171
|
installLocation: "--install-location",
|
|
168
172
|
installReason: "--install-reason",
|
|
169
173
|
forceUuid: "--force-uuid",
|
|
@@ -187,7 +191,7 @@ export interface PackageManagerListPackagesOptions {
|
|
|
187
191
|
listThirdParty: boolean;
|
|
188
192
|
showVersionCode: boolean;
|
|
189
193
|
listApexOnly: boolean;
|
|
190
|
-
user:
|
|
194
|
+
user: SingleUserOrAll;
|
|
191
195
|
uid: number;
|
|
192
196
|
filter: string;
|
|
193
197
|
}
|
|
@@ -218,6 +222,39 @@ export interface PackageManagerListPackagesResult {
|
|
|
218
222
|
uid?: number | undefined;
|
|
219
223
|
}
|
|
220
224
|
|
|
225
|
+
export interface PackageManagerUninstallOptions {
|
|
226
|
+
keepData: boolean;
|
|
227
|
+
user: SingleUserOrAll;
|
|
228
|
+
versionCode: number;
|
|
229
|
+
/**
|
|
230
|
+
* Only remove the specified splits, not the entire app
|
|
231
|
+
*
|
|
232
|
+
* On Android 10 and lower, only one split name can be specified.
|
|
233
|
+
*/
|
|
234
|
+
splitNames: string[];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const PACKAGE_MANAGER_UNINSTALL_OPTIONS_MAP: Record<
|
|
238
|
+
keyof PackageManagerUninstallOptions,
|
|
239
|
+
string
|
|
240
|
+
> = {
|
|
241
|
+
keepData: "-k",
|
|
242
|
+
user: "--user",
|
|
243
|
+
versionCode: "--versionCode",
|
|
244
|
+
splitNames: "",
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export interface PackageManagerResolveActivityOptions {
|
|
248
|
+
user?: SingleUserOrAll;
|
|
249
|
+
intent: IntentBuilder;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const PACKAGE_MANAGER_RESOLVE_ACTIVITY_OPTIONS_MAP: Partial<
|
|
253
|
+
Record<keyof PackageManagerResolveActivityOptions, string>
|
|
254
|
+
> = {
|
|
255
|
+
user: "--user",
|
|
256
|
+
};
|
|
257
|
+
|
|
221
258
|
export class PackageManager extends AdbCommandBase {
|
|
222
259
|
#cmd: Cmd;
|
|
223
260
|
|
|
@@ -226,48 +263,32 @@ export class PackageManager extends AdbCommandBase {
|
|
|
226
263
|
this.#cmd = new Cmd(adb);
|
|
227
264
|
}
|
|
228
265
|
|
|
229
|
-
#buildArguments<T>(
|
|
230
|
-
commands: string[],
|
|
231
|
-
options: Partial<T> | undefined,
|
|
232
|
-
map: Record<keyof T, string>,
|
|
233
|
-
): string[] {
|
|
234
|
-
const args = ["pm", ...commands];
|
|
235
|
-
if (options) {
|
|
236
|
-
for (const [key, value] of Object.entries(options)) {
|
|
237
|
-
if (value) {
|
|
238
|
-
const option = map[key as keyof T];
|
|
239
|
-
if (option) {
|
|
240
|
-
args.push(option);
|
|
241
|
-
switch (typeof value) {
|
|
242
|
-
case "number":
|
|
243
|
-
args.push(value.toString());
|
|
244
|
-
break;
|
|
245
|
-
case "string":
|
|
246
|
-
args.push(value);
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return args;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
266
|
#buildInstallArguments(
|
|
267
|
+
command: string,
|
|
257
268
|
options: Partial<PackageManagerInstallOptions> | undefined,
|
|
258
269
|
): string[] {
|
|
259
|
-
|
|
260
|
-
["
|
|
270
|
+
const args = buildArguments(
|
|
271
|
+
["pm", command],
|
|
261
272
|
options,
|
|
262
273
|
PACKAGE_MANAGER_INSTALL_OPTIONS_MAP,
|
|
263
274
|
);
|
|
275
|
+
if (!options?.skipExisting) {
|
|
276
|
+
// Compatibility with old versions of pm
|
|
277
|
+
args.push("-r");
|
|
278
|
+
}
|
|
279
|
+
return args;
|
|
264
280
|
}
|
|
265
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Install the apk file.
|
|
284
|
+
*
|
|
285
|
+
* @param apks Path to the apk file. It must exist on the device. On Android 10 and lower, only one apk can be specified.
|
|
286
|
+
*/
|
|
266
287
|
async install(
|
|
267
288
|
apks: string[],
|
|
268
289
|
options?: Partial<PackageManagerInstallOptions>,
|
|
269
290
|
): Promise<string> {
|
|
270
|
-
const args = this.#buildInstallArguments(options);
|
|
291
|
+
const args = this.#buildInstallArguments("install", options);
|
|
271
292
|
// WIP: old version of pm doesn't support multiple apks
|
|
272
293
|
args.push(...apks);
|
|
273
294
|
return await this.adb.subprocess.spawnAndWaitLegacy(args);
|
|
@@ -276,7 +297,7 @@ export class PackageManager extends AdbCommandBase {
|
|
|
276
297
|
async pushAndInstallStream(
|
|
277
298
|
stream: ReadableStream<Consumable<Uint8Array>>,
|
|
278
299
|
options?: Partial<PackageManagerInstallOptions>,
|
|
279
|
-
): Promise<
|
|
300
|
+
): Promise<void> {
|
|
280
301
|
const sync = await this.adb.sync();
|
|
281
302
|
|
|
282
303
|
const fileName = Math.random().toString().substring(2);
|
|
@@ -291,43 +312,58 @@ export class PackageManager extends AdbCommandBase {
|
|
|
291
312
|
await sync.dispose();
|
|
292
313
|
}
|
|
293
314
|
|
|
294
|
-
// Starting from Android 7, `pm` is a
|
|
315
|
+
// Starting from Android 7, `pm` is only a wrapper for `cmd package`,
|
|
295
316
|
// and `cmd package` launches faster than `pm`.
|
|
296
317
|
// But `cmd package` can't read `/data/local/tmp` folder due to SELinux policy,
|
|
297
318
|
// so installing a file must use `pm`.
|
|
298
|
-
const args = this.#buildInstallArguments(options);
|
|
319
|
+
const args = this.#buildInstallArguments("install", options);
|
|
299
320
|
args.push(filePath);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
const output = await this.adb.subprocess
|
|
324
|
+
.spawnAndWaitLegacy(args.map(escapeArg))
|
|
325
|
+
.then((output) => output.trim());
|
|
326
|
+
|
|
327
|
+
if (output !== "Success") {
|
|
328
|
+
throw new Error(output);
|
|
329
|
+
}
|
|
330
|
+
} finally {
|
|
331
|
+
await this.adb.rm(filePath);
|
|
332
|
+
}
|
|
310
333
|
}
|
|
311
334
|
|
|
312
335
|
async installStream(
|
|
313
336
|
size: number,
|
|
314
337
|
stream: ReadableStream<Consumable<Uint8Array>>,
|
|
315
338
|
options?: Partial<PackageManagerInstallOptions>,
|
|
316
|
-
): Promise<
|
|
339
|
+
): Promise<void> {
|
|
317
340
|
// Android 7 added both `cmd` command and streaming install support,
|
|
318
341
|
// we can't detect whether `pm` supports streaming install,
|
|
319
342
|
// so we detect `cmd` command support instead.
|
|
320
343
|
if (!this.#cmd.supportsCmd) {
|
|
321
|
-
|
|
344
|
+
await this.pushAndInstallStream(stream, options);
|
|
345
|
+
return;
|
|
322
346
|
}
|
|
323
347
|
|
|
324
|
-
const args = this.#buildInstallArguments(options);
|
|
348
|
+
const args = this.#buildInstallArguments("install", options);
|
|
325
349
|
// Remove `pm` from args, final command will starts with `cmd package install`
|
|
326
350
|
args.shift();
|
|
327
351
|
args.push("-S", size.toString());
|
|
328
352
|
const process = await this.#cmd.spawn(false, "package", ...args);
|
|
329
|
-
|
|
330
|
-
|
|
353
|
+
|
|
354
|
+
const output = process.stdout
|
|
355
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
356
|
+
.pipeThrough(new ConcatStringStream())
|
|
357
|
+
.then((output) => output.trim());
|
|
358
|
+
|
|
359
|
+
await Promise.all([
|
|
360
|
+
stream.pipeTo(process.stdin),
|
|
361
|
+
output.then((output) => {
|
|
362
|
+
if (output !== "Success") {
|
|
363
|
+
throw new Error(output);
|
|
364
|
+
}
|
|
365
|
+
}),
|
|
366
|
+
]);
|
|
331
367
|
}
|
|
332
368
|
|
|
333
369
|
static parsePackageListItem(
|
|
@@ -381,23 +417,229 @@ export class PackageManager extends AdbCommandBase {
|
|
|
381
417
|
};
|
|
382
418
|
}
|
|
383
419
|
|
|
384
|
-
async
|
|
420
|
+
async #cmdOrSubprocess(args: string[]) {
|
|
421
|
+
if (this.#cmd.supportsCmd) {
|
|
422
|
+
args.shift();
|
|
423
|
+
return await this.#cmd.spawn(false, "package", ...args);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return this.adb.subprocess.spawn(args);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async *listPackages(
|
|
385
430
|
options?: Partial<PackageManagerListPackagesOptions>,
|
|
386
|
-
):
|
|
387
|
-
const args =
|
|
388
|
-
["list", "packages"],
|
|
431
|
+
): AsyncGenerator<PackageManagerListPackagesResult, void, void> {
|
|
432
|
+
const args = buildArguments(
|
|
433
|
+
["pm", "list", "packages"],
|
|
389
434
|
options,
|
|
390
435
|
PACKAGE_MANAGER_LIST_PACKAGES_OPTIONS_MAP,
|
|
391
436
|
);
|
|
392
437
|
if (options?.filter) {
|
|
393
438
|
args.push(options.filter);
|
|
394
439
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
.
|
|
399
|
-
.
|
|
440
|
+
|
|
441
|
+
const process = await this.#cmdOrSubprocess(args);
|
|
442
|
+
const reader = process.stdout
|
|
443
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
444
|
+
.pipeThrough(new SplitStringStream("\n"))
|
|
445
|
+
.getReader();
|
|
446
|
+
while (true) {
|
|
447
|
+
const { done, value } = await reader.read();
|
|
448
|
+
if (done) {
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
yield PackageManager.parsePackageListItem(value);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
async uninstall(
|
|
456
|
+
packageName: string,
|
|
457
|
+
options?: Partial<PackageManagerUninstallOptions>,
|
|
458
|
+
): Promise<void> {
|
|
459
|
+
const args = buildArguments(
|
|
460
|
+
["pm", "uninstall"],
|
|
461
|
+
options,
|
|
462
|
+
PACKAGE_MANAGER_UNINSTALL_OPTIONS_MAP,
|
|
463
|
+
);
|
|
464
|
+
args.push(packageName);
|
|
465
|
+
if (options?.splitNames) {
|
|
466
|
+
args.push(...options.splitNames);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const process = await this.#cmdOrSubprocess(args);
|
|
470
|
+
const output = await process.stdout
|
|
471
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
472
|
+
.pipeThrough(new ConcatStringStream())
|
|
473
|
+
.then((output) => output.trim());
|
|
474
|
+
if (output !== "Success") {
|
|
475
|
+
throw new Error(output);
|
|
476
|
+
}
|
|
400
477
|
}
|
|
401
478
|
|
|
402
|
-
|
|
479
|
+
async resolveActivity(
|
|
480
|
+
options: PackageManagerResolveActivityOptions,
|
|
481
|
+
): Promise<string | undefined> {
|
|
482
|
+
let args = buildArguments(
|
|
483
|
+
["pm", "resolve-activity", "--components"],
|
|
484
|
+
options,
|
|
485
|
+
PACKAGE_MANAGER_RESOLVE_ACTIVITY_OPTIONS_MAP,
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
args = args.concat(options.intent.build());
|
|
489
|
+
|
|
490
|
+
const process = await this.#cmdOrSubprocess(args);
|
|
491
|
+
const output = await process.stdout
|
|
492
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
493
|
+
.pipeThrough(new ConcatStringStream())
|
|
494
|
+
.then((output) => output.trim());
|
|
495
|
+
|
|
496
|
+
if (output === "No activity found") {
|
|
497
|
+
return undefined;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return output;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Creates a new install session.
|
|
505
|
+
*
|
|
506
|
+
* Install sessions are used to install apps with multiple splits, but it can also be used to install a single apk.
|
|
507
|
+
*
|
|
508
|
+
* Install sessions was added in Android 5.0 (API level 21).
|
|
509
|
+
*
|
|
510
|
+
* @param options Options for the install session
|
|
511
|
+
* @returns ID of the new install session
|
|
512
|
+
*/
|
|
513
|
+
async sessionCreate(options?: Partial<PackageManagerInstallOptions>) {
|
|
514
|
+
const args = this.#buildInstallArguments("install-create", options);
|
|
515
|
+
|
|
516
|
+
const process = await this.#cmdOrSubprocess(args);
|
|
517
|
+
const output = await process.stdout
|
|
518
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
519
|
+
.pipeThrough(new ConcatStringStream())
|
|
520
|
+
.then((output) => output.trim());
|
|
521
|
+
|
|
522
|
+
const sessionIdString = output.match(/.*\[(\d+)\].*/);
|
|
523
|
+
if (!sessionIdString) {
|
|
524
|
+
throw new Error("Failed to create install session");
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return Number.parseInt(sessionIdString[1]!, 10);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async sessionAddSplit(sessionId: number, splitName: string, path: string) {
|
|
531
|
+
const args: string[] = [
|
|
532
|
+
"pm",
|
|
533
|
+
"install-write",
|
|
534
|
+
sessionId.toString(),
|
|
535
|
+
splitName,
|
|
536
|
+
path,
|
|
537
|
+
];
|
|
538
|
+
|
|
539
|
+
const output = await this.adb.subprocess
|
|
540
|
+
.spawnAndWaitLegacy(args)
|
|
541
|
+
.then((output) => output.trim());
|
|
542
|
+
if (!output.startsWith("Success")) {
|
|
543
|
+
throw new Error(output);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async sessionAddSplitStream(
|
|
548
|
+
sessionId: number,
|
|
549
|
+
splitName: string,
|
|
550
|
+
size: number,
|
|
551
|
+
stream: ReadableStream<Consumable<Uint8Array>>,
|
|
552
|
+
) {
|
|
553
|
+
const args: string[] = [
|
|
554
|
+
"pm",
|
|
555
|
+
"install-write",
|
|
556
|
+
"-S",
|
|
557
|
+
size.toString(),
|
|
558
|
+
sessionId.toString(),
|
|
559
|
+
splitName,
|
|
560
|
+
"-",
|
|
561
|
+
];
|
|
562
|
+
|
|
563
|
+
const process = await this.#cmdOrSubprocess(args);
|
|
564
|
+
const output = process.stdout
|
|
565
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
566
|
+
.pipeThrough(new ConcatStringStream())
|
|
567
|
+
.then((output) => output.trim());
|
|
568
|
+
|
|
569
|
+
await Promise.all([
|
|
570
|
+
stream.pipeTo(process.stdin),
|
|
571
|
+
output.then((output) => {
|
|
572
|
+
if (!output.startsWith("Success")) {
|
|
573
|
+
throw new Error(output);
|
|
574
|
+
}
|
|
575
|
+
}),
|
|
576
|
+
]);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async sessionCommit(sessionId: number) {
|
|
580
|
+
const args: string[] = ["pm", "install-commit", sessionId.toString()];
|
|
581
|
+
const output = await this.adb.subprocess
|
|
582
|
+
.spawnAndWaitLegacy(args)
|
|
583
|
+
.then((output) => output.trim());
|
|
584
|
+
if (output !== "Success") {
|
|
585
|
+
throw new Error(output);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
async sessionAbandon(sessionId: number) {
|
|
590
|
+
const args: string[] = ["pm", "install-abandon", sessionId.toString()];
|
|
591
|
+
const output = await this.adb.subprocess
|
|
592
|
+
.spawnAndWaitLegacy(args)
|
|
593
|
+
.then((output) => output.trim());
|
|
594
|
+
if (output !== "Success") {
|
|
595
|
+
throw new Error(output);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export class PackageManagerInstallSession {
|
|
601
|
+
static async create(
|
|
602
|
+
packageManager: PackageManager,
|
|
603
|
+
options?: Partial<PackageManagerInstallOptions>,
|
|
604
|
+
) {
|
|
605
|
+
const id = await packageManager.sessionCreate(options);
|
|
606
|
+
return new PackageManagerInstallSession(packageManager, id);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
#packageManager: PackageManager;
|
|
610
|
+
|
|
611
|
+
#id: number;
|
|
612
|
+
get id() {
|
|
613
|
+
return this.#id;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
constructor(packageManager: PackageManager, id: number) {
|
|
617
|
+
this.#packageManager = packageManager;
|
|
618
|
+
this.#id = id;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
addSplit(splitName: string, path: string) {
|
|
622
|
+
return this.#packageManager.sessionAddSplit(this.#id, splitName, path);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
addSplitStream(
|
|
626
|
+
splitName: string,
|
|
627
|
+
size: number,
|
|
628
|
+
stream: ReadableStream<Consumable<Uint8Array>>,
|
|
629
|
+
) {
|
|
630
|
+
return this.#packageManager.sessionAddSplitStream(
|
|
631
|
+
this.#id,
|
|
632
|
+
splitName,
|
|
633
|
+
size,
|
|
634
|
+
stream,
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
commit() {
|
|
639
|
+
return this.#packageManager.sessionCommit(this.#id);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
abandon() {
|
|
643
|
+
return this.#packageManager.sessionAbandon(this.#id);
|
|
644
|
+
}
|
|
403
645
|
}
|
package/src/settings.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Adb, AdbSubprocessWaitResult } from "@yume-chan/adb";
|
|
|
2
2
|
import { AdbCommandBase } from "@yume-chan/adb";
|
|
3
3
|
|
|
4
4
|
import { Cmd } from "./cmd.js";
|
|
5
|
+
import type { SingleUser } from "./utils.js";
|
|
5
6
|
|
|
6
7
|
export type SettingsNamespace = "system" | "secure" | "global";
|
|
7
8
|
|
|
@@ -12,7 +13,7 @@ export enum SettingsResetMode {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface SettingsOptions {
|
|
15
|
-
user?:
|
|
16
|
+
user?: SingleUser;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export interface SettingsPutOptions extends SettingsOptions {
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function buildArguments<T>(
|
|
2
|
+
commands: string[],
|
|
3
|
+
options: Partial<T> | undefined,
|
|
4
|
+
map: Partial<Record<keyof T, string>>,
|
|
5
|
+
): string[] {
|
|
6
|
+
const args = commands;
|
|
7
|
+
if (options) {
|
|
8
|
+
for (const [key, value] of Object.entries(options)) {
|
|
9
|
+
if (value) {
|
|
10
|
+
const option = map[key as keyof T];
|
|
11
|
+
if (option) {
|
|
12
|
+
args.push(option);
|
|
13
|
+
switch (typeof value) {
|
|
14
|
+
case "number":
|
|
15
|
+
args.push(value.toString());
|
|
16
|
+
break;
|
|
17
|
+
case "string":
|
|
18
|
+
args.push(value);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type SingleUser = number | "current";
|
|
29
|
+
export type SingleUserOrAll = SingleUser | "all";
|