@react-native-harness/platform-android 1.2.0-rc.1 → 1.3.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/dist/__tests__/adb-id.test.d.ts +2 -0
- package/dist/__tests__/adb-id.test.d.ts.map +1 -0
- package/dist/__tests__/adb-id.test.js +41 -0
- package/dist/__tests__/adb.test.js +56 -13
- package/dist/__tests__/app-monitor.test.js +196 -141
- package/dist/__tests__/instance.test.js +3 -72
- package/dist/adb.d.ts +2 -0
- package/dist/adb.d.ts.map +1 -1
- package/dist/adb.js +5 -1
- package/dist/app-monitor.d.ts.map +1 -1
- package/dist/app-monitor.js +2 -5
- package/dist/device-state.d.ts +6 -0
- package/dist/device-state.d.ts.map +1 -0
- package/dist/device-state.js +142 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/eslint.config.mjs +1 -0
- package/package.json +5 -4
- package/src/__tests__/adb-id.test.ts +51 -0
- package/src/__tests__/instance.test.ts +9 -105
- package/src/adb.ts +15 -1
- package/src/app-monitor.ts +3 -8
- package/test/setup.ts +68 -0
- package/vite.config.ts +19 -0
- package/src/__tests__/adb.test.ts +0 -700
- package/src/__tests__/app-monitor.test.ts +0 -273
- package/src/__tests__/environment.test.ts +0 -212
package/dist/adb.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AndroidAppLaunchOptions } from '@react-native-harness/platforms';
|
|
2
|
+
import { type Subprocess } from '@react-native-harness/tools';
|
|
2
3
|
import type { ChildProcessByStdio } from 'node:child_process';
|
|
3
4
|
import type { Readable } from 'node:stream';
|
|
4
5
|
import { type EmulatorBootMode } from './emulator-startup.js';
|
|
@@ -42,6 +43,7 @@ export declare const isAppRunning: (adbId: string, bundleId: string) => Promise<
|
|
|
42
43
|
export declare const getAppUid: (adbId: string, bundleId: string) => Promise<number>;
|
|
43
44
|
export declare const setHideErrorDialogs: (adbId: string, hide: boolean) => Promise<void>;
|
|
44
45
|
export declare const getLogcatTimestamp: (adbId: string) => Promise<string>;
|
|
46
|
+
export declare const startLogcat: (adbId: string, args: readonly string[]) => Subprocess;
|
|
45
47
|
export declare const getAvds: () => Promise<string[]>;
|
|
46
48
|
export type AdbDevice = {
|
|
47
49
|
id: string;
|
package/dist/adb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../src/adb.ts"],"names":[],"mappings":"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"}
|
package/dist/adb.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger, spawn, SubprocessError } from '@react-native-harness/tools';
|
|
1
|
+
import { logger, spawn, SubprocessError, } from '@react-native-harness/tools';
|
|
2
2
|
import { spawn as nodeSpawn } from 'node:child_process';
|
|
3
3
|
import { access, rm } from 'node:fs/promises';
|
|
4
4
|
import { getAvdConfigPath, getAvdDirectory, readAvdConfig, } from './avd-config.js';
|
|
@@ -490,6 +490,10 @@ export const getLogcatTimestamp = async (adbId) => {
|
|
|
490
490
|
]);
|
|
491
491
|
return stdout.trim().replace(/^'+|'+$/g, '');
|
|
492
492
|
};
|
|
493
|
+
export const startLogcat = (adbId, args) => spawn(getAdbBinaryPath(), ['-s', adbId, ...args], {
|
|
494
|
+
stdout: 'pipe',
|
|
495
|
+
stderr: 'pipe',
|
|
496
|
+
});
|
|
493
497
|
export const getAvds = async () => {
|
|
494
498
|
try {
|
|
495
499
|
const emulatorBinaryPath = await ensureEmulatorInstalled();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-monitor.d.ts","sourceRoot":"","sources":["../src/app-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EAErB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"app-monitor.d.ts","sourceRoot":"","sources":["../src/app-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EAErB,MAAM,iCAAiC,CAAC;AA+SzC,QAAA,MAAM,qBAAqB,GACzB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,eAAe,GAAG,IAwEpB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,mDAKrC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C,KAAG,iBA4KH,CAAC;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG;IAC3C,eAAe,EAAE,CACf,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACtC,CAAC"}
|
package/dist/app-monitor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { escapeRegExp, getEmitter, logger,
|
|
1
|
+
import { escapeRegExp, getEmitter, logger, SubprocessError, } from '@react-native-harness/tools';
|
|
2
2
|
import * as adb from './adb.js';
|
|
3
3
|
import { androidCrashParser } from './crash-parser.js';
|
|
4
4
|
const androidAppMonitorLogger = logger.child('android-app-monitor');
|
|
@@ -281,10 +281,7 @@ export const createAndroidAppMonitor = ({ adbId, bundleId, appUid, crashArtifact
|
|
|
281
281
|
};
|
|
282
282
|
const startLogcat = async () => {
|
|
283
283
|
const logcatTimestamp = await adb.getLogcatTimestamp(adbId);
|
|
284
|
-
logcatProcess =
|
|
285
|
-
stdout: 'pipe',
|
|
286
|
-
stderr: 'pipe',
|
|
287
|
-
});
|
|
284
|
+
logcatProcess = adb.startLogcat(adbId, getLogcatArgs(appUid, logcatTimestamp));
|
|
288
285
|
const currentProcess = logcatProcess;
|
|
289
286
|
if (!currentProcess) {
|
|
290
287
|
return;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-state.d.ts","sourceRoot":"","sources":["../src/device-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,qBAAqB,EAEtB,MAAM,iCAAiC,CAAC;AA0HzC,eAAO,MAAM,wBAAwB,GAAI,SAAS;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,KAAG,qBAqFH,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as adb from './adb.js';
|
|
2
|
+
const ANDROID_PERMISSION_ALIASES = {
|
|
3
|
+
bluetooth: [
|
|
4
|
+
'android.permission.BLUETOOTH_CONNECT',
|
|
5
|
+
'android.permission.BLUETOOTH_SCAN',
|
|
6
|
+
],
|
|
7
|
+
calendar: [
|
|
8
|
+
'android.permission.READ_CALENDAR',
|
|
9
|
+
'android.permission.WRITE_CALENDAR',
|
|
10
|
+
],
|
|
11
|
+
camera: ['android.permission.CAMERA'],
|
|
12
|
+
contacts: [
|
|
13
|
+
'android.permission.READ_CONTACTS',
|
|
14
|
+
'android.permission.WRITE_CONTACTS',
|
|
15
|
+
],
|
|
16
|
+
location: [
|
|
17
|
+
'android.permission.ACCESS_FINE_LOCATION',
|
|
18
|
+
'android.permission.ACCESS_COARSE_LOCATION',
|
|
19
|
+
],
|
|
20
|
+
mediaLibrary: [
|
|
21
|
+
'android.permission.READ_MEDIA_IMAGES',
|
|
22
|
+
'android.permission.READ_MEDIA_VIDEO',
|
|
23
|
+
'android.permission.READ_MEDIA_AUDIO',
|
|
24
|
+
],
|
|
25
|
+
microphone: ['android.permission.RECORD_AUDIO'],
|
|
26
|
+
notifications: ['android.permission.POST_NOTIFICATIONS'],
|
|
27
|
+
phone: [
|
|
28
|
+
'android.permission.CALL_PHONE',
|
|
29
|
+
'android.permission.ANSWER_PHONE_CALLS',
|
|
30
|
+
],
|
|
31
|
+
sms: [
|
|
32
|
+
'android.permission.READ_SMS',
|
|
33
|
+
'android.permission.RECEIVE_SMS',
|
|
34
|
+
'android.permission.SEND_SMS',
|
|
35
|
+
],
|
|
36
|
+
storage: [
|
|
37
|
+
'android.permission.READ_EXTERNAL_STORAGE',
|
|
38
|
+
'android.permission.WRITE_EXTERNAL_STORAGE',
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
const normalizePermissionName = (name) => {
|
|
42
|
+
return name.trim();
|
|
43
|
+
};
|
|
44
|
+
const resolvePermissions = async (options) => {
|
|
45
|
+
if (options.command.kind === 'permission-all') {
|
|
46
|
+
return adb.getDeclaredDangerousPermissions(options.adbId, options.bundleId);
|
|
47
|
+
}
|
|
48
|
+
const normalized = normalizePermissionName(options.command.permission);
|
|
49
|
+
const aliases = ANDROID_PERMISSION_ALIASES[normalized];
|
|
50
|
+
if (aliases) {
|
|
51
|
+
return aliases;
|
|
52
|
+
}
|
|
53
|
+
return [normalized];
|
|
54
|
+
};
|
|
55
|
+
const snapshotPermissions = async (options) => {
|
|
56
|
+
const granted = await Promise.all(options.permissions.map(async (permission) => {
|
|
57
|
+
const isGranted = await adb.isPermissionGranted(options.adbId, options.bundleId, permission);
|
|
58
|
+
return isGranted ? permission : null;
|
|
59
|
+
}));
|
|
60
|
+
return granted.filter((permission) => permission != null);
|
|
61
|
+
};
|
|
62
|
+
const applyPermissionSnapshot = async (options) => {
|
|
63
|
+
const grantedSet = new Set(options.snapshot.previousGranted);
|
|
64
|
+
const toGrant = options.snapshot.permissions.filter((permission) => grantedSet.has(permission));
|
|
65
|
+
const toRevoke = options.snapshot.permissions.filter((permission) => !grantedSet.has(permission));
|
|
66
|
+
if (toGrant.length > 0) {
|
|
67
|
+
await adb.setPermissions(options.adbId, options.bundleId, toGrant, 'grant', {
|
|
68
|
+
bestEffort: true,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (toRevoke.length > 0) {
|
|
72
|
+
await adb.setPermissions(options.adbId, options.bundleId, toRevoke, 'reset', {
|
|
73
|
+
bestEffort: true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
export const createAndroidDeviceState = (options) => {
|
|
78
|
+
const outstandingMutations = new Map();
|
|
79
|
+
let mutationCounter = 0;
|
|
80
|
+
const rememberMutation = (snapshot) => {
|
|
81
|
+
const id = `android-permissions-${++mutationCounter}`;
|
|
82
|
+
const mutation = {
|
|
83
|
+
id,
|
|
84
|
+
snapshot,
|
|
85
|
+
revert: async () => {
|
|
86
|
+
await controller.permissions.revert(id);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
outstandingMutations.set(id, mutation);
|
|
90
|
+
return mutation;
|
|
91
|
+
};
|
|
92
|
+
const controller = {
|
|
93
|
+
permissions: {
|
|
94
|
+
apply: async (command) => {
|
|
95
|
+
const permissions = await resolvePermissions({
|
|
96
|
+
adbId: options.adbId,
|
|
97
|
+
bundleId: options.bundleId,
|
|
98
|
+
command,
|
|
99
|
+
});
|
|
100
|
+
if (permissions.length === 0) {
|
|
101
|
+
return { mutation: null };
|
|
102
|
+
}
|
|
103
|
+
const previousGranted = await snapshotPermissions({
|
|
104
|
+
adbId: options.adbId,
|
|
105
|
+
bundleId: options.bundleId,
|
|
106
|
+
permissions,
|
|
107
|
+
});
|
|
108
|
+
await adb.setPermissions(options.adbId, options.bundleId, permissions, command.decision, { bestEffort: command.kind === 'permission-all' });
|
|
109
|
+
const mutation = rememberMutation({
|
|
110
|
+
kind: 'permission-set',
|
|
111
|
+
permissions,
|
|
112
|
+
previousGranted,
|
|
113
|
+
});
|
|
114
|
+
return { mutation };
|
|
115
|
+
},
|
|
116
|
+
revert: async (mutationId) => {
|
|
117
|
+
const mutation = outstandingMutations.get(mutationId);
|
|
118
|
+
if (!mutation) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
outstandingMutations.delete(mutationId);
|
|
122
|
+
await applyPermissionSnapshot({
|
|
123
|
+
adbId: options.adbId,
|
|
124
|
+
bundleId: options.bundleId,
|
|
125
|
+
snapshot: mutation.snapshot,
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
resetOutstanding: async () => {
|
|
129
|
+
const mutations = [...outstandingMutations.values()].reverse();
|
|
130
|
+
outstandingMutations.clear();
|
|
131
|
+
for (const mutation of mutations) {
|
|
132
|
+
await applyPermissionSnapshot({
|
|
133
|
+
adbId: options.adbId,
|
|
134
|
+
bundleId: options.bundleId,
|
|
135
|
+
snapshot: mutation.snapshot,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
return controller;
|
|
142
|
+
};
|