@skrillex1224/android-toolkit 0.1.8 → 1.0.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/index.d.ts CHANGED
@@ -1,191 +1,164 @@
1
1
  export interface AndroidContext {
2
- adbPath?: string;
3
- fridaPath?: string;
4
- fridaServerPath?: string;
5
- fridaWebViewEventAgentScript?: string;
6
- serial: string;
7
- packageName: string;
8
- query: string;
9
- runId?: string;
10
- [key: string]: any;
11
- }
12
-
13
- export interface AndroidActorShareInfo {
14
- mode: 'clipboard' | 'custom';
15
- prefix: string;
16
- xurl: Array<string | string[]>;
17
- }
18
-
19
- export interface AndroidActorInfoItem {
20
- key: string;
21
- name: string;
22
- icon: string;
23
- share: AndroidActorShareInfo;
24
- [key: string]: any;
25
- }
26
-
27
- export interface AndroidConstantsModule {
28
- Code: Record<string, number>;
29
- Status: Record<string, string>;
30
- ActorInfo: Record<string, AndroidActorInfoItem>;
31
- }
32
-
33
- export interface AndroidCrawlerErrorInfo {
34
- message: string;
35
- code?: number;
36
- context?: Record<string, any>;
37
- }
38
-
39
- export interface AndroidCrawlerError extends Error {
40
- code: number;
41
- context?: Record<string, any>;
42
- }
43
-
44
- export interface AndroidErrorsModule {
45
- CrawlerError: new (info: AndroidCrawlerErrorInfo) => AndroidCrawlerError;
46
- serializeError(error: unknown): Record<string, any>;
47
- }
48
-
49
- export interface AndroidLogger {
50
- debug(message: string, meta?: Record<string, any>): void;
51
- info(message: string, meta?: Record<string, any>): void;
52
- warn(message: string, meta?: Record<string, any>): void;
53
- success(message: string, meta?: Record<string, any>): void;
54
- fail(message: string, error?: unknown): void;
55
- start(message: string, meta?: Record<string, any>): void;
56
- duration(startedAt: number): string;
57
- createLogger(scope: string): AndroidLogger;
58
- }
59
-
60
- export interface AndroidDeviceModule {
61
- adbShell(ctx: AndroidContext, args: string[], options?: Record<string, any>): Promise<string>;
62
- adbExec(ctx: AndroidContext, args: string[], options?: Record<string, any>): Promise<string>;
63
- forceStopApp(ctx: AndroidContext, packageName?: string): Promise<void>;
64
- startActivity(ctx: AndroidContext, component: string, args?: string[]): Promise<void>;
65
- startLauncher(ctx: AndroidContext, packageName?: string, launcherActivity?: string): Promise<void>;
66
- waitForForeground(ctx: AndroidContext, packageName?: string, timeoutMs?: number): Promise<boolean>;
67
- screenSize(ctx: AndroidContext): Promise<{ width: number; height: number }>;
68
- screenDensity(ctx: AndroidContext): Promise<number>;
69
- overrideScreenSize(ctx: AndroidContext, width: number, height: number): Promise<void>;
70
- resetScreenSize(ctx: AndroidContext): Promise<void>;
71
- resetScreenDensity(ctx: AndroidContext): Promise<void>;
72
- click(ctx: AndroidContext, pointOrX: any, y?: number): Promise<void>;
73
- move(ctx: AndroidContext, from: { x: number; y: number }, to: { x: number; y: number }, durationMs?: number): Promise<void>;
74
- pressBack(ctx: AndroidContext): Promise<void>;
75
- wakeAndUnlock(ctx: AndroidContext): Promise<void>;
76
- focusedActivity(ctx: AndroidContext): Promise<string>;
77
- waitForActivity(ctx: AndroidContext, predicate: (focused: string) => boolean, timeoutMs?: number, intervalMs?: number): Promise<string>;
78
- screenshotPng(ctx: AndroidContext): Promise<Buffer>;
79
- screenshotBase64(ctx: AndroidContext): Promise<string>;
80
- [key: string]: any;
81
- }
82
-
83
- export interface AndroidFridaModule {
84
- runScript(ctx: AndroidContext, source: string, options?: Record<string, any>): Promise<any>;
85
- querySQLite(ctx: AndroidContext, options?: Record<string, any>): Promise<any>;
86
- startWebViewEventRecorder(ctx: AndroidContext, config?: Record<string, any>, options?: Record<string, any>): Promise<any>;
87
- }
88
-
89
- export interface AndroidShareScreenCompressionOptions {
90
- enabled?: boolean;
91
- maxBytes?: number;
92
- maxBase64Bytes?: number;
93
- type?: 'jpeg' | 'jpg';
94
- outputType?: 'jpeg' | 'jpg';
95
- quality?: number;
96
- minQuality?: number;
97
- minScale?: number;
98
- }
99
-
100
- export interface AndroidShareScreenCaptureOptions {
101
- Frida?: AndroidFridaModule;
102
- frida?: AndroidFridaModule;
103
- actorInfo?: string | AndroidActorInfoItem;
104
- actor?: string | AndroidActorInfoItem;
105
- actorKey?: string | AndroidActorInfoItem;
106
- restore?: boolean;
107
- maxHeight?: number;
108
- width?: number;
109
- height?: number;
110
- settleMs?: number;
111
- scrollToTop?: boolean;
112
- timeoutMs?: number;
113
- fridaTimeoutSeconds?: number;
114
- maxBytes?: number;
115
- maxBase64Bytes?: number;
116
- type?: 'jpeg' | 'jpg';
117
- outputType?: 'jpeg' | 'jpg';
118
- quality?: number;
119
- minQuality?: number;
120
- minScale?: number;
121
- compression?: boolean | AndroidShareScreenCompressionOptions;
122
- compress?: boolean;
123
- }
124
-
125
- export interface AndroidShareLinkCaptureOptions {
126
- actorInfo?: string | AndroidActorInfoItem;
127
- actor?: string | AndroidActorInfoItem;
128
- actorKey?: string | AndroidActorInfoItem;
129
- share?: Partial<AndroidActorShareInfo>;
130
- timeoutMs?: number;
131
- pollIntervalMs?: number;
132
- payloadSnapshotMaxLen?: number;
133
- signal?: AbortSignal;
134
- performActions?: () => any | Promise<any>;
135
- }
136
-
137
- export interface AndroidShareLinkCaptureResult {
138
- link: string | null;
139
- payloadText: string;
140
- payloadSnapshot: string;
141
- source: 'clipboard' | 'custom' | 'none' | string;
142
- }
143
-
144
- export interface AndroidShareModule {
145
- captureScreen(ctx: AndroidContext, options?: AndroidShareScreenCaptureOptions): Promise<string>;
146
- captureLink(ctx: AndroidContext, options?: AndroidShareLinkCaptureOptions): Promise<AndroidShareLinkCaptureResult>;
147
- }
148
-
149
- export interface AndroidApifyKitInstance {
150
- runStep<T>(name: string, meta: any, fn: () => Promise<T> | T): Promise<T>;
151
- runStepLoose<T>(name: string, meta: any, fn: () => Promise<T> | T): Promise<T>;
152
- pushSuccess(data: any): Promise<void>;
153
- pushFailed(error: unknown, context?: Record<string, any>): Promise<void>;
154
- pushArtifact(data: any): Promise<void>;
155
- hasPushed(): boolean;
156
- }
157
-
158
- export interface AndroidApifyKitModule {
159
- useApifyKit(options?: Record<string, any>): Promise<AndroidApifyKitInstance>;
160
- }
161
-
162
- export interface AndroidLaunchRunHandlerArgs {
163
- input: any;
164
- ctx: AndroidContext;
165
- kit: {
166
- ApifyKit: AndroidApifyKitInstance;
167
- Device: AndroidDeviceModule;
168
- Frida: AndroidFridaModule;
169
- Share: AndroidShareModule;
170
- Logger: AndroidLogger;
171
- };
172
- ApifyKit: AndroidApifyKitInstance;
173
- }
174
-
175
- export interface AndroidLaunchModule {
176
- run(handler: (args: AndroidLaunchRunHandlerArgs) => Promise<void> | void, options?: Record<string, any>): Promise<void>;
2
+ runId: string;
3
+ query: string;
4
+ serial: string;
5
+ packageName: string;
6
+ adbPath: string;
7
+ fridaPath: string;
8
+ actorKey?: string;
9
+ appVersion?: string;
10
+ slotKey?: string;
11
+ instanceId?: string;
12
+ externalIp?: string;
13
+ }
14
+
15
+ export interface ViewBounds {
16
+ left: number;
17
+ top: number;
18
+ right: number;
19
+ bottom: number;
20
+ width: number;
21
+ height: number;
22
+ centerX: number;
23
+ centerY: number;
24
+ }
25
+
26
+ export interface ViewNode {
27
+ resourceId: string;
28
+ id: string;
29
+ text: string;
30
+ contentDesc: string;
31
+ className: string;
32
+ packageName: string;
33
+ bounds: ViewBounds;
34
+ clickable: boolean;
35
+ enabled: boolean;
36
+ focusable: boolean;
37
+ focused: boolean;
38
+ scrollable: boolean;
39
+ visible: boolean;
40
+ children: ViewNode[];
41
+ }
42
+
43
+ export type ViewSelector = {
44
+ id?: string;
45
+ text?: string;
46
+ textContains?: string;
47
+ contentDesc?: string;
48
+ };
49
+
50
+ export namespace Constants {
51
+ export const Code: Record<string, number>;
52
+ export const Status: Record<string, string>;
53
+ export const UnicodeIme: {
54
+ packageName: string;
55
+ component: string;
56
+ inputTextAction: string;
57
+ };
58
+ export const ActorInfo: Record<string, {
59
+ key: string;
60
+ name: string;
61
+ icon: string;
62
+ share: {
63
+ mode: 'clipboard';
64
+ prefix: string;
65
+ xurl: unknown[];
66
+ };
67
+ }>;
68
+ }
69
+
70
+ export namespace Errors {
71
+ export class CrawlerError extends Error {
72
+ code: number;
73
+ context: Record<string, unknown>;
74
+ constructor(input?: string | {
75
+ message?: string;
76
+ code?: number;
77
+ context?: Record<string, unknown>;
78
+ });
79
+ static isCrawlerError(error: unknown): boolean;
80
+ static from(error: unknown, fallback?: {
81
+ code?: number;
82
+ context?: Record<string, unknown>;
83
+ }): CrawlerError;
84
+ }
85
+ export function serializeError(error: unknown): Record<string, unknown>;
177
86
  }
178
87
 
179
88
  export interface AndroidToolkit {
180
- Launch: AndroidLaunchModule;
181
- ApifyKit: AndroidApifyKitModule;
182
- Device: AndroidDeviceModule;
183
- Frida: AndroidFridaModule;
184
- Share: AndroidShareModule;
185
- Constants: AndroidConstantsModule;
186
- Errors: AndroidErrorsModule;
187
- Logger: AndroidLogger;
188
- Context: Record<string, any>;
89
+ Launch: {
90
+ run(handler: (args: {
91
+ input: Record<string, unknown>;
92
+ ctx: AndroidContext;
93
+ kit: AndroidToolkitRuntime;
94
+ ApifyKit: AndroidToolkitRuntime['ApifyKit'];
95
+ }) => Promise<void>, options?: Record<string, unknown>): Promise<void>;
96
+ };
97
+ ApifyKit: {
98
+ useApifyKit(options?: Record<string, unknown>): Promise<AndroidToolkitRuntime['ApifyKit']>;
99
+ };
100
+ DeviceInput: AndroidToolkitRuntime['DeviceInput'];
101
+ DeviceView: AndroidToolkitRuntime['DeviceView'];
102
+ Device: AndroidToolkitRuntime['Device'];
103
+ Mutation: AndroidToolkitRuntime['Mutation'];
104
+ Share: AndroidToolkitRuntime['Share'];
105
+ Frida: AndroidToolkitRuntime['Frida'];
106
+ Constants: typeof Constants;
107
+ Errors: typeof Errors;
108
+ Logger: AndroidToolkitRuntime['Logger'];
109
+ Context: {
110
+ createAndroidContext(input?: Record<string, unknown>, defaults?: Record<string, unknown>): AndroidContext;
111
+ firstNonEmpty(...values: unknown[]): string;
112
+ requireNonEmpty(value: unknown, name: string): string;
113
+ };
114
+ }
115
+
116
+ export interface AndroidToolkitRuntime {
117
+ ApifyKit: {
118
+ runStep<T>(step: string, target: unknown, actionFn: () => Promise<T>, options?: Record<string, unknown>): Promise<T>;
119
+ runStepLoose<T>(step: string, target: unknown, actionFn: () => Promise<T>, options?: Record<string, unknown>): Promise<T>;
120
+ pushSuccess(data?: Record<string, unknown>, options?: Record<string, unknown>): Promise<void>;
121
+ pushFailed(error: unknown, meta?: Record<string, unknown>): Promise<void>;
122
+ pushArtifact(data?: Record<string, unknown>): Promise<void>;
123
+ hasPushed(): boolean;
124
+ };
125
+ Device: Record<string, (...args: any[]) => Promise<any>>;
126
+ DeviceInput: {
127
+ click(ctx: AndroidContext, selectorOrPoint: ViewSelector | ViewBounds | {x: number; y: number}, options?: Record<string, unknown>): Promise<unknown>;
128
+ tap(ctx: AndroidContext, selectorOrPoint: ViewSelector | ViewBounds | {x: number; y: number}, options?: Record<string, unknown>): Promise<unknown>;
129
+ fill(ctx: AndroidContext, selector: ViewSelector, text: string, options?: Record<string, unknown>): Promise<void>;
130
+ type(ctx: AndroidContext, selector: ViewSelector, text: string, options?: Record<string, unknown>): Promise<void>;
131
+ press(ctx: AndroidContext, key: string, options?: Record<string, unknown>): Promise<void>;
132
+ pressEnter(ctx: AndroidContext, options?: Record<string, unknown>): Promise<void>;
133
+ scroll(ctx: AndroidContext, selector: ViewSelector, direction: 'up' | 'down', options?: Record<string, unknown>): Promise<void>;
134
+ scrollToEnd(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<unknown>;
135
+ scrollToTop(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<unknown>;
136
+ };
137
+ DeviceView: {
138
+ snapshot(ctx: AndroidContext, options?: Record<string, unknown>): Promise<{xml: string; tree: ViewNode[]; roots: ViewNode[]; flat: ViewNode[]; nodes: ViewNode[]}>;
139
+ find(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<ViewNode>;
140
+ findAll(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<ViewNode[]>;
141
+ waitFor(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<ViewNode>;
142
+ bounds(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<ViewBounds>;
143
+ text(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<string>;
144
+ exists(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<boolean>;
145
+ isScrollable(ctx: AndroidContext, selector: ViewSelector, options?: Record<string, unknown>): Promise<boolean>;
146
+ hashNode(node: ViewNode): string;
147
+ };
148
+ Mutation: {
149
+ waitForStable(ctx: AndroidContext, selectors: ViewSelector | ViewSelector[] | string | string[], options?: Record<string, unknown>): Promise<Record<string, unknown>>;
150
+ waitForStableAcrossRoots(ctx: AndroidContext, selectors: ViewSelector | ViewSelector[] | string | string[], options?: Record<string, unknown>): Promise<Record<string, unknown>>;
151
+ useMonitor(ctx: AndroidContext, selectors: ViewSelector | ViewSelector[] | string | string[], options?: Record<string, unknown>): Promise<{stop(): Promise<Record<string, unknown>>}>;
152
+ };
153
+ Share: {
154
+ captureScreen(ctx: AndroidContext, options?: Record<string, unknown>): Promise<string>;
155
+ captureLink(ctx: AndroidContext, options?: Record<string, unknown>): Promise<{link: string; source: string; payloadSnapshot: string}>;
156
+ };
157
+ Frida: {
158
+ querySQLite(ctx: AndroidContext, options: Record<string, unknown>): Promise<Record<string, unknown>>;
159
+ health(ctx: AndroidContext): Promise<Record<string, unknown>>;
160
+ };
161
+ Logger: Record<string, any>;
189
162
  }
190
163
 
191
164
  export function useAndroidToolKit(): AndroidToolkit;
package/package.json CHANGED
@@ -1,29 +1,47 @@
1
1
  {
2
2
  "name": "@skrillex1224/android-toolkit",
3
- "version": "0.1.8",
3
+ "version": "1.0.0",
4
+ "description": "Native Android automation toolkit for Apify-compatible actors.",
4
5
  "type": "module",
5
- "main": "index.js",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
6
8
  "types": "index.d.ts",
7
9
  "exports": {
8
- ".": "./index.js"
10
+ ".": {
11
+ "browser": {
12
+ "types": "./browser.d.ts",
13
+ "default": "./dist/browser.js"
14
+ },
15
+ "types": "./index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs"
18
+ },
19
+ "./browser": {
20
+ "types": "./browser.d.ts",
21
+ "default": "./dist/browser.js"
22
+ }
9
23
  },
10
24
  "files": [
11
- "index.js",
25
+ "dist/",
26
+ "browser.d.ts",
12
27
  "index.d.ts",
13
- "entrys",
14
- "src",
15
- "scripts",
16
28
  "README.md"
17
29
  ],
18
30
  "scripts": {
19
- "postinstall": "node scripts/postinstall.js",
20
- "check": "node --check index.js && node --check entrys/node.js && node --check src/launch.js && node --check src/apify-kit.js && node --check src/context.js && node --check src/constants.js && node --check src/device.js && node --check src/errors.js && node --check src/frida-client.js && node --check src/logger.js && node --check src/share.js && node --check src/internals/compression.js && node --check src/internals/frida/webview_event_agent.js",
21
- "test": "node --test test/*.test.js"
31
+ "build": "node build.js",
32
+ "check": "node --check index.js && node --check entrys/node.js && node --check entrys/browser.js && node --check build.js && find src -name '*.js' -maxdepth 3 -print0 | xargs -0 -n1 node --check",
33
+ "test": "node --test test/*.test.js",
34
+ "prepublishOnly": "npm run build"
22
35
  },
23
36
  "engines": {
24
37
  "node": ">=18"
25
38
  },
26
39
  "dependencies": {
40
+ "esbuild": "^0.24.2",
41
+ "fast-xml-parser": "^4.5.1",
27
42
  "jimp": "^1.6.1"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
28
46
  }
29
47
  }
package/entrys/node.js DELETED
@@ -1,26 +0,0 @@
1
- import { Launch } from '../src/launch.js';
2
- import { ApifyKit } from '../src/apify-kit.js';
3
- import { Device } from '../src/device.js';
4
- import { Frida } from '../src/frida-client.js';
5
- import { Share } from '../src/share.js';
6
- import * as Constants from '../src/constants.js';
7
- import * as Errors from '../src/errors.js';
8
- import { Logger } from '../src/logger.js';
9
- import { Context } from '../src/context.js';
10
-
11
- // Unified Entry Point
12
- // 和 playwright-toolkit 的 usePlaywrightToolKit() 保持同一种入口格式:
13
- // visitor/androider 只从这里取模块,不直接穿透到内部文件。
14
- export const useAndroidToolKit = () => {
15
- return {
16
- Launch,
17
- ApifyKit,
18
- Device,
19
- Frida,
20
- Share,
21
- Constants,
22
- Errors,
23
- Logger,
24
- Context
25
- };
26
- };
package/index.js DELETED
@@ -1 +0,0 @@
1
- export { useAndroidToolKit } from './entrys/node.js';
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import {execFileSync, spawnSync} from 'node:child_process';
4
-
5
- log('检查 Android toolkit 运行环境');
6
- checkAdb();
7
- installOrCheckFrida();
8
-
9
- function checkAdb() {
10
- const adb = findCommand('adb');
11
- if (adb) {
12
- log(`已找到 adb: ${adb}`);
13
- return;
14
- }
15
- warn(`未找到 adb。请安装 Android platform-tools,并确保 \`adb\` 在 PATH 中。${installHintForAdb()}`);
16
- }
17
-
18
- function installOrCheckFrida() {
19
- const frida = findCommand('frida');
20
- if (frida) {
21
- log(`已找到 frida: ${frida}`);
22
- return;
23
- }
24
-
25
- const pip3 = findCommand('pip3');
26
- const python3 = findCommand('python3');
27
- if (!pip3 || !python3) {
28
- warn(`未找到 frida,且当前机器缺少 python3/pip3,无法自动安装 frida-tools。${installHintForFrida()}`);
29
- return;
30
- }
31
-
32
- try {
33
- log('尝试自动安装 frida-tools 到用户目录');
34
- execFileSync(python3, ['-m', 'pip', 'install', '--user', '--upgrade', 'frida-tools'], {stdio: 'inherit'});
35
- const installedFrida = findCommand('frida');
36
- if (installedFrida) {
37
- log(`frida 安装成功: ${installedFrida}`);
38
- return;
39
- }
40
- warn('frida-tools 已安装,但 `frida` 仍不在 PATH 中。请把 Python user bin 加入 PATH。');
41
- return;
42
- } catch (error) {
43
- warn(`自动安装 frida-tools 失败: ${error.message || String(error)}`);
44
- }
45
-
46
- warn(`未能自动准备 frida,请手动确认 \`frida --version\` 可执行。${installHintForFrida()}`);
47
- }
48
-
49
- function findCommand(command) {
50
- const result = spawnSync('which', [command], {encoding: 'utf8'});
51
- return result.status === 0 ? String(result.stdout || '').trim() : '';
52
- }
53
-
54
- function installHintForAdb() {
55
- if (process.platform === 'darwin') return ' macOS 可用 `brew install android-platform-tools`。';
56
- if (process.platform === 'linux') return ' Linux 可安装 Android platform-tools,或用系统包管理器安装 adb(如 apt/dnf/pacman/apk)。';
57
- return '';
58
- }
59
-
60
- function installHintForFrida() {
61
- if (process.platform === 'darwin') return ' macOS 也可用 `python3 -m pip install --user frida-tools`。';
62
- if (process.platform === 'linux') return ' Linux 也可用 `python3 -m pip install --user frida-tools`。';
63
- return '';
64
- }
65
-
66
- function log(message) {
67
- console.log(`[android-toolkit] ${message}`);
68
- }
69
-
70
- function warn(message) {
71
- console.warn(`[android-toolkit] ${message}`);
72
- }