@react-native-harness/platform-apple 1.0.0-alpha.18
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/LICENSE +20 -0
- package/README.md +99 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/factory.d.ts +6 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +21 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/instance.d.ts +5 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +65 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +7 -0
- package/dist/xcrun/devicectl.d.ts +32 -0
- package/dist/xcrun/devicectl.d.ts.map +1 -0
- package/dist/xcrun/devicectl.js +85 -0
- package/dist/xcrun/simctl.d.ts +23 -0
- package/dist/xcrun/simctl.d.ts.map +1 -0
- package/dist/xcrun/simctl.js +62 -0
- package/eslint.config.mjs +19 -0
- package/package.json +25 -0
- package/src/config.ts +56 -0
- package/src/factory.ts +40 -0
- package/src/index.ts +6 -0
- package/src/instance.ts +105 -0
- package/src/utils.ts +9 -0
- package/src/xcrun/devicectl.ts +153 -0
- package/src/xcrun/simctl.ts +122 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Callstack
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[![mit licence][license-badge]][license]
|
|
4
|
+
[![npm downloads][npm-downloads-badge]][npm-downloads]
|
|
5
|
+
[![Chat][chat-badge]][chat]
|
|
6
|
+
[![PRs Welcome][prs-welcome-badge]][prs-welcome]
|
|
7
|
+
|
|
8
|
+
Apple platform for React Native Harness - enables testing on iOS simulators and physical devices.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @react-native-harness/platform-apple
|
|
14
|
+
# or
|
|
15
|
+
pnpm add @react-native-harness/platform-apple
|
|
16
|
+
# or
|
|
17
|
+
yarn add @react-native-harness/platform-apple
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Import the Apple platform functions in your `rn-harness.config.mjs`:
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import {
|
|
26
|
+
applePlatform,
|
|
27
|
+
applePhysicalDevice,
|
|
28
|
+
appleSimulator,
|
|
29
|
+
} from '@react-native-harness/platform-apple';
|
|
30
|
+
|
|
31
|
+
const config = {
|
|
32
|
+
runners: [
|
|
33
|
+
applePlatform({
|
|
34
|
+
name: 'ios',
|
|
35
|
+
device: appleSimulator('iPhone 16 Pro Max', '18.0'),
|
|
36
|
+
bundleId: 'org.reactjs.native.example.YourApp',
|
|
37
|
+
}),
|
|
38
|
+
applePlatform({
|
|
39
|
+
name: 'iphone-device',
|
|
40
|
+
device: applePhysicalDevice('iPhone (Your Name)'),
|
|
41
|
+
bundleId: 'com.your.app',
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
// ... other config
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default config;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `applePlatform(config)`
|
|
53
|
+
|
|
54
|
+
Creates an Apple platform runner configuration.
|
|
55
|
+
|
|
56
|
+
**Parameters:**
|
|
57
|
+
|
|
58
|
+
- `config.name` - Unique name for the runner
|
|
59
|
+
- `config.device` - Apple device configuration (simulator or physical)
|
|
60
|
+
- `config.bundleId` - iOS application bundle ID
|
|
61
|
+
|
|
62
|
+
### `appleSimulator(deviceName, osVersion)`
|
|
63
|
+
|
|
64
|
+
Creates an iOS simulator device configuration.
|
|
65
|
+
|
|
66
|
+
**Parameters:**
|
|
67
|
+
|
|
68
|
+
- `deviceName` - Name of the iOS simulator (e.g., 'iPhone 16 Pro Max')
|
|
69
|
+
- `osVersion` - iOS version (e.g., '18.0')
|
|
70
|
+
|
|
71
|
+
### `applePhysicalDevice(deviceName)`
|
|
72
|
+
|
|
73
|
+
Creates a physical Apple device configuration.
|
|
74
|
+
|
|
75
|
+
**Parameters:**
|
|
76
|
+
|
|
77
|
+
- `deviceName` - Name of the physical device (e.g., 'iPhone (Your Name)')
|
|
78
|
+
|
|
79
|
+
## Requirements
|
|
80
|
+
|
|
81
|
+
- macOS with Xcode installed
|
|
82
|
+
- iOS Simulator or physical device connected
|
|
83
|
+
- React Native project configured for iOS
|
|
84
|
+
|
|
85
|
+
## Made with ❤️ at Callstack
|
|
86
|
+
|
|
87
|
+
`react-native-harness` is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack][callstack-readme-with-love] is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi!
|
|
88
|
+
|
|
89
|
+
Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥
|
|
90
|
+
|
|
91
|
+
[callstack-readme-with-love]: https://callstack.com/?utm_source=github.com&utm_medium=referral&utm_campaign=react-native-harness&utm_term=readme-with-love
|
|
92
|
+
[license-badge]: https://img.shields.io/npm/l/react-native-harness?style=for-the-badge
|
|
93
|
+
[license]: https://github.com/callstackincubator/react-native-harness/blob/main/LICENSE
|
|
94
|
+
[npm-downloads-badge]: https://img.shields.io/npm/dm/react-native-harness?style=for-the-badge
|
|
95
|
+
[npm-downloads]: https://www.npmjs.com/package/react-native-harness
|
|
96
|
+
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
|
|
97
|
+
[prs-welcome]: ./CONTRIBUTING.md
|
|
98
|
+
[chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=for-the-badge
|
|
99
|
+
[chat]: https://discord.gg/xgGt7KAjxv
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const AppleSimulatorSchema: z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"simulator">;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
systemVersion: z.ZodString;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
type: "simulator";
|
|
8
|
+
name: string;
|
|
9
|
+
systemVersion: string;
|
|
10
|
+
}, {
|
|
11
|
+
type: "simulator";
|
|
12
|
+
name: string;
|
|
13
|
+
systemVersion: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const ApplePhysicalDeviceSchema: z.ZodObject<{
|
|
16
|
+
type: z.ZodLiteral<"physical">;
|
|
17
|
+
name: z.ZodString;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
type: "physical";
|
|
20
|
+
name: string;
|
|
21
|
+
}, {
|
|
22
|
+
type: "physical";
|
|
23
|
+
name: string;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const AppleDeviceSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
26
|
+
type: z.ZodLiteral<"simulator">;
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
systemVersion: z.ZodString;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
type: "simulator";
|
|
31
|
+
name: string;
|
|
32
|
+
systemVersion: string;
|
|
33
|
+
}, {
|
|
34
|
+
type: "simulator";
|
|
35
|
+
name: string;
|
|
36
|
+
systemVersion: string;
|
|
37
|
+
}>, z.ZodObject<{
|
|
38
|
+
type: z.ZodLiteral<"physical">;
|
|
39
|
+
name: z.ZodString;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
type: "physical";
|
|
42
|
+
name: string;
|
|
43
|
+
}, {
|
|
44
|
+
type: "physical";
|
|
45
|
+
name: string;
|
|
46
|
+
}>]>;
|
|
47
|
+
export declare const ApplePlatformConfigSchema: z.ZodObject<{
|
|
48
|
+
name: z.ZodString;
|
|
49
|
+
device: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
50
|
+
type: z.ZodLiteral<"simulator">;
|
|
51
|
+
name: z.ZodString;
|
|
52
|
+
systemVersion: z.ZodString;
|
|
53
|
+
}, "strip", z.ZodTypeAny, {
|
|
54
|
+
type: "simulator";
|
|
55
|
+
name: string;
|
|
56
|
+
systemVersion: string;
|
|
57
|
+
}, {
|
|
58
|
+
type: "simulator";
|
|
59
|
+
name: string;
|
|
60
|
+
systemVersion: string;
|
|
61
|
+
}>, z.ZodObject<{
|
|
62
|
+
type: z.ZodLiteral<"physical">;
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
}, "strip", z.ZodTypeAny, {
|
|
65
|
+
type: "physical";
|
|
66
|
+
name: string;
|
|
67
|
+
}, {
|
|
68
|
+
type: "physical";
|
|
69
|
+
name: string;
|
|
70
|
+
}>]>;
|
|
71
|
+
bundleId: z.ZodString;
|
|
72
|
+
}, "strip", z.ZodTypeAny, {
|
|
73
|
+
name: string;
|
|
74
|
+
device: {
|
|
75
|
+
type: "simulator";
|
|
76
|
+
name: string;
|
|
77
|
+
systemVersion: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: "physical";
|
|
80
|
+
name: string;
|
|
81
|
+
};
|
|
82
|
+
bundleId: string;
|
|
83
|
+
}, {
|
|
84
|
+
name: string;
|
|
85
|
+
device: {
|
|
86
|
+
type: "simulator";
|
|
87
|
+
name: string;
|
|
88
|
+
systemVersion: string;
|
|
89
|
+
} | {
|
|
90
|
+
type: "physical";
|
|
91
|
+
name: string;
|
|
92
|
+
};
|
|
93
|
+
bundleId: string;
|
|
94
|
+
}>;
|
|
95
|
+
export type AppleSimulator = z.infer<typeof AppleSimulatorSchema>;
|
|
96
|
+
export type ApplePhysicalDevice = z.infer<typeof ApplePhysicalDeviceSchema>;
|
|
97
|
+
export type AppleDevice = z.infer<typeof AppleDeviceSchema>;
|
|
98
|
+
export type ApplePlatformConfig = z.infer<typeof ApplePlatformConfigSchema>;
|
|
99
|
+
export declare const isAppleDeviceSimulator: (device: AppleDevice) => device is AppleSimulator;
|
|
100
|
+
export declare const isAppleDevicePhysical: (device: AppleDevice) => device is ApplePhysicalDevice;
|
|
101
|
+
export declare function assertAppleDeviceSimulator(device: AppleDevice): asserts device is AppleSimulator;
|
|
102
|
+
export declare function assertAppleDevicePhysical(device: AppleDevice): asserts device is ApplePhysicalDevice;
|
|
103
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAI/B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;EAGpC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;IAG5B,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIpC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,sBAAsB,GACjC,QAAQ,WAAW,KAClB,MAAM,IAAI,cAEZ,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,QAAQ,WAAW,KAClB,MAAM,IAAI,mBAEZ,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,IAAI,cAAc,CAIlC;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAIvC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const AppleSimulatorSchema = z.object({
|
|
3
|
+
type: z.literal('simulator'),
|
|
4
|
+
name: z.string().min(1, 'Name is required'),
|
|
5
|
+
systemVersion: z.string().min(1, 'System version is required'),
|
|
6
|
+
});
|
|
7
|
+
export const ApplePhysicalDeviceSchema = z.object({
|
|
8
|
+
type: z.literal('physical'),
|
|
9
|
+
name: z.string().min(1, 'Name is required'),
|
|
10
|
+
});
|
|
11
|
+
export const AppleDeviceSchema = z.discriminatedUnion('type', [
|
|
12
|
+
AppleSimulatorSchema,
|
|
13
|
+
ApplePhysicalDeviceSchema,
|
|
14
|
+
]);
|
|
15
|
+
export const ApplePlatformConfigSchema = z.object({
|
|
16
|
+
name: z.string().min(1, 'Name is required'),
|
|
17
|
+
device: AppleDeviceSchema,
|
|
18
|
+
bundleId: z.string().min(1, 'Bundle ID is required'),
|
|
19
|
+
});
|
|
20
|
+
export const isAppleDeviceSimulator = (device) => {
|
|
21
|
+
return device.type === 'simulator';
|
|
22
|
+
};
|
|
23
|
+
export const isAppleDevicePhysical = (device) => {
|
|
24
|
+
return device.type === 'physical';
|
|
25
|
+
};
|
|
26
|
+
export function assertAppleDeviceSimulator(device) {
|
|
27
|
+
if (!isAppleDeviceSimulator(device)) {
|
|
28
|
+
throw new Error('Device is not a simulator');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function assertAppleDevicePhysical(device) {
|
|
32
|
+
if (!isAppleDevicePhysical(device)) {
|
|
33
|
+
throw new Error('Device is not a physical device');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { HarnessPlatform } from '@react-native-harness/platforms';
|
|
2
|
+
import type { AppleSimulator, ApplePhysicalDevice, ApplePlatformConfig } from './config.js';
|
|
3
|
+
export declare const appleSimulator: (name: string, systemVersion: string) => AppleSimulator;
|
|
4
|
+
export declare const applePhysicalDevice: (name: string) => ApplePhysicalDevice;
|
|
5
|
+
export declare const applePlatform: (config: ApplePlatformConfig) => HarnessPlatform;
|
|
6
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAOrB,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,eAAe,MAAM,KACpB,cAID,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,KAAG,mBAGjD,CAAC;AAEH,eAAO,MAAM,aAAa,GACxB,QAAQ,mBAAmB,KAC1B,eAWD,CAAC"}
|
package/dist/factory.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ApplePlatformConfigSchema, isAppleDeviceSimulator } from './config.js';
|
|
2
|
+
import { getApplePhysicalDevicePlatformInstance, getAppleSimulatorPlatformInstance, } from './instance.js';
|
|
3
|
+
export const appleSimulator = (name, systemVersion) => ({
|
|
4
|
+
type: 'simulator',
|
|
5
|
+
name,
|
|
6
|
+
systemVersion,
|
|
7
|
+
});
|
|
8
|
+
export const applePhysicalDevice = (name) => ({
|
|
9
|
+
type: 'physical',
|
|
10
|
+
name,
|
|
11
|
+
});
|
|
12
|
+
export const applePlatform = (config) => ({
|
|
13
|
+
name: config.name,
|
|
14
|
+
getInstance: async () => {
|
|
15
|
+
const parsedConfig = ApplePlatformConfigSchema.parse(config);
|
|
16
|
+
if (isAppleDeviceSimulator(parsedConfig.device)) {
|
|
17
|
+
return getAppleSimulatorPlatformInstance(parsedConfig);
|
|
18
|
+
}
|
|
19
|
+
return getApplePhysicalDevicePlatformInstance(parsedConfig);
|
|
20
|
+
},
|
|
21
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { applePlatform, appleSimulator, applePhysicalDevice, } from './factory.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { HarnessPlatformInstance } from '@react-native-harness/platforms';
|
|
2
|
+
import { ApplePlatformConfig } from './config.js';
|
|
3
|
+
export declare const getAppleSimulatorPlatformInstance: (config: ApplePlatformConfig) => Promise<HarnessPlatformInstance>;
|
|
4
|
+
export declare const getApplePhysicalDevicePlatformInstance: (config: ApplePlatformConfig) => Promise<HarnessPlatformInstance>;
|
|
5
|
+
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,mBAAmB,EAGpB,MAAM,aAAa,CAAC;AAKrB,eAAO,MAAM,iCAAiC,GAC5C,QAAQ,mBAAmB,KAC1B,OAAO,CAAC,uBAAuB,CAmDjC,CAAC;AAEF,eAAO,MAAM,sCAAsC,GACjD,QAAQ,mBAAmB,KAC1B,OAAO,CAAC,uBAAuB,CAiCjC,CAAC"}
|
package/dist/instance.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AppNotInstalledError, DeviceNotFoundError, } from '@react-native-harness/platforms';
|
|
2
|
+
import { assertAppleDevicePhysical, assertAppleDeviceSimulator, } from './config.js';
|
|
3
|
+
import * as simctl from './xcrun/simctl.js';
|
|
4
|
+
import * as devicectl from './xcrun/devicectl.js';
|
|
5
|
+
import { getDeviceName } from './utils.js';
|
|
6
|
+
export const getAppleSimulatorPlatformInstance = async (config) => {
|
|
7
|
+
assertAppleDeviceSimulator(config.device);
|
|
8
|
+
const udid = await simctl.getSimulatorId(config.device.name, config.device.systemVersion);
|
|
9
|
+
if (!udid) {
|
|
10
|
+
throw new DeviceNotFoundError(getDeviceName(config.device));
|
|
11
|
+
}
|
|
12
|
+
const isInstalled = await simctl.isAppInstalled(udid, config.bundleId);
|
|
13
|
+
if (!isInstalled) {
|
|
14
|
+
throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
|
|
15
|
+
}
|
|
16
|
+
const simulatorStatus = await simctl.getSimulatorStatus(udid);
|
|
17
|
+
if (simulatorStatus !== 'Booted') {
|
|
18
|
+
throw new Error('Simulator is not booted');
|
|
19
|
+
}
|
|
20
|
+
const isAvailable = await simctl.isAppInstalled(udid, config.bundleId);
|
|
21
|
+
if (!isAvailable) {
|
|
22
|
+
throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
startApp: async () => {
|
|
26
|
+
await simctl.startApp(udid, config.bundleId);
|
|
27
|
+
},
|
|
28
|
+
restartApp: async () => {
|
|
29
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
30
|
+
await simctl.startApp(udid, config.bundleId);
|
|
31
|
+
},
|
|
32
|
+
stopApp: async () => {
|
|
33
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
34
|
+
},
|
|
35
|
+
dispose: async () => {
|
|
36
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export const getApplePhysicalDevicePlatformInstance = async (config) => {
|
|
41
|
+
assertAppleDevicePhysical(config.device);
|
|
42
|
+
const deviceId = await devicectl.getDeviceId(config.device.name);
|
|
43
|
+
if (!deviceId) {
|
|
44
|
+
throw new DeviceNotFoundError(getDeviceName(config.device));
|
|
45
|
+
}
|
|
46
|
+
const isAvailable = await devicectl.isAppInstalled(deviceId, config.bundleId);
|
|
47
|
+
if (!isAvailable) {
|
|
48
|
+
throw new AppNotInstalledError(config.bundleId, getDeviceName(config.device));
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
startApp: async () => {
|
|
52
|
+
await devicectl.startApp(deviceId, config.bundleId);
|
|
53
|
+
},
|
|
54
|
+
restartApp: async () => {
|
|
55
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
56
|
+
await devicectl.startApp(deviceId, config.bundleId);
|
|
57
|
+
},
|
|
58
|
+
stopApp: async () => {
|
|
59
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
60
|
+
},
|
|
61
|
+
dispose: async () => {
|
|
62
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/typescript/lib/lib.dom.d.ts","../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/tslib/tslib.d.ts","../../../node_modules/tslib/modules/index.d.ts","../../../node_modules/zod/dist/types/v3/helpers/typealiases.d.ts","../../../node_modules/zod/dist/types/v3/helpers/util.d.ts","../../../node_modules/zod/dist/types/v3/zoderror.d.ts","../../../node_modules/zod/dist/types/v3/locales/en.d.ts","../../../node_modules/zod/dist/types/v3/errors.d.ts","../../../node_modules/zod/dist/types/v3/helpers/parseutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/enumutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/errorutil.d.ts","../../../node_modules/zod/dist/types/v3/helpers/partialutil.d.ts","../../../node_modules/zod/dist/types/v3/standard-schema.d.ts","../../../node_modules/zod/dist/types/v3/types.d.ts","../../../node_modules/zod/dist/types/v3/external.d.ts","../../../node_modules/zod/dist/types/v3/index.d.ts","../../../node_modules/zod/dist/types/index.d.ts","../src/config.ts","../../platforms/dist/types.d.ts","../../platforms/dist/factory.d.ts","../../platforms/dist/errors.d.ts","../../platforms/dist/index.d.ts","../../tools/dist/abort.d.ts","../../../node_modules/picocolors/types.d.ts","../../../node_modules/picocolors/picocolors.d.ts","../../tools/dist/color.d.ts","../../tools/dist/logger.d.ts","../../../node_modules/@clack/core/dist/index.d.mts","../../../node_modules/@clack/prompts/dist/index.d.mts","../../tools/dist/prompts.d.ts","../../../node_modules/nano-spawn/source/index.d.ts","../../tools/dist/spawn.d.ts","../../tools/dist/react-native.d.ts","../../tools/dist/error.d.ts","../../tools/dist/index.d.ts","../src/xcrun/simctl.ts","../src/xcrun/devicectl.ts","../src/utils.ts","../src/instance.ts","../src/factory.ts","../src/index.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/dom-events.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/globals.global.d.ts","../../../node_modules/@types/node/index.d.ts"],"fileIdsList":[[131,134,146],[86,134,146],[100,146],[103,146],[104,109,137,146],[105,116,117,124,134,145,146],[105,106,116,124,146],[107,146],[108,109,117,125,146],[109,134,142,146],[110,112,116,124,146],[111,146],[112,113,146],[116,146],[114,116,146],[116,117,118,134,145,146],[116,117,118,131,134,137,146],[146,150],[146],[112,116,119,124,134,145,146],[116,117,119,120,124,134,142,145,146],[119,121,134,142,145,146],[100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152],[116,122,146],[123,145,146],[112,116,124,134,146],[125,146],[126,146],[103,127,146],[128,144,146,150],[129,146],[130,146],[116,131,132,146],[131,133,146,148],[104,116,134,135,136,137,146],[104,134,136,146],[134,135,146],[137,146],[138,146],[116,140,141,146],[140,141,146],[109,124,134,142,146],[143,146],[124,144,146],[104,119,130,145,146],[109,146],[134,146,147],[146,148],[146,149],[104,109,116,118,127,134,145,146,148,150],[134,146,151],[105,146],[82,146],[60,146],[74,146],[64,65,146],[62,63,64,66,67,72,146],[63,64,146],[72,146],[73,146],[64,146],[62,63,64,67,68,69,70,71,146],[62,63,74,146],[61,75,146],[61,76,80,97,146],[61,76,98,146],[61,76,80,94,95,96,146],[61,76,146],[61,93,109,117,125,126,146],[61,93,146],[77,146],[77,78,79,146],[83,146],[81,84,85,88,90,91,92,146],[87,146],[89,146]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"b5ce7a470bc3628408429040c4e3a53a27755022a32fd05e2cb694e7015386c7","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6a5253138c5432c68a1510c70fe78a644fe2e632111ba778e1978010d6edfec","impliedFormat":1},{"version":"b8f34dd1757f68e03262b1ca3ddfa668a855b872f8bdd5224d6f993a7b37dc2c","impliedFormat":99},{"version":"d3cfde44f8089768ebb08098c96d01ca260b88bccf238d55eee93f1c620ff5a5","impliedFormat":1},{"version":"293eadad9dead44c6fd1db6de552663c33f215c55a1bfa2802a1bceed88ff0ec","impliedFormat":1},{"version":"54f6ec6ea75acea6eb23635617252d249145edbc7bcd9d53f2d70280d2aef953","impliedFormat":1},{"version":"c25ce98cca43a3bfa885862044be0d59557be4ecd06989b2001a83dcf69620fd","impliedFormat":1},{"version":"8e71e53b02c152a38af6aec45e288cc65bede077b92b9b43b3cb54a37978bb33","impliedFormat":1},{"version":"754a9396b14ca3a4241591afb4edc644b293ccc8a3397f49be4dfd520c08acb3","impliedFormat":1},{"version":"f672c876c1a04a223cf2023b3d91e8a52bb1544c576b81bf64a8fec82be9969c","impliedFormat":1},{"version":"e4b03ddcf8563b1c0aee782a185286ed85a255ce8a30df8453aade2188bbc904","impliedFormat":1},{"version":"de2316e90fc6d379d83002f04ad9698bc1e5285b4d52779778f454dd12ce9f44","impliedFormat":1},{"version":"25b3f581e12ede11e5739f57a86e8668fbc0124f6649506def306cad2c59d262","impliedFormat":1},{"version":"2da997a01a6aa5c5c09de5d28f0f4407b597c5e1aecfd32f1815809c532650a2","impliedFormat":1},{"version":"5d26d2e47e2352def36f89a3e8bf8581da22b7f857e07ef3114cd52cf4813445","impliedFormat":1},{"version":"3db2efd285e7328d8014b54a7fce3f4861ebcdc655df40517092ed0050983617","impliedFormat":1},{"version":"d5d39a24c759df40480a4bfc0daffd364489702fdbcbdfc1711cde34f8739995","impliedFormat":1},{"version":"9c7dbfc3d2477afe16f56ebcc8a95e24aadd380c2facf9b9fecfce04e87b882e","signature":"277423b251fb375945b8dfcd5ba1a662eec1bd75b39c42a4bcb27912ae9158c7","impliedFormat":99},{"version":"e37270191d6e04dfa60d210394e75002e62398159beec672035a54c9d2827c40","impliedFormat":99},{"version":"fc61bab1427ed7f1e75aaff1d6893859f0ad5832db78e173c7e59abc4b3eebf2","impliedFormat":99},{"version":"742dbfad4257af069a16003c1a48a083697b6fe1c9902ba4a3a54bc08ce8db84","impliedFormat":99},{"version":"6e24348814b735daaa863c787ee558d05db2c9fe90447e97d474ba9f60dfb171","impliedFormat":99},{"version":"3e442c402123b264ccdf7123c1366e1473d9c39f5db69373e938284fc01c49ce","impliedFormat":99},{"version":"590595c1230ebb7c43ebac51b2b2da956a719b213355b4358e2a6b16a8b5936c","impliedFormat":1},{"version":"8c5f0739f00f89f89b03a1fe6658c6d78000d7ebd7f556f0f8d6908fa679de35","impliedFormat":1},{"version":"a15c0df1ac9b2a4d833490522614fc57ae97d70a07bf4964a4d6bb73f3f56399","impliedFormat":99},{"version":"e4cead4a8596a6f051c36ef184f5fb6f117232eefdc1f98ef9847c9efc2c8911","impliedFormat":99},{"version":"df7225806785ade68c6cf2b1cf3ba0d1c7fed1ee7605f34e37d4a901f1d29fd2","impliedFormat":99},{"version":"6bf8a7596880ff1b8f8fd52ee8de8000df00c0c98adacb0b0af0e6a3f16cabe6","impliedFormat":99},{"version":"8af66ec621033f41ccb2bcee775e883c2649fa0db71192fe863185b0281082a6","impliedFormat":99},{"version":"9d4af7bde3e345d3071b5fefbece2d3482971aae89ded50f302c8cb246e81581","impliedFormat":99},{"version":"f3eb748185038bca941a02994b1b0b5803c0a2ce818b8a7d72a24a6b814f5d3e","impliedFormat":99},{"version":"2ba26b5ab00dd3495eeb733cdb46d939a8eb755a395a91169158cdf962aff6c3","impliedFormat":99},{"version":"d6fe58ebff353af75db3986d9ab2b4b57258ad5af3f4b65cdb2100fd47df5425","impliedFormat":99},{"version":"299207f09ec026435d722d979effd6556f7facc6c16256c3c00f797648eed0cb","impliedFormat":99},{"version":"d71a9f0e67f6d98f158f056afca969fc359a241dbdfad6253d55b97d9f530348","signature":"24830d55a5964806840f3a1cef8679ac8ef0e13299edffcf93b73626230e3a97","impliedFormat":99},{"version":"c54595aaed14b999c35fd323fd8d676bb6c0a2d21b909081b8da26be5b1c1516","signature":"6be80d57374da8b7adc9ec6acb08c38699d16b76bda6953c9690018898c40350","impliedFormat":99},{"version":"09d484490fbff29868cd82b10519c45400814800569871ce27c6726e39d1094c","signature":"3ddf102e56cda9d977de594a122b1abed68821c38fd0b73bdb657f5063878177","impliedFormat":99},{"version":"662826451442fa53ec83cec3603b463d1e849135c4e5b50d882ddf363dd7b6ee","signature":"fde73bd38e0324f9613d97b0ca5370b48248f04e0a9f989b1de53176e3f97345","impliedFormat":99},{"version":"b454e6ba2403b80dd29c314e53017725ae2706b250d7b82de92cc177f290a00a","signature":"6a98ca8526c3518a75f3135d1fde19cd3839a3cb6c3e8404f3d282e83a606067","impliedFormat":99},{"version":"6e3f6aeec16f043afcb40227ec7a6bdd7f8f8a0b9d6196bddd8cfb1357a32ce6","signature":"7ebf46b10ce3196a4b117a4f59e33cf37fc84d9e99bbddcb2a69f89f143eca7b","impliedFormat":99},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"f749812878fecfa53cfc13b36e5d35086fb6377983a9df44175da83ccc23af1f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7d2e3fea24c712c99c03ad8f556abedbfe105f87f1be10b95dbd409d24bc05a3","impliedFormat":1},{"version":"211e3f15fbced4ab4be19f49ffa990b9ff20d749d33b65ff753be691e7616239","affectsGlobalScope":true,"impliedFormat":1},{"version":"3719525a8f6ab731e3dfd585d9f87df55ec7d50d461df84f74eb4d68bb165244","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"e596c9bb2f29a2699fdd4ae89139612652245192f67f45617c5a4b20832aaae9","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"1cdcfc1f624d6c08aa12c73935f6e13f095919cd99edf95752951796eb225729","impliedFormat":1},{"version":"4eaff3d8e10676fd7913d8c108890e71c688e1e7d52f6d1d55c39514f493dc47","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"00dee7cdca8b8420c47ea4a31a34b8e8294013ebc4f463fd941e867e7bf05029","affectsGlobalScope":true,"impliedFormat":1},{"version":"3256f3cccd578f9e7fe3a28096c505634bebcee8afb738ffa99368e536ca3a0b","impliedFormat":1},{"version":"1c84b46267610a34028edfd0d035509341751262bac1062857f3c8df7aff7153","impliedFormat":1},{"version":"7f138842074d0a40681775af008c8452093b68c383c94de31759e853c6d06b5c","impliedFormat":1},{"version":"a3d541d303ee505053f5dcbf9fafb65cac3d5631037501cd616195863a6c5740","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0715e4cd28ad471b2a93f3e552ff51a3ae423417a01a10aa1d3bc7c6b95059d6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"4f3fdeba4e28e21aa719c081b8dc8f91d47e12e773389b9d35679c08151c9d37","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"f69ff39996a61a0dd10f4bce73272b52e8024a4d58b13ab32bf4712909d0a2b7","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"1422cd9e705adcc09088fda85a900c2b70e3ad36ea85846f68bd1a884cdf4e2b","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"a73ae8c0e62103bb9e21bb6538700881bf135b9a8b125b857ec68edfa0da4ed3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e1c1b2fbe236bf7ee3e342eeae7e20efb8988a0ac7da1cbbfa2c1f66b76c3423","affectsGlobalScope":true,"impliedFormat":1},{"version":"868831cab82b65dfe1d68180e898af1f2101e89ba9b754d1db6fb8cc2fac1921","impliedFormat":1},{"version":"0fe8985a28f82c450a04a6edf1279d7181c0893f37da7d2a27f8efd4fd5edb03","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"52120bb7e4583612225bdf08e7c12559548170f11e660d33a33623bae9bbdbba","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6dd3dba8e665ac43d279e0fdf5219edda0eed69b5e9a5061f46cd6a65c4f7a1","impliedFormat":1}],"root":[76,[94,99]],"options":{"composite":true,"declarationMap":true,"emitDeclarationOnly":false,"importHelpers":true,"module":199,"noEmitOnError":true,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noUnusedLocals":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"strict":true,"target":9,"tsBuildInfoFile":"./tsconfig.lib.tsbuildinfo"},"referencedMap":[[86,1],[87,2],[100,3],[101,3],[103,4],[104,5],[105,6],[106,7],[107,8],[108,9],[109,10],[110,11],[111,12],[112,13],[113,13],[115,14],[114,15],[116,14],[117,16],[118,17],[102,18],[152,19],[119,20],[120,21],[121,22],[153,23],[122,24],[123,25],[124,26],[125,27],[126,28],[127,29],[128,30],[129,31],[130,32],[131,33],[132,33],[133,34],[134,35],[136,36],[135,37],[137,38],[138,39],[139,19],[140,40],[141,41],[142,42],[143,43],[144,44],[145,45],[146,46],[147,47],[148,48],[149,49],[150,50],[151,51],[89,52],[83,53],[82,19],[61,54],[60,19],[58,19],[59,19],[10,19],[12,19],[11,19],[2,19],[13,19],[14,19],[15,19],[16,19],[17,19],[18,19],[19,19],[20,19],[3,19],[21,19],[22,19],[4,19],[23,19],[27,19],[24,19],[25,19],[26,19],[28,19],[29,19],[30,19],[5,19],[31,19],[32,19],[33,19],[34,19],[6,19],[38,19],[35,19],[36,19],[37,19],[39,19],[7,19],[40,19],[45,19],[46,19],[41,19],[42,19],[43,19],[44,19],[8,19],[50,19],[47,19],[48,19],[49,19],[51,19],[9,19],[52,19],[53,19],[54,19],[56,19],[55,19],[1,19],[57,19],[75,55],[66,56],[73,57],[68,19],[69,19],[67,58],[70,59],[62,19],[63,19],[74,60],[65,61],[71,19],[72,62],[64,63],[76,64],[98,65],[99,66],[97,67],[96,68],[95,69],[94,70],[79,19],[78,71],[80,72],[77,19],[81,19],[84,73],[92,19],[93,74],[85,19],[88,75],[91,19],[90,76]],"latestChangedDtsFile":"./index.d.ts","version":"5.8.3"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvE,eAAO,MAAM,aAAa,GAAI,QAAQ,WAAW,KAAG,MAMnD,CAAC"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const devicectl: <TOutput>(command: string, args: string[]) => Promise<TOutput>;
|
|
2
|
+
export type AppleDeviceInfo = {
|
|
3
|
+
identifier: string;
|
|
4
|
+
deviceProperties: {
|
|
5
|
+
name: string;
|
|
6
|
+
osVersionNumber: string;
|
|
7
|
+
};
|
|
8
|
+
hardwareProperties: {
|
|
9
|
+
marketingName: string;
|
|
10
|
+
productType: string;
|
|
11
|
+
udid: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare const listDevices: () => Promise<AppleDeviceInfo[]>;
|
|
15
|
+
export type AppleAppInfo = {
|
|
16
|
+
bundleIdentifier: string;
|
|
17
|
+
name: string;
|
|
18
|
+
version: string;
|
|
19
|
+
url: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const listApps: (identifier: string) => Promise<AppleAppInfo[]>;
|
|
22
|
+
export declare const getAppInfo: (identifier: string, bundleId: string) => Promise<AppleAppInfo | null>;
|
|
23
|
+
export declare const isAppInstalled: (identifier: string, bundleId: string) => Promise<boolean>;
|
|
24
|
+
export declare const startApp: (identifier: string, bundleId: string) => Promise<void>;
|
|
25
|
+
export type AppleProcessInfo = {
|
|
26
|
+
executable: string;
|
|
27
|
+
processIdentifier: number;
|
|
28
|
+
};
|
|
29
|
+
export declare const getProcesses: (identifier: string) => Promise<AppleProcessInfo[]>;
|
|
30
|
+
export declare const stopApp: (identifier: string, bundleId: string) => Promise<void>;
|
|
31
|
+
export declare const getDeviceId: (name: string) => Promise<string | null>;
|
|
32
|
+
//# sourceMappingURL=devicectl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devicectl.d.ts","sourceRoot":"","sources":["../../src/xcrun/devicectl.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,SAAS,GAAU,OAAO,EACrC,SAAS,MAAM,EACf,MAAM,MAAM,EAAE,KACb,OAAO,CAAC,OAAO,CAejB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,kBAAkB,EAAE;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,eAAe,EAAE,CAK7D,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,YAAY,EAAE,CAQzE,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAW7B,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAQd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,MAAM,KACjB,OAAO,CAAC,gBAAgB,EAAE,CAO5B,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAwBd,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAOrE,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { spawn } from '@react-native-harness/tools';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
export const devicectl = async (command, args) => {
|
|
7
|
+
const tempFile = join(tmpdir(), `devicectl-${randomUUID()}.json`);
|
|
8
|
+
await spawn('xcrun', [
|
|
9
|
+
'devicectl',
|
|
10
|
+
command,
|
|
11
|
+
...args,
|
|
12
|
+
'--json-output',
|
|
13
|
+
tempFile,
|
|
14
|
+
]);
|
|
15
|
+
const output = fs.readFileSync(tempFile, 'utf8');
|
|
16
|
+
fs.unlinkSync(tempFile);
|
|
17
|
+
return JSON.parse(output).result;
|
|
18
|
+
};
|
|
19
|
+
export const listDevices = async () => {
|
|
20
|
+
const result = await devicectl('list', [
|
|
21
|
+
'devices',
|
|
22
|
+
]);
|
|
23
|
+
return result.devices;
|
|
24
|
+
};
|
|
25
|
+
export const listApps = async (identifier) => {
|
|
26
|
+
const result = await devicectl('device', [
|
|
27
|
+
'info',
|
|
28
|
+
'apps',
|
|
29
|
+
'--device',
|
|
30
|
+
identifier,
|
|
31
|
+
]);
|
|
32
|
+
return result.apps;
|
|
33
|
+
};
|
|
34
|
+
export const getAppInfo = async (identifier, bundleId) => {
|
|
35
|
+
const result = await devicectl('device', [
|
|
36
|
+
'info',
|
|
37
|
+
'apps',
|
|
38
|
+
'--device',
|
|
39
|
+
identifier,
|
|
40
|
+
'--bundle-id',
|
|
41
|
+
bundleId,
|
|
42
|
+
]);
|
|
43
|
+
return result.apps[0] ?? null;
|
|
44
|
+
};
|
|
45
|
+
export const isAppInstalled = async (identifier, bundleId) => {
|
|
46
|
+
const apps = await listApps(identifier);
|
|
47
|
+
return apps.some((app) => app.bundleIdentifier === bundleId);
|
|
48
|
+
};
|
|
49
|
+
export const startApp = async (identifier, bundleId) => {
|
|
50
|
+
await devicectl('device', [
|
|
51
|
+
'process',
|
|
52
|
+
'launch',
|
|
53
|
+
'--device',
|
|
54
|
+
identifier,
|
|
55
|
+
bundleId,
|
|
56
|
+
]);
|
|
57
|
+
};
|
|
58
|
+
export const getProcesses = async (identifier) => {
|
|
59
|
+
const result = await devicectl('device', ['info', 'processes', '--device', identifier]);
|
|
60
|
+
return result.runningProcesses;
|
|
61
|
+
};
|
|
62
|
+
export const stopApp = async (identifier, bundleId) => {
|
|
63
|
+
const appInfo = await getAppInfo(identifier, bundleId);
|
|
64
|
+
if (!appInfo) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const processes = await getProcesses(identifier);
|
|
68
|
+
const process = processes.find((process) => process.executable.startsWith(appInfo.url));
|
|
69
|
+
if (!process) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await devicectl('device', [
|
|
73
|
+
'process',
|
|
74
|
+
'terminate',
|
|
75
|
+
'--device',
|
|
76
|
+
identifier,
|
|
77
|
+
'--pid',
|
|
78
|
+
process.processIdentifier.toString(),
|
|
79
|
+
]);
|
|
80
|
+
};
|
|
81
|
+
export const getDeviceId = async (name) => {
|
|
82
|
+
const devices = await listDevices();
|
|
83
|
+
const device = devices.find((device) => device.deviceProperties.name === name);
|
|
84
|
+
return device?.identifier ?? null;
|
|
85
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type AppleAppInfo = {
|
|
2
|
+
Bundle: string;
|
|
3
|
+
CFBundleIdentifier: string;
|
|
4
|
+
CFBundleName: string;
|
|
5
|
+
CFBundleDisplayName: string;
|
|
6
|
+
Path: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const getAppInfo: (udid: string, bundleId: string) => Promise<AppleAppInfo | null>;
|
|
9
|
+
export declare const isAppInstalled: (udid: string, bundleId: string) => Promise<boolean>;
|
|
10
|
+
export type AppleSimulatorState = 'Booted' | 'Booting' | 'Shutdown';
|
|
11
|
+
export type AppleSimulatorInfo = {
|
|
12
|
+
name: string;
|
|
13
|
+
udid: string;
|
|
14
|
+
state: AppleSimulatorState;
|
|
15
|
+
isAvailable: boolean;
|
|
16
|
+
runtime: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const getSimulators: () => Promise<AppleSimulatorInfo[]>;
|
|
19
|
+
export declare const getSimulatorStatus: (udid: string) => Promise<AppleSimulatorState>;
|
|
20
|
+
export declare const startApp: (udid: string, bundleId: string) => Promise<void>;
|
|
21
|
+
export declare const stopApp: (udid: string, bundleId: string) => Promise<void>;
|
|
22
|
+
export declare const getSimulatorId: (name: string, systemVersion: string) => Promise<string | null>;
|
|
23
|
+
//# sourceMappingURL=simctl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simctl.d.ts","sourceRoot":"","sources":["../../src/xcrun/simctl.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,YAAY,GAAG,IAAI,CAkB7B,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,OAAO,CAGjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,mBAAmB,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,kBAAkB,EAAE,CAqBlE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,KACX,OAAO,CAAC,mBAAmB,CAS7B,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,OAAO,GAClB,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,eAAe,MAAM,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAQvB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { spawn, spawnAndForget } from '@react-native-harness/tools';
|
|
2
|
+
const plistToJson = async (plistOutput) => {
|
|
3
|
+
const { stdout: jsonOutput } = await spawn('plutil', ['-convert', 'json', '-o', '-', '-'], { stdin: { string: plistOutput } });
|
|
4
|
+
return JSON.parse(jsonOutput);
|
|
5
|
+
};
|
|
6
|
+
export const getAppInfo = async (udid, bundleId) => {
|
|
7
|
+
const { stdout: plistOutput } = await spawn('xcrun', [
|
|
8
|
+
'simctl',
|
|
9
|
+
'appinfo',
|
|
10
|
+
udid,
|
|
11
|
+
bundleId,
|
|
12
|
+
]);
|
|
13
|
+
const json = await plistToJson(plistOutput);
|
|
14
|
+
// If there is only one entry, it means the app is not installed
|
|
15
|
+
const hasMoreThanOneEntry = Object.keys(json).length > 1;
|
|
16
|
+
if (!hasMoreThanOneEntry) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return json;
|
|
20
|
+
};
|
|
21
|
+
export const isAppInstalled = async (udid, bundleId) => {
|
|
22
|
+
const appInfo = await getAppInfo(udid, bundleId);
|
|
23
|
+
return appInfo !== null;
|
|
24
|
+
};
|
|
25
|
+
export const getSimulators = async () => {
|
|
26
|
+
const { stdout } = await spawn('xcrun', [
|
|
27
|
+
'simctl',
|
|
28
|
+
'list',
|
|
29
|
+
'devices',
|
|
30
|
+
'--json',
|
|
31
|
+
]);
|
|
32
|
+
const runtimeDevices = JSON.parse(stdout).devices;
|
|
33
|
+
const simulators = [];
|
|
34
|
+
Object.entries(runtimeDevices).forEach(([runtime, devices]) => {
|
|
35
|
+
devices.forEach((device) => {
|
|
36
|
+
simulators.push({
|
|
37
|
+
...device,
|
|
38
|
+
runtime,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return simulators;
|
|
43
|
+
};
|
|
44
|
+
export const getSimulatorStatus = async (udid) => {
|
|
45
|
+
const simulators = await getSimulators();
|
|
46
|
+
const simulator = simulators.find((s) => s.udid === udid);
|
|
47
|
+
if (!simulator) {
|
|
48
|
+
throw new Error(`Simulator with UDID ${udid} not found`);
|
|
49
|
+
}
|
|
50
|
+
return simulator.state;
|
|
51
|
+
};
|
|
52
|
+
export const startApp = async (udid, bundleId) => {
|
|
53
|
+
await spawn('xcrun', ['simctl', 'launch', udid, bundleId]);
|
|
54
|
+
};
|
|
55
|
+
export const stopApp = async (udid, bundleId) => {
|
|
56
|
+
await spawnAndForget('xcrun', ['simctl', 'terminate', udid, bundleId]);
|
|
57
|
+
};
|
|
58
|
+
export const getSimulatorId = async (name, systemVersion) => {
|
|
59
|
+
const simulators = await getSimulators();
|
|
60
|
+
const simulator = simulators.find((s) => s.name === name && s.runtime.endsWith(systemVersion.replaceAll('.', '-')));
|
|
61
|
+
return simulator?.udid ?? null;
|
|
62
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import baseConfig from '../../eslint.config.mjs';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...baseConfig,
|
|
5
|
+
{
|
|
6
|
+
files: ['**/*.json'],
|
|
7
|
+
rules: {
|
|
8
|
+
'@nx/dependency-checks': [
|
|
9
|
+
'error',
|
|
10
|
+
{
|
|
11
|
+
ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
languageOptions: {
|
|
16
|
+
parser: await import('jsonc-eslint-parser'),
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@react-native-harness/platform-apple",
|
|
3
|
+
"description": "Apple platform for React Native Harness",
|
|
4
|
+
"version": "1.0.0-alpha.18",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"./package.json": "./package.json",
|
|
11
|
+
".": {
|
|
12
|
+
"development": "./src/index.ts",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"zod": "^3.25.67",
|
|
20
|
+
"tslib": "^2.3.0",
|
|
21
|
+
"@react-native-harness/platforms": "1.0.0-alpha.18",
|
|
22
|
+
"@react-native-harness/tools": "1.0.0-alpha.18"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT"
|
|
25
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const AppleSimulatorSchema = z.object({
|
|
4
|
+
type: z.literal('simulator'),
|
|
5
|
+
name: z.string().min(1, 'Name is required'),
|
|
6
|
+
systemVersion: z.string().min(1, 'System version is required'),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const ApplePhysicalDeviceSchema = z.object({
|
|
10
|
+
type: z.literal('physical'),
|
|
11
|
+
name: z.string().min(1, 'Name is required'),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const AppleDeviceSchema = z.discriminatedUnion('type', [
|
|
15
|
+
AppleSimulatorSchema,
|
|
16
|
+
ApplePhysicalDeviceSchema,
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
export const ApplePlatformConfigSchema = z.object({
|
|
20
|
+
name: z.string().min(1, 'Name is required'),
|
|
21
|
+
device: AppleDeviceSchema,
|
|
22
|
+
bundleId: z.string().min(1, 'Bundle ID is required'),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type AppleSimulator = z.infer<typeof AppleSimulatorSchema>;
|
|
26
|
+
export type ApplePhysicalDevice = z.infer<typeof ApplePhysicalDeviceSchema>;
|
|
27
|
+
export type AppleDevice = z.infer<typeof AppleDeviceSchema>;
|
|
28
|
+
export type ApplePlatformConfig = z.infer<typeof ApplePlatformConfigSchema>;
|
|
29
|
+
|
|
30
|
+
export const isAppleDeviceSimulator = (
|
|
31
|
+
device: AppleDevice
|
|
32
|
+
): device is AppleSimulator => {
|
|
33
|
+
return device.type === 'simulator';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const isAppleDevicePhysical = (
|
|
37
|
+
device: AppleDevice
|
|
38
|
+
): device is ApplePhysicalDevice => {
|
|
39
|
+
return device.type === 'physical';
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function assertAppleDeviceSimulator(
|
|
43
|
+
device: AppleDevice
|
|
44
|
+
): asserts device is AppleSimulator {
|
|
45
|
+
if (!isAppleDeviceSimulator(device)) {
|
|
46
|
+
throw new Error('Device is not a simulator');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function assertAppleDevicePhysical(
|
|
51
|
+
device: AppleDevice
|
|
52
|
+
): asserts device is ApplePhysicalDevice {
|
|
53
|
+
if (!isAppleDevicePhysical(device)) {
|
|
54
|
+
throw new Error('Device is not a physical device');
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/factory.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { HarnessPlatform } from '@react-native-harness/platforms';
|
|
2
|
+
import type {
|
|
3
|
+
AppleSimulator,
|
|
4
|
+
ApplePhysicalDevice,
|
|
5
|
+
ApplePlatformConfig,
|
|
6
|
+
} from './config.js';
|
|
7
|
+
import { ApplePlatformConfigSchema, isAppleDeviceSimulator } from './config.js';
|
|
8
|
+
import {
|
|
9
|
+
getApplePhysicalDevicePlatformInstance,
|
|
10
|
+
getAppleSimulatorPlatformInstance,
|
|
11
|
+
} from './instance.js';
|
|
12
|
+
|
|
13
|
+
export const appleSimulator = (
|
|
14
|
+
name: string,
|
|
15
|
+
systemVersion: string
|
|
16
|
+
): AppleSimulator => ({
|
|
17
|
+
type: 'simulator',
|
|
18
|
+
name,
|
|
19
|
+
systemVersion,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const applePhysicalDevice = (name: string): ApplePhysicalDevice => ({
|
|
23
|
+
type: 'physical',
|
|
24
|
+
name,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const applePlatform = (
|
|
28
|
+
config: ApplePlatformConfig
|
|
29
|
+
): HarnessPlatform => ({
|
|
30
|
+
name: config.name,
|
|
31
|
+
getInstance: async () => {
|
|
32
|
+
const parsedConfig = ApplePlatformConfigSchema.parse(config);
|
|
33
|
+
|
|
34
|
+
if (isAppleDeviceSimulator(parsedConfig.device)) {
|
|
35
|
+
return getAppleSimulatorPlatformInstance(parsedConfig);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return getApplePhysicalDevicePlatformInstance(parsedConfig);
|
|
39
|
+
},
|
|
40
|
+
});
|
package/src/index.ts
ADDED
package/src/instance.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppNotInstalledError,
|
|
3
|
+
DeviceNotFoundError,
|
|
4
|
+
HarnessPlatformInstance,
|
|
5
|
+
} from '@react-native-harness/platforms';
|
|
6
|
+
import {
|
|
7
|
+
ApplePlatformConfig,
|
|
8
|
+
assertAppleDevicePhysical,
|
|
9
|
+
assertAppleDeviceSimulator,
|
|
10
|
+
} from './config.js';
|
|
11
|
+
import * as simctl from './xcrun/simctl.js';
|
|
12
|
+
import * as devicectl from './xcrun/devicectl.js';
|
|
13
|
+
import { getDeviceName } from './utils.js';
|
|
14
|
+
|
|
15
|
+
export const getAppleSimulatorPlatformInstance = async (
|
|
16
|
+
config: ApplePlatformConfig
|
|
17
|
+
): Promise<HarnessPlatformInstance> => {
|
|
18
|
+
assertAppleDeviceSimulator(config.device);
|
|
19
|
+
|
|
20
|
+
const udid = await simctl.getSimulatorId(
|
|
21
|
+
config.device.name,
|
|
22
|
+
config.device.systemVersion
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (!udid) {
|
|
26
|
+
throw new DeviceNotFoundError(getDeviceName(config.device));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isInstalled = await simctl.isAppInstalled(udid, config.bundleId);
|
|
30
|
+
|
|
31
|
+
if (!isInstalled) {
|
|
32
|
+
throw new AppNotInstalledError(
|
|
33
|
+
config.bundleId,
|
|
34
|
+
getDeviceName(config.device)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const simulatorStatus = await simctl.getSimulatorStatus(udid);
|
|
39
|
+
|
|
40
|
+
if (simulatorStatus !== 'Booted') {
|
|
41
|
+
throw new Error('Simulator is not booted');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const isAvailable = await simctl.isAppInstalled(udid, config.bundleId);
|
|
45
|
+
|
|
46
|
+
if (!isAvailable) {
|
|
47
|
+
throw new AppNotInstalledError(
|
|
48
|
+
config.bundleId,
|
|
49
|
+
getDeviceName(config.device)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
startApp: async () => {
|
|
55
|
+
await simctl.startApp(udid, config.bundleId);
|
|
56
|
+
},
|
|
57
|
+
restartApp: async () => {
|
|
58
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
59
|
+
await simctl.startApp(udid, config.bundleId);
|
|
60
|
+
},
|
|
61
|
+
stopApp: async () => {
|
|
62
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
63
|
+
},
|
|
64
|
+
dispose: async () => {
|
|
65
|
+
await simctl.stopApp(udid, config.bundleId);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const getApplePhysicalDevicePlatformInstance = async (
|
|
71
|
+
config: ApplePlatformConfig
|
|
72
|
+
): Promise<HarnessPlatformInstance> => {
|
|
73
|
+
assertAppleDevicePhysical(config.device);
|
|
74
|
+
|
|
75
|
+
const deviceId = await devicectl.getDeviceId(config.device.name);
|
|
76
|
+
|
|
77
|
+
if (!deviceId) {
|
|
78
|
+
throw new DeviceNotFoundError(getDeviceName(config.device));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const isAvailable = await devicectl.isAppInstalled(deviceId, config.bundleId);
|
|
82
|
+
|
|
83
|
+
if (!isAvailable) {
|
|
84
|
+
throw new AppNotInstalledError(
|
|
85
|
+
config.bundleId,
|
|
86
|
+
getDeviceName(config.device)
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
startApp: async () => {
|
|
92
|
+
await devicectl.startApp(deviceId, config.bundleId);
|
|
93
|
+
},
|
|
94
|
+
restartApp: async () => {
|
|
95
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
96
|
+
await devicectl.startApp(deviceId, config.bundleId);
|
|
97
|
+
},
|
|
98
|
+
stopApp: async () => {
|
|
99
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
100
|
+
},
|
|
101
|
+
dispose: async () => {
|
|
102
|
+
await devicectl.stopApp(deviceId, config.bundleId);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { isAppleDeviceSimulator, type AppleDevice } from './config.js';
|
|
2
|
+
|
|
3
|
+
export const getDeviceName = (device: AppleDevice): string => {
|
|
4
|
+
if (isAppleDeviceSimulator(device)) {
|
|
5
|
+
return `${device.name} (${device.systemVersion}) (simulator)`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return `${device.name} (physical)`;
|
|
9
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { spawn } from '@react-native-harness/tools';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
|
|
7
|
+
export const devicectl = async <TOutput>(
|
|
8
|
+
command: string,
|
|
9
|
+
args: string[]
|
|
10
|
+
): Promise<TOutput> => {
|
|
11
|
+
const tempFile = join(tmpdir(), `devicectl-${randomUUID()}.json`);
|
|
12
|
+
|
|
13
|
+
await spawn('xcrun', [
|
|
14
|
+
'devicectl',
|
|
15
|
+
command,
|
|
16
|
+
...args,
|
|
17
|
+
'--json-output',
|
|
18
|
+
tempFile,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const output = fs.readFileSync(tempFile, 'utf8');
|
|
22
|
+
fs.unlinkSync(tempFile);
|
|
23
|
+
|
|
24
|
+
return JSON.parse(output).result;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type AppleDeviceInfo = {
|
|
28
|
+
identifier: string;
|
|
29
|
+
deviceProperties: {
|
|
30
|
+
name: string;
|
|
31
|
+
osVersionNumber: string;
|
|
32
|
+
};
|
|
33
|
+
hardwareProperties: {
|
|
34
|
+
marketingName: string;
|
|
35
|
+
productType: string;
|
|
36
|
+
udid: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const listDevices = async (): Promise<AppleDeviceInfo[]> => {
|
|
41
|
+
const result = await devicectl<{ devices: AppleDeviceInfo[] }>('list', [
|
|
42
|
+
'devices',
|
|
43
|
+
]);
|
|
44
|
+
return result.devices;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type AppleAppInfo = {
|
|
48
|
+
bundleIdentifier: string;
|
|
49
|
+
name: string;
|
|
50
|
+
version: string;
|
|
51
|
+
url: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const listApps = async (identifier: string): Promise<AppleAppInfo[]> => {
|
|
55
|
+
const result = await devicectl<{ apps: AppleAppInfo[] }>('device', [
|
|
56
|
+
'info',
|
|
57
|
+
'apps',
|
|
58
|
+
'--device',
|
|
59
|
+
identifier,
|
|
60
|
+
]);
|
|
61
|
+
return result.apps;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const getAppInfo = async (
|
|
65
|
+
identifier: string,
|
|
66
|
+
bundleId: string
|
|
67
|
+
): Promise<AppleAppInfo | null> => {
|
|
68
|
+
const result = await devicectl<{ apps: AppleAppInfo[] }>('device', [
|
|
69
|
+
'info',
|
|
70
|
+
'apps',
|
|
71
|
+
'--device',
|
|
72
|
+
identifier,
|
|
73
|
+
'--bundle-id',
|
|
74
|
+
bundleId,
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
return result.apps[0] ?? null;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const isAppInstalled = async (
|
|
81
|
+
identifier: string,
|
|
82
|
+
bundleId: string
|
|
83
|
+
): Promise<boolean> => {
|
|
84
|
+
const apps = await listApps(identifier);
|
|
85
|
+
return apps.some((app) => app.bundleIdentifier === bundleId);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const startApp = async (
|
|
89
|
+
identifier: string,
|
|
90
|
+
bundleId: string
|
|
91
|
+
): Promise<void> => {
|
|
92
|
+
await devicectl('device', [
|
|
93
|
+
'process',
|
|
94
|
+
'launch',
|
|
95
|
+
'--device',
|
|
96
|
+
identifier,
|
|
97
|
+
bundleId,
|
|
98
|
+
]);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type AppleProcessInfo = {
|
|
102
|
+
executable: string;
|
|
103
|
+
processIdentifier: number;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const getProcesses = async (
|
|
107
|
+
identifier: string
|
|
108
|
+
): Promise<AppleProcessInfo[]> => {
|
|
109
|
+
const result = await devicectl<{ runningProcesses: AppleProcessInfo[] }>(
|
|
110
|
+
'device',
|
|
111
|
+
['info', 'processes', '--device', identifier]
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return result.runningProcesses;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const stopApp = async (
|
|
118
|
+
identifier: string,
|
|
119
|
+
bundleId: string
|
|
120
|
+
): Promise<void> => {
|
|
121
|
+
const appInfo = await getAppInfo(identifier, bundleId);
|
|
122
|
+
|
|
123
|
+
if (!appInfo) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const processes = await getProcesses(identifier);
|
|
128
|
+
const process = processes.find((process) =>
|
|
129
|
+
process.executable.startsWith(appInfo.url)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (!process) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
await devicectl('device', [
|
|
137
|
+
'process',
|
|
138
|
+
'terminate',
|
|
139
|
+
'--device',
|
|
140
|
+
identifier,
|
|
141
|
+
'--pid',
|
|
142
|
+
process.processIdentifier.toString(),
|
|
143
|
+
]);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const getDeviceId = async (name: string): Promise<string | null> => {
|
|
147
|
+
const devices = await listDevices();
|
|
148
|
+
const device = devices.find(
|
|
149
|
+
(device) => device.deviceProperties.name === name
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return device?.identifier ?? null;
|
|
153
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawn, spawnAndForget } from '@react-native-harness/tools';
|
|
2
|
+
|
|
3
|
+
const plistToJson = async (plistOutput: string): Promise<any> => {
|
|
4
|
+
const { stdout: jsonOutput } = await spawn(
|
|
5
|
+
'plutil',
|
|
6
|
+
['-convert', 'json', '-o', '-', '-'],
|
|
7
|
+
{ stdin: { string: plistOutput } }
|
|
8
|
+
);
|
|
9
|
+
return JSON.parse(jsonOutput);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type AppleAppInfo = {
|
|
13
|
+
Bundle: string;
|
|
14
|
+
CFBundleIdentifier: string;
|
|
15
|
+
CFBundleName: string;
|
|
16
|
+
CFBundleDisplayName: string;
|
|
17
|
+
Path: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const getAppInfo = async (
|
|
21
|
+
udid: string,
|
|
22
|
+
bundleId: string
|
|
23
|
+
): Promise<AppleAppInfo | null> => {
|
|
24
|
+
const { stdout: plistOutput } = await spawn('xcrun', [
|
|
25
|
+
'simctl',
|
|
26
|
+
'appinfo',
|
|
27
|
+
udid,
|
|
28
|
+
bundleId,
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const json = await plistToJson(plistOutput);
|
|
32
|
+
|
|
33
|
+
// If there is only one entry, it means the app is not installed
|
|
34
|
+
const hasMoreThanOneEntry = Object.keys(json).length > 1;
|
|
35
|
+
|
|
36
|
+
if (!hasMoreThanOneEntry) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return json;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const isAppInstalled = async (
|
|
44
|
+
udid: string,
|
|
45
|
+
bundleId: string
|
|
46
|
+
): Promise<boolean> => {
|
|
47
|
+
const appInfo = await getAppInfo(udid, bundleId);
|
|
48
|
+
return appInfo !== null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type AppleSimulatorState = 'Booted' | 'Booting' | 'Shutdown';
|
|
52
|
+
|
|
53
|
+
export type AppleSimulatorInfo = {
|
|
54
|
+
name: string;
|
|
55
|
+
udid: string;
|
|
56
|
+
state: AppleSimulatorState;
|
|
57
|
+
isAvailable: boolean;
|
|
58
|
+
runtime: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const getSimulators = async (): Promise<AppleSimulatorInfo[]> => {
|
|
62
|
+
const { stdout } = await spawn('xcrun', [
|
|
63
|
+
'simctl',
|
|
64
|
+
'list',
|
|
65
|
+
'devices',
|
|
66
|
+
'--json',
|
|
67
|
+
]);
|
|
68
|
+
const runtimeDevices: Record<string, AppleSimulatorInfo[]> =
|
|
69
|
+
JSON.parse(stdout).devices;
|
|
70
|
+
const simulators: AppleSimulatorInfo[] = [];
|
|
71
|
+
|
|
72
|
+
Object.entries(runtimeDevices).forEach(([runtime, devices]) => {
|
|
73
|
+
devices.forEach((device) => {
|
|
74
|
+
simulators.push({
|
|
75
|
+
...device,
|
|
76
|
+
runtime,
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return simulators;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const getSimulatorStatus = async (
|
|
85
|
+
udid: string
|
|
86
|
+
): Promise<AppleSimulatorState> => {
|
|
87
|
+
const simulators = await getSimulators();
|
|
88
|
+
const simulator = simulators.find((s) => s.udid === udid);
|
|
89
|
+
|
|
90
|
+
if (!simulator) {
|
|
91
|
+
throw new Error(`Simulator with UDID ${udid} not found`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return simulator.state;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const startApp = async (
|
|
98
|
+
udid: string,
|
|
99
|
+
bundleId: string
|
|
100
|
+
): Promise<void> => {
|
|
101
|
+
await spawn('xcrun', ['simctl', 'launch', udid, bundleId]);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const stopApp = async (
|
|
105
|
+
udid: string,
|
|
106
|
+
bundleId: string
|
|
107
|
+
): Promise<void> => {
|
|
108
|
+
await spawnAndForget('xcrun', ['simctl', 'terminate', udid, bundleId]);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const getSimulatorId = async (
|
|
112
|
+
name: string,
|
|
113
|
+
systemVersion: string
|
|
114
|
+
): Promise<string | null> => {
|
|
115
|
+
const simulators = await getSimulators();
|
|
116
|
+
const simulator = simulators.find(
|
|
117
|
+
(s) =>
|
|
118
|
+
s.name === name && s.runtime.endsWith(systemVersion.replaceAll('.', '-'))
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return simulator?.udid ?? null;
|
|
122
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
8
|
+
"emitDeclarationOnly": false,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"types": ["node"],
|
|
11
|
+
"lib": ["DOM", "ES2022"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*.ts"],
|
|
14
|
+
"references": [
|
|
15
|
+
{
|
|
16
|
+
"path": "../tools/tsconfig.lib.json"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "../platforms/tsconfig.lib.json"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|