devicely 2.1.4 → 2.1.6
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/bin/devicely.js +105 -1
- package/lib/androidDeviceDetection.js +276 -1
- package/lib/appMappings.js +337 -1
- package/lib/deviceDetection.js +394 -1
- package/lib/devices.js +54 -1
- package/lib/doctor.js +94 -1
- package/lib/executor.js +104 -1
- package/lib/logger.js +35 -1
- package/lib/scriptLoader.js +75 -1
- package/lib/server.js +3485 -1
- package/package.json +3 -12
- package/scripts/compile-shell-scripts.js +208 -0
- package/scripts/encrypt-shell-simple.js +75 -0
- package/scripts/obfuscate-shell.js +160 -0
- package/scripts/shell/android_device_control +0 -0
- package/scripts/shell/apps_presets.conf +271 -0
- package/scripts/shell/connect_android_usb +0 -0
- package/scripts/shell/connect_android_usb_multi_final +0 -0
- package/scripts/shell/connect_android_wireless +0 -0
- package/scripts/shell/connect_android_wireless_multi_final +0 -0
- package/scripts/shell/connect_ios_usb +0 -0
- package/scripts/shell/connect_ios_usb_multi_final +0 -0
- package/scripts/shell/connect_ios_wireless_multi_final +0 -0
- package/scripts/shell/create_production_scripts +0 -0
- package/scripts/shell/devices.conf +24 -0
- package/scripts/shell/diagnose_wireless_ios +0 -0
- package/scripts/shell/find_element_coordinates +0 -0
- package/scripts/shell/find_wda +0 -0
- package/scripts/shell/install_uiautomator2 +0 -0
- package/scripts/shell/ios_device_control +0 -0
- package/scripts/shell/organize_project +0 -0
- package/scripts/shell/pre-publish-check +0 -0
- package/scripts/shell/publish +0 -0
- package/scripts/shell/publish-to-npm +0 -0
- package/scripts/shell/setup +0 -0
- package/scripts/shell/setup_android +0 -0
- package/scripts/shell/start +0 -0
- package/scripts/shell/sync-to-npm-package-final +0 -0
- package/scripts/shell/test_android_locators +0 -0
- package/scripts/shell/test_connect +0 -0
- package/scripts/shell/test_device_detection +0 -0
- package/scripts/shell/test_fixes +0 -0
- package/scripts/shell/test_getlocators_fix +0 -0
- package/scripts/shell/test_recording_feature +0 -0
- package/scripts/shell/verify-shell-protection +0 -0
- package/scripts/shell/verify_distribution +0 -0
- package/lib/package-lock.json +0 -1678
- package/lib/package.json +0 -30
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_225900.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_225942.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_231101.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_232911.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260208_095103.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260208_095720.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115040.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115047.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115118.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115125.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115143.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120107.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120118.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120137.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120201.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_134529.png +0 -0
- package/scripts/shell/android_device_control.enc +0 -1
- package/scripts/shell/connect_android_usb_multi_final.enc +0 -1
- package/scripts/shell/connect_android_wireless.enc +0 -1
- package/scripts/shell/connect_android_wireless_multi_final.enc +0 -1
- package/scripts/shell/connect_ios_usb_multi_final.enc +0 -1
- package/scripts/shell/connect_ios_wireless_multi_final.enc +0 -1
- package/scripts/shell/ios_device_control.enc +0 -1
package/bin/devicely.js
CHANGED
|
@@ -1,3 +1,107 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Devicely CLI Entry Point
|
|
5
|
+
* AI-Powered Device Pool
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { program } = require('commander');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const packageJson = require('../package.json');
|
|
11
|
+
const { startServer } = require('../lib/server');
|
|
12
|
+
const { listDevices } = require('../lib/devices');
|
|
13
|
+
const { checkDoctor } = require('../lib/doctor');
|
|
14
|
+
const { executeCommand } = require('../lib/executor');
|
|
15
|
+
|
|
16
|
+
// Configure CLI
|
|
17
|
+
program
|
|
18
|
+
.name('devicely')
|
|
19
|
+
.description('Devicely - One Command, All Devices. AI Powered Mobile Automation')
|
|
20
|
+
.version(packageJson.version, '-v, --version', 'Display version number')
|
|
21
|
+
.helpOption('-h, --help', 'Display help information');
|
|
22
|
+
|
|
23
|
+
// Start command - Launch server and open web UI
|
|
24
|
+
program
|
|
25
|
+
.command('start')
|
|
26
|
+
.description('Start Devicely server and open web interface')
|
|
27
|
+
.option('-p, --port <port>', 'Server port', '3001')
|
|
28
|
+
.option('--no-browser', 'Don\'t open browser automatically')
|
|
29
|
+
.option('--debug', 'Enable debug logging')
|
|
30
|
+
.option('--usb-only', 'Detect USB devices only')
|
|
31
|
+
.option('--wifi-only', 'Detect WiFi devices only')
|
|
32
|
+
.action(async (options) => {
|
|
33
|
+
try {
|
|
34
|
+
console.log(chalk.cyan.bold('\n🚀 Devicely - One Command, All Devices'));
|
|
35
|
+
console.log(chalk.gray(' AI Powered Mobile Automation'));
|
|
36
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
37
|
+
|
|
38
|
+
await startServer(options);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(chalk.red('\n❌ Error:'), error.message);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// List command - Show connected devices
|
|
46
|
+
program
|
|
47
|
+
.command('list')
|
|
48
|
+
.description('List all connected iOS and Android devices')
|
|
49
|
+
.option('-v, --verbose', 'Show detailed device information')
|
|
50
|
+
.action(async (options) => {
|
|
51
|
+
try {
|
|
52
|
+
console.log(chalk.cyan.bold('\n📱 Scanning for devices...'));
|
|
53
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
54
|
+
|
|
55
|
+
await listDevices(options);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red('\n❌ Error:'), error.message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Doctor command - Check system requirements
|
|
63
|
+
program
|
|
64
|
+
.command('doctor')
|
|
65
|
+
.description('Check system requirements for iOS and Android automation')
|
|
66
|
+
.action(async () => {
|
|
67
|
+
try {
|
|
68
|
+
console.log(chalk.cyan.bold('\n🔍 Checking system requirements...'));
|
|
69
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
70
|
+
|
|
71
|
+
await checkDoctor();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(chalk.red('\n❌ Error:'), error.message);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Exec command - Execute command on devices
|
|
79
|
+
program
|
|
80
|
+
.command('exec <command>')
|
|
81
|
+
.description('Execute command on connected iOS/Android devices')
|
|
82
|
+
.option('-d, --device <name>', 'Execute on specific device')
|
|
83
|
+
.option('-a, --all', 'Execute on all devices (default)')
|
|
84
|
+
.action(async (command, options) => {
|
|
85
|
+
try {
|
|
86
|
+
console.log(chalk.cyan.bold('\n⚡ Executing command...'));
|
|
87
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
88
|
+
|
|
89
|
+
await executeCommand(command, options);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(chalk.red('\n❌ Error:'), error.message);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Parse arguments
|
|
97
|
+
program.parse(process.argv);
|
|
98
|
+
|
|
99
|
+
// Show help if no command provided
|
|
100
|
+
if (!process.argv.slice(2).length) {
|
|
101
|
+
program.outputHelp();
|
|
102
|
+
console.log(chalk.cyan('\n💡 Quick start:'));
|
|
103
|
+
console.log(chalk.gray(' devicely start ') + chalk.white('# Start the server'));
|
|
104
|
+
console.log(chalk.gray(' devicely list ') + chalk.white('# List devices'));
|
|
105
|
+
console.log(chalk.gray(' devicely doctor ') + chalk.white('# Check system'));
|
|
106
|
+
console.log('');
|
|
107
|
+
}
|
|
@@ -1,2 +1,277 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const _0x13a7e8=_0x88cc;(function(_0x4827aa,_0x25043e){const _0x15c85c=_0x88cc,_0x3166b4=_0x4827aa();while(!![]){try{const _0x431c00=-parseInt(_0x15c85c(0xd4))/0x1*(parseInt(_0x15c85c(0xf6))/0x2)+parseInt(_0x15c85c(0xb0))/0x3*(parseInt(_0x15c85c(0xe6))/0x4)+-parseInt(_0x15c85c(0x93))/0x5*(-parseInt(_0x15c85c(0x110))/0x6)+parseInt(_0x15c85c(0x10a))/0x7+parseInt(_0x15c85c(0xac))/0x8+-parseInt(_0x15c85c(0x9b))/0x9+parseInt(_0x15c85c(0xa9))/0xa*(-parseInt(_0x15c85c(0xe4))/0xb);if(_0x431c00===_0x25043e)break;else _0x3166b4['push'](_0x3166b4['shift']());}catch(_0x14706d){_0x3166b4['push'](_0x3166b4['shift']());}}}(_0x1db9,0xf3603));const {exec,execSync}=require(_0x13a7e8(0xc6)),{promisify}=require(_0x13a7e8(0xc9)),execAsync=promisify(exec);async function detectUSBDevices(){const _0x4a1f64=_0x13a7e8,_0x18582d={'BDXCM':'Error\x20detecting\x20USB\x20Android\x20devices:','zRkzU':function(_0x15f625,_0x36e6b9){return _0x15f625(_0x36e6b9);},'coRDX':'adb\x20devices\x20-l','kgvVp':'device','GwylR':function(_0x65f02c,_0x2e27f1){return _0x65f02c!==_0x2e27f1;},'CcvbZ':_0x4a1f64(0xec),'HMUiz':_0x4a1f64(0xd1),'InUOv':'qXpil','mFTDp':'WJOrf','Muqil':_0x4a1f64(0xf9),'uldJH':'android','dFODL':_0x4a1f64(0xce),'NAKYJ':_0x4a1f64(0xbb),'DBKgB':'ILStQ'};try{const {stdout:_0x1ec3a4}=await _0x18582d[_0x4a1f64(0x8a)](execAsync,_0x18582d[_0x4a1f64(0x10f)]),_0x41f4aa=_0x1ec3a4[_0x4a1f64(0x8b)]('\x0a')['slice'](0x1),_0x34295a=[];for(const _0x9f391b of _0x41f4aa){if(!_0x9f391b[_0x4a1f64(0x10c)]()||!_0x9f391b[_0x4a1f64(0xf3)](_0x18582d['kgvVp']))continue;const _0x176b34=_0x9f391b['trim']()[_0x4a1f64(0x8b)](/\s+/),_0x37dec4=_0x176b34[0x0],_0x53ec20=_0x176b34[0x1];if(_0x18582d[_0x4a1f64(0x8e)](_0x53ec20,_0x18582d['kgvVp']))continue;if(_0x37dec4[_0x4a1f64(0xf3)](':'))continue;let _0x21e290=_0x18582d[_0x4a1f64(0x96)];const _0x281fc2=_0x9f391b[_0x4a1f64(0xe8)](/model:([^\s]+)/);if(_0x281fc2){if(_0x18582d['HMUiz']!==_0x4a1f64(0xd1))return _0x1a7028[_0x4a1f64(0x94)](_0x18582d['BDXCM'],_0x5930af[_0x4a1f64(0x101)]),[];else _0x21e290=_0x281fc2[0x1]['replace'](/_/g,'\x20');}else try{if(_0x18582d[_0x4a1f64(0xb9)]!==_0x4a1f64(0xd7)){const {stdout:_0x20ffef}=await execAsync(_0x4a1f64(0xbe)+_0x37dec4+_0x4a1f64(0xf1));_0x21e290=_0x20ffef[_0x4a1f64(0x10c)]()[_0x4a1f64(0xa7)](/\r/g,'');}else return![];}catch(_0x41bf91){}let _0x292819='';try{if(_0x18582d[_0x4a1f64(0xc7)]===_0x18582d[_0x4a1f64(0xae)])_0x4c86cb[_0x4a1f64(0xb5)](_0x1d79a2['serial']),_0x3372ed[_0x4a1f64(0x112)](_0x3fba27);else{const {stdout:_0x177fea}=await execAsync(_0x4a1f64(0xbe)+_0x37dec4+_0x4a1f64(0xa1));_0x292819=_0x177fea['trim']()[_0x4a1f64(0xa7)](/\r/g,'');}}catch(_0x4e7916){}const _0x42d6d2={};_0x42d6d2[_0x4a1f64(0xde)]=_0x21e290,_0x42d6d2[_0x4a1f64(0xa8)]=_0x37dec4,_0x42d6d2['serial']=_0x37dec4,_0x42d6d2['ip']='',_0x42d6d2[_0x4a1f64(0x10e)]=_0x18582d['uldJH'],_0x42d6d2[_0x4a1f64(0x8f)]='usb',_0x42d6d2[_0x4a1f64(0xc8)]=_0x18582d['dFODL'],_0x42d6d2[_0x4a1f64(0x10d)]=_0x292819,_0x42d6d2[_0x4a1f64(0xff)]=_0x18582d[_0x4a1f64(0x9e)],_0x34295a[_0x4a1f64(0x112)](_0x42d6d2);}return _0x34295a;}catch(_0x580435){return _0x18582d[_0x4a1f64(0x8e)](_0x18582d[_0x4a1f64(0xc4)],_0x18582d[_0x4a1f64(0xc4)])?[]:(console[_0x4a1f64(0x94)](_0x18582d[_0x4a1f64(0x92)],_0x580435[_0x4a1f64(0x101)]),[]);}}async function detectWirelessDevices(){const _0x45bca8=_0x13a7e8,_0x13dcff={'OalsW':function(_0x33811a,_0xdcc349){return _0x33811a(_0xdcc349);},'wEpLw':_0x45bca8(0x10b),'nsJPL':_0x45bca8(0xad),'gKNTA':_0x45bca8(0x111),'xqCBe':function(_0x3d160d,_0xa88c6c){return _0x3d160d!==_0xa88c6c;},'geqGV':'Unknown','JRCgU':function(_0x502d05,_0xfb5a5a){return _0x502d05(_0xfb5a5a);},'OtNHM':function(_0x479e1d,_0x337044){return _0x479e1d!==_0x337044;},'FaDTU':function(_0x17b398,_0x266223){return _0x17b398===_0x266223;},'NNLmQ':_0x45bca8(0x8c),'nhtqc':_0x45bca8(0x9d),'UPidz':_0x45bca8(0x9a),'RENea':_0x45bca8(0xbb)};try{const {stdout:_0x2e7f0a}=await _0x13dcff['OalsW'](execAsync,_0x13dcff[_0x45bca8(0xe1)]),_0x22c25c=_0x2e7f0a[_0x45bca8(0x8b)]('\x0a')[_0x45bca8(0xbd)](0x1),_0x31b251=[];for(const _0x80348e of _0x22c25c){if(!_0x80348e[_0x45bca8(0x10c)]()||!_0x80348e[_0x45bca8(0xf3)](_0x13dcff[_0x45bca8(0xeb)]))continue;if(!_0x80348e[_0x45bca8(0xf3)](_0x13dcff[_0x45bca8(0xcb)]))continue;const _0x5f6d4f=_0x80348e[_0x45bca8(0x10c)]()[_0x45bca8(0x8b)](/\s+/),_0x1e293e=_0x5f6d4f[0x0],_0x162037=_0x5f6d4f[0x1];if(_0x13dcff[_0x45bca8(0xbf)](_0x162037,_0x45bca8(0xad)))continue;const [_0x48969a,_0x3ea78f]=_0x1e293e['split'](':');let _0x24e45a=_0x13dcff[_0x45bca8(0x113)];try{const {stdout:_0x3b9436}=await _0x13dcff[_0x45bca8(0xd0)](execAsync,'adb\x20-s\x20'+_0x1e293e+'\x20shell\x20getprop\x20ro.product.model');_0x24e45a=_0x3b9436[_0x45bca8(0x10c)]()[_0x45bca8(0xa7)](/\r/g,'');}catch(_0x5d3372){}let _0x2cbaf6=_0x1e293e;try{const {stdout:_0x1aa6c1}=await execAsync(_0x45bca8(0xbe)+_0x1e293e+_0x45bca8(0xa5)),_0x427ca3=_0x1aa6c1[_0x45bca8(0x10c)]()[_0x45bca8(0xa7)](/\r/g,'');_0x427ca3&&_0x13dcff[_0x45bca8(0xb3)](_0x427ca3,_0x45bca8(0x107))&&(_0x2cbaf6=_0x427ca3);}catch(_0xde272a){}let _0x1a5f07='';try{if(_0x13dcff[_0x45bca8(0xa3)](_0x13dcff['NNLmQ'],_0x13dcff['NNLmQ'])){const {stdout:_0x5a2e5a}=await execAsync(_0x45bca8(0xbe)+_0x1e293e+_0x45bca8(0xa1));_0x1a5f07=_0x5a2e5a['trim']()['replace'](/\r/g,'');}else _0x21ecbd=_0x37a79e;}catch(_0x104dd6){}const _0x97a725={};_0x97a725[_0x45bca8(0xde)]=_0x24e45a,_0x97a725[_0x45bca8(0xa8)]=_0x1e293e,_0x97a725[_0x45bca8(0xa6)]=_0x2cbaf6,_0x97a725['ip']=_0x48969a,_0x97a725[_0x45bca8(0x10e)]=_0x13dcff['nhtqc'],_0x97a725[_0x45bca8(0x8f)]=_0x13dcff['UPidz'],_0x97a725[_0x45bca8(0xc8)]=_0x13dcff[_0x45bca8(0xef)],_0x97a725['osVersion']=_0x1a5f07,_0x97a725[_0x45bca8(0xff)]=_0x13dcff[_0x45bca8(0xc5)],_0x31b251[_0x45bca8(0x112)](_0x97a725);}return _0x31b251;}catch(_0x554183){return console['error']('Error\x20detecting\x20wireless\x20Android\x20devices:',_0x554183[_0x45bca8(0x101)]),[];}}async function discoverAllAndroidDevices(){const _0x295d25=_0x13a7e8,_0x30e74c={'pgUAS':_0x295d25(0x91),'DtLPc':_0x295d25(0xdd),'TvaTI':_0x295d25(0xd9),'CoCAm':_0x295d25(0xf0),'zfPwp':_0x295d25(0xf5),'UTiYf':'\x0aMake\x20sure:','WFATg':_0x295d25(0x108),'wGnrt':function(_0x56d664,_0x88534d,_0x26d6ed){return _0x56d664(_0x88534d,_0x26d6ed);},'NycgJ':_0x295d25(0xea),'uWIqp':_0x295d25(0xed),'umiDH':function(_0x126bd6,_0x9906d2,_0x16dc78){return _0x126bd6(_0x9906d2,_0x16dc78);},'chUrY':_0x295d25(0x97),'TVgak':function(_0x369f9c){return _0x369f9c();},'QjqYp':function(_0x2de4f7,_0x3aa55d){return _0x2de4f7===_0x3aa55d;},'dzVDd':'oOPmt','biWRD':function(_0x162710,_0x17cbc1){return _0x162710!==_0x17cbc1;},'tFmkG':_0x295d25(0xd3)};try{try{_0x30e74c[_0x295d25(0xdb)](execSync,_0x295d25(0xea),{'stdio':_0x30e74c[_0x295d25(0xb7)]});}catch(_0x5cb423){if(_0x30e74c[_0x295d25(0xd2)]===_0x30e74c[_0x295d25(0xd2)])return console[_0x295d25(0xfb)](_0x295d25(0x114)),[];else{const _0x4535d9=_0x30e74c[_0x295d25(0x109)][_0x295d25(0x8b)]('|');let _0x47e5ad=0x0;while(!![]){switch(_0x4535d9[_0x47e5ad++]){case'0':_0x2cfc78[_0x295d25(0xd6)](_0x30e74c[_0x295d25(0xb6)]);continue;case'1':_0xab6dbf[_0x295d25(0xd6)](_0x30e74c[_0x295d25(0xb8)]);continue;case'2':_0x267cd9[_0x295d25(0xf2)](0x1);continue;case'3':_0x1b9e4c[_0x295d25(0xd6)](_0x30e74c[_0x295d25(0xc3)]);continue;case'4':_0x3b3bdf[_0x295d25(0xd6)](_0x295d25(0xcc));continue;case'5':_0x3f343b[_0x295d25(0xd6)](_0x30e74c[_0x295d25(0x87)]);continue;case'6':_0x453da9[_0x295d25(0xd6)](_0x30e74c[_0x295d25(0xe5)]);continue;}break;}}}const [_0x44626d,_0x38b632]=await Promise[_0x295d25(0xa4)]([_0x30e74c[_0x295d25(0xca)](detectUSBDevices),detectWirelessDevices()]),_0x5f262f=[..._0x44626d,..._0x38b632],_0x32331e=[],_0x4d88f7=new Set();for(const _0x27fa12 of _0x5f262f){if(_0x30e74c[_0x295d25(0xe0)](_0x30e74c[_0x295d25(0x8d)],_0x30e74c[_0x295d25(0x8d)]))!_0x4d88f7[_0x295d25(0xcf)](_0x27fa12['serial'])&&(_0x4d88f7[_0x295d25(0xb5)](_0x27fa12[_0x295d25(0xa6)]),_0x32331e[_0x295d25(0x112)](_0x27fa12));else return _0x3ae260[_0x295d25(0x94)](_0x30e74c[_0x295d25(0x98)],_0x42ea70['message']),[];}return _0x32331e;}catch(_0x14e7db){if(_0x30e74c[_0x295d25(0xe3)](_0x30e74c[_0x295d25(0x106)],_0x295d25(0xe2)))return console[_0x295d25(0x94)](_0x30e74c[_0x295d25(0x98)],_0x14e7db[_0x295d25(0x101)]),[];else _0x30e74c[_0x295d25(0xc0)](_0x3b5123,_0x30e74c['NycgJ'],{'stdio':_0x30e74c[_0x295d25(0xb7)]});}}function _0x1db9(){const _0x3f321d=['Dw5RBM93BG','rxjYB3iGzgLZy292zxjPBMCGqw5KCM9PzcbKzxzPy2vZoG','CgDvqvm','odG4oteXmxnzANnLqG','ywrIigrLDMLJzxmGlwW','DhjPBq','B3nwzxjZAw9U','CgXHDgzVCM0','y29srfG','mta1mdGZmZrSwgHur3K','oJu1ntu','ChvZAa','z2vXr1y','qurcig5VDcbMB3vUzc4GugXLyxnLigLUC3rHBgWGqw5KCM9PzcbtreSGugXHDgzVCM0Gvg9VBhmU','EMzqD3a','zhP0wgW','yw5KCM9PzfzLCNnPB24','ELjRELu','C3bSAxq','AM1iCvG','zhPwrgq','r3D5Bfi','y29UBMvJDgLVBLr5Cgu','cK1HA2uGC3vYztO','nxW2Fdf8m3W0Fdb8mG','qKryq00','nxvhyxbPrW','zxjYB3i','r2jYELe','q2n2yLO','DgDPq2i','v0zbvgC','u2XQAe0','D2LYzwXLC3m','odu1nty4ognrqxrkyW','icaGsva6ia','yw5KCM9Pza','tKflwuO','DLbezM4','tuHIDue','ihnOzwXSigDLDhbYB3aGCM8UyNvPBgqUDMvYC2LVBI5YzwXLyxnL','ihnOzwXSigr1BxbZExmGyMf0DgvYEq','rMfevfu','ywXS','ihnOzwXSigDLDhbYB3aGCM8UC2vYAwfSBM8','C2vYAwfS','CMvWBgfJzq','DwrPza','ntGWndG0mgPzzM9SvW','Aw1bsNO','tM5AzMW','odCXotyWsxHduwHu','zgv2AwnL','txvXAwW','icaGqMf0DgvYEtOG','m1DKDwL5BG','z2v0sw5ZDgfSBgvKqxbWCW','8j+KLIbezxrLy3rPBMCGqw5KCM9PzcbKzxzPy2vZlI4UcG','t3rose0','8j+tSsa','ywrK','rhrmugm','DvDjCxa','vhzHveK','sw5vt3y','zMLSDgvY','y29UBMvJDgvK','Dg9vChbLCKnHC2u','C2XPy2u','ywrIic1Zia','EhfdqMu','D0DUCNq','ze9Ayue','q05Mve4','q29dqw0','rejlz0i','uKvozwe','y2HPBgrFChjVy2vZCW','Buzurha','DhLWzq','DxrPBa','vfzNywS','z0Tovee','icaZlIbezxzPy2uGAxmGyxv0Ag9YAxPLzcaOy2HLy2SGzgv2AwnLihnJCMvLBIK','ihnOzwXSihbTigXPC3qGCgfJA2fNzxmGltm','DxnI','AgfZ','sLjdz1u','yMfeAge','y2HvCLK','CNvcrNi','mJm2nJvtswLrr2O','ihnOzwXSihbTigXPC3qGCgfJA2fNzxm','Bg9N','AgrryuO','icaGqw5KCM9PzdOG','icaXlIbezxzPy2uGAxmGy29UBMvJDgvKihzPysbvu0iGB3iGD2LYzwXLC3nSEq','CgfJA2fNztO','Dw1PreG','ww90uMC','ica0lIbbreiGAxmGChjVCgvYBhKGAw5ZDgfSBgvK','BMfTzq','tuzSt2S','uwPXwxa','D0vWthC','qLbdrwe','yMLxuKq','mtfkv1ntrg8','vvrPwwy','mtK0nti2ng5PrfnvCW','u3nArha','Bwf0y2G','BuvAzgu','D2HPy2GGywrI','BNnkueW','vw5RBM93BG','AwDUB3jL','Axnvsuf1Dg9TyxrVCJjjBNn0ywXSzwq','vvbPzhO','icaYlIbvu0iGzgvIDwDNAw5NigLZigvUywjSzwq','ihnOzwXSigDLDhbYB3aGCM8UChjVzhvJDc5TB2rLBa','zxHPDa','Aw5JBhvKzxm','4PYxie5VDcbPBNn0ywXSzwq','tM8Gqw5KCM9PzcbKzxzPy2vZigrLDgvJDgvKlG','otjlswfrCeG','zxHWB3j0CW','Aw8UyxbWAxvTlNvPyxv0B21HDg9YmI5Zzxj2zxi','ug5Yr1G','zgLZy292zxjbBgXbBMrYB2LKrgv2AwnLCW','D2fYBG','BK1PB2e','zxPbv0m','wLHtDLy','C3rHDhvZ','tfDsz3i','BwvZC2fNzq','uMroqxK','BwfW','rM91BMqG','4PYtieLUC3rHBgXLza','DezTA0C'];_0x1db9=function(){return _0x3f321d;};return _0x1db9();}function _0x88cc(_0x381d2b,_0x1709a4){_0x381d2b=_0x381d2b-0x87;const _0x1db948=_0x1db9();let _0x88cccd=_0x1db948[_0x381d2b];if(_0x88cc['saEEbr']===undefined){var _0x3b4fe4=function(_0x1260d6){const _0x16bf71='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5c7cfe='',_0x1cc6dc='';for(let _0x227645=0x0,_0x44cde2,_0xd8b81,_0xe59bc3=0x0;_0xd8b81=_0x1260d6['charAt'](_0xe59bc3++);~_0xd8b81&&(_0x44cde2=_0x227645%0x4?_0x44cde2*0x40+_0xd8b81:_0xd8b81,_0x227645++%0x4)?_0x5c7cfe+=String['fromCharCode'](0xff&_0x44cde2>>(-0x2*_0x227645&0x6)):0x0){_0xd8b81=_0x16bf71['indexOf'](_0xd8b81);}for(let _0x1a7028=0x0,_0x5930af=_0x5c7cfe['length'];_0x1a7028<_0x5930af;_0x1a7028++){_0x1cc6dc+='%'+('00'+_0x5c7cfe['charCodeAt'](_0x1a7028)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1cc6dc);};_0x88cc['GxZEaD']=_0x3b4fe4,_0x88cc['icqsZf']={},_0x88cc['saEEbr']=!![];}const _0x105f8b=_0x1db948[0x0],_0x197850=_0x381d2b+_0x105f8b,_0x2ed625=_0x88cc['icqsZf'][_0x197850];return!_0x2ed625?(_0x88cccd=_0x88cc['GxZEaD'](_0x88cccd),_0x88cc['icqsZf'][_0x197850]=_0x88cccd):_0x88cccd=_0x2ed625,_0x88cccd;}async function getDeviceBattery(_0x33eb11){const _0x1730b8=_0x13a7e8,_0x565224={'imAJz':function(_0xdde70b,_0x102a39){return _0xdde70b(_0x102a39);}};try{const {stdout:_0x61763d}=await execAsync(_0x1730b8(0xbe)+_0x33eb11+_0x1730b8(0xa2)),_0x1c75b4=_0x61763d[_0x1730b8(0xe8)](/level:\s*(\d+)/);return _0x1c75b4?_0x565224[_0x1730b8(0xaa)](parseInt,_0x1c75b4[0x1]):-0x1;}catch(_0x48e6d7){return-0x1;}}async function isUIAutomator2Installed(_0x13f941){const _0x31d5ab=_0x13a7e8,_0x2fb5f2={'HHYuG':function(_0x1d6952,_0x3cd48f){return _0x1d6952(_0x3cd48f);},'nPDTz':_0x31d5ab(0xf8)};try{const {stdout:_0x3ba9b7}=await _0x2fb5f2['HHYuG'](execAsync,_0x31d5ab(0xbe)+_0x13f941+_0x31d5ab(0xd5));return _0x3ba9b7['includes'](_0x2fb5f2['nPDTz']);}catch(_0x484a0e){return![];}}async function getInstalledApps(_0xcf2fbd){const _0x91eebd=_0x13a7e8,_0x2ff963={'MHbuA':function(_0x47ebee,_0x34c873){return _0x47ebee(_0x34c873);}};try{const {stdout:_0x15c0a3}=await _0x2ff963[_0x91eebd(0xa0)](execAsync,_0x91eebd(0xbe)+_0xcf2fbd+_0x91eebd(0xcd));return _0x15c0a3[_0x91eebd(0x8b)]('\x0a')[_0x91eebd(0xba)](_0x7c426=>_0x7c426[_0x91eebd(0x10c)]())[_0x91eebd(0x103)](_0x46ed7f=>_0x46ed7f[_0x91eebd(0xa7)](_0x91eebd(0xda),'')['trim']());}catch(_0x1795e9){return[];}}const _0x5b974a={};_0x5b974a['detectUSBDevices']=detectUSBDevices,_0x5b974a['detectWirelessDevices']=detectWirelessDevices,_0x5b974a[_0x13a7e8(0xfa)]=discoverAllAndroidDevices,_0x5b974a['getDeviceBattery']=getDeviceBattery,_0x5b974a[_0x13a7e8(0xee)]=isUIAutomator2Installed,_0x5b974a[_0x13a7e8(0xb1)]=getInstalledApps,module[_0x13a7e8(0xf7)]=_0x5b974a;require['main']===module&&((async()=>{const _0x14451c=_0x13a7e8,_0x164cc3={'SljhM':'ADB\x20not\x20found.\x20Please\x20install\x20Android\x20SDK\x20Platform\x20Tools.','igjbI':_0x14451c(0xb2),'NnZfl':function(_0x38e6d5){return _0x38e6d5();},'ezAWC':function(_0x4c29f1,_0x3264d7){return _0x4c29f1===_0x3264d7;},'RdNAy':function(_0x3ec1dd,_0xf038c6){return _0x3ec1dd!==_0xf038c6;},'LWRgr':_0x14451c(0x88),'GbrzQ':_0x14451c(0xf5),'vPDfn':'\x20\x201.\x20Device\x20is\x20connected\x20via\x20USB\x20or\x20wirelessly','mEZde':_0x14451c(0xcc),'MFlOk':'\x20\x204.\x20ADB\x20is\x20properly\x20installed','nMioa':'LAaip','dOZaA':function(_0x26cc7c,_0x483e53){return _0x26cc7c>=_0x483e53;},'YotRg':function(_0x27da0c,_0xb8389){return _0x27da0c(_0xb8389);},'CNfTN':_0x14451c(0x105),'ZXSvV':_0x14451c(0xf4)};console['log'](_0x164cc3['igjbI']);const _0x4e28ee=await _0x164cc3[_0x14451c(0xab)](discoverAllAndroidDevices);if(_0x164cc3[_0x14451c(0xfd)](_0x4e28ee['length'],0x0)){if(_0x164cc3[_0x14451c(0x102)](_0x164cc3[_0x14451c(0x100)],_0x164cc3[_0x14451c(0x100)]))return-0x1;else console[_0x14451c(0xd6)](_0x164cc3[_0x14451c(0x95)]),console[_0x14451c(0xd6)](_0x14451c(0x90)),console[_0x14451c(0xd6)](_0x164cc3[_0x14451c(0x9f)]),console[_0x14451c(0xd6)](_0x14451c(0xf0)),console[_0x14451c(0xd6)](_0x164cc3[_0x14451c(0xe9)]),console[_0x14451c(0xd6)](_0x164cc3[_0x14451c(0xdf)]),process[_0x14451c(0xf2)](0x1);}console[_0x14451c(0xd6)](_0x14451c(0x104)+_0x4e28ee['length']+'\x20device(s):\x0a');for(const _0x414596 of _0x4e28ee){if(_0x164cc3['ezAWC'](_0x164cc3[_0x14451c(0xfc)],_0x14451c(0xe7)))return _0x37a9ed[_0x14451c(0xfb)](GxvKMs[_0x14451c(0x99)]),[];else{console[_0x14451c(0xd6)](_0x14451c(0xb4)+_0x414596[_0x14451c(0xde)]),console[_0x14451c(0xd6)]('\x20\x20\x20Serial:\x20'+_0x414596[_0x14451c(0xa6)]),console[_0x14451c(0xd6)](_0x14451c(0xd8)+_0x414596[_0x14451c(0x89)]),console[_0x14451c(0xd6)]('\x20\x20\x20Connection:\x20'+_0x414596[_0x14451c(0x8f)][_0x14451c(0xbc)]());if(_0x414596['ip'])console[_0x14451c(0xd6)](_0x14451c(0x9c)+_0x414596['ip']);const _0x4474ec=await getDeviceBattery(_0x414596[_0x14451c(0xa6)]);if(_0x164cc3[_0x14451c(0xc1)](_0x4474ec,0x0))console[_0x14451c(0xd6)](_0x14451c(0xaf)+_0x4474ec+'%');const _0x2f25c1=await _0x164cc3[_0x14451c(0xdc)](isUIAutomator2Installed,_0x414596[_0x14451c(0xa6)]);console[_0x14451c(0xd6)]('\x20\x20\x20UIAutomator2:\x20'+(_0x2f25c1?_0x164cc3[_0x14451c(0xc2)]:_0x164cc3[_0x14451c(0xfe)])),console['log']('');}}})());
|
|
2
|
+
/**
|
|
3
|
+
* Android Device Detection Module
|
|
4
|
+
* Detects Android devices connected via USB and wireless
|
|
5
|
+
* Compatible with iOS device detection module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { exec, execSync } = require('child_process');
|
|
9
|
+
const { promisify } = require('util');
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detect USB-connected Android devices
|
|
14
|
+
* @returns {Promise<Array>} List of detected devices
|
|
15
|
+
*/
|
|
16
|
+
async function detectUSBDevices() {
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await execAsync('adb devices -l');
|
|
19
|
+
const lines = stdout.split('\n').slice(1); // Skip header
|
|
20
|
+
|
|
21
|
+
const devices = [];
|
|
22
|
+
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
if (!line.trim() || !line.includes('device')) continue;
|
|
25
|
+
|
|
26
|
+
const parts = line.trim().split(/\s+/);
|
|
27
|
+
const serial = parts[0];
|
|
28
|
+
const status = parts[1];
|
|
29
|
+
|
|
30
|
+
if (status !== 'device') continue;
|
|
31
|
+
|
|
32
|
+
// Skip wireless devices (they have :PORT in serial)
|
|
33
|
+
if (serial.includes(':')) continue;
|
|
34
|
+
|
|
35
|
+
// Get device model
|
|
36
|
+
let model = 'Unknown';
|
|
37
|
+
const modelMatch = line.match(/model:([^\s]+)/);
|
|
38
|
+
if (modelMatch) {
|
|
39
|
+
model = modelMatch[1].replace(/_/g, ' ');
|
|
40
|
+
} else {
|
|
41
|
+
try {
|
|
42
|
+
const { stdout: modelStdout } = await execAsync(`adb -s ${serial} shell getprop ro.product.model`);
|
|
43
|
+
model = modelStdout.trim().replace(/\r/g, '');
|
|
44
|
+
} catch (err) {
|
|
45
|
+
// Ignore error, use Unknown
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get Android version
|
|
50
|
+
let androidVersion = '';
|
|
51
|
+
try {
|
|
52
|
+
const { stdout: versionStdout } = await execAsync(`adb -s ${serial} shell getprop ro.build.version.release`);
|
|
53
|
+
androidVersion = versionStdout.trim().replace(/\r/g, '');
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// Ignore
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
devices.push({
|
|
59
|
+
name: model,
|
|
60
|
+
udid: serial,
|
|
61
|
+
serial: serial,
|
|
62
|
+
ip: '',
|
|
63
|
+
platform: 'android',
|
|
64
|
+
connectionType: 'usb',
|
|
65
|
+
type: 'usb',
|
|
66
|
+
osVersion: androidVersion,
|
|
67
|
+
status: 'connected'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return devices;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Error detecting USB Android devices:', error.message);
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Detect wireless Android devices
|
|
80
|
+
* @returns {Promise<Array>} List of detected wireless devices
|
|
81
|
+
*/
|
|
82
|
+
async function detectWirelessDevices() {
|
|
83
|
+
try {
|
|
84
|
+
const { stdout } = await execAsync('adb devices -l');
|
|
85
|
+
const lines = stdout.split('\n').slice(1);
|
|
86
|
+
|
|
87
|
+
const devices = [];
|
|
88
|
+
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
if (!line.trim() || !line.includes('device')) continue;
|
|
91
|
+
if (!line.includes(':5555')) continue; // Wireless connections typically use port 5555
|
|
92
|
+
|
|
93
|
+
const parts = line.trim().split(/\s+/);
|
|
94
|
+
const address = parts[0]; // IP:PORT
|
|
95
|
+
const status = parts[1];
|
|
96
|
+
|
|
97
|
+
if (status !== 'device') continue;
|
|
98
|
+
|
|
99
|
+
const [ip, port] = address.split(':');
|
|
100
|
+
|
|
101
|
+
// Get device info
|
|
102
|
+
let model = 'Unknown';
|
|
103
|
+
try {
|
|
104
|
+
const { stdout: modelStdout } = await execAsync(`adb -s ${address} shell getprop ro.product.model`);
|
|
105
|
+
model = modelStdout.trim().replace(/\r/g, '');
|
|
106
|
+
} catch (err) {
|
|
107
|
+
// Ignore
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let serial = address;
|
|
111
|
+
try {
|
|
112
|
+
const { stdout: serialStdout } = await execAsync(`adb -s ${address} shell getprop ro.serialno`);
|
|
113
|
+
const actualSerial = serialStdout.trim().replace(/\r/g, '');
|
|
114
|
+
if (actualSerial && actualSerial !== 'unknown') {
|
|
115
|
+
serial = actualSerial;
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
// Keep using IP:PORT as serial
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let androidVersion = '';
|
|
122
|
+
try {
|
|
123
|
+
const { stdout: versionStdout } = await execAsync(`adb -s ${address} shell getprop ro.build.version.release`);
|
|
124
|
+
androidVersion = versionStdout.trim().replace(/\r/g, '');
|
|
125
|
+
} catch (err) {
|
|
126
|
+
// Ignore
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
devices.push({
|
|
130
|
+
name: model,
|
|
131
|
+
udid: address, // For wireless, UDID is IP:PORT
|
|
132
|
+
serial: serial,
|
|
133
|
+
ip: ip,
|
|
134
|
+
platform: 'android',
|
|
135
|
+
connectionType: 'wireless',
|
|
136
|
+
type: 'wireless',
|
|
137
|
+
osVersion: androidVersion,
|
|
138
|
+
status: 'connected'
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return devices;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('Error detecting wireless Android devices:', error.message);
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Detect all Android devices (USB + Wireless)
|
|
151
|
+
* @returns {Promise<Array>} Combined list of all detected devices
|
|
152
|
+
*/
|
|
153
|
+
async function discoverAllAndroidDevices() {
|
|
154
|
+
try {
|
|
155
|
+
// Check if ADB is available
|
|
156
|
+
try {
|
|
157
|
+
execSync('which adb', { stdio: 'ignore' });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
console.warn('ADB not found. Please install Android SDK Platform Tools.');
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const [usbDevices, wirelessDevices] = await Promise.all([
|
|
164
|
+
detectUSBDevices(),
|
|
165
|
+
detectWirelessDevices()
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
// Combine and deduplicate by serial
|
|
169
|
+
const allDevices = [...usbDevices, ...wirelessDevices];
|
|
170
|
+
const uniqueDevices = [];
|
|
171
|
+
const seenSerials = new Set();
|
|
172
|
+
|
|
173
|
+
for (const device of allDevices) {
|
|
174
|
+
if (!seenSerials.has(device.serial)) {
|
|
175
|
+
seenSerials.add(device.serial);
|
|
176
|
+
uniqueDevices.push(device);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return uniqueDevices;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Error discovering Android devices:', error.message);
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get device battery level
|
|
189
|
+
* @param {string} serial - Device serial number
|
|
190
|
+
* @returns {Promise<number>} Battery level percentage
|
|
191
|
+
*/
|
|
192
|
+
async function getDeviceBattery(serial) {
|
|
193
|
+
try {
|
|
194
|
+
const { stdout } = await execAsync(`adb -s ${serial} shell dumpsys battery`);
|
|
195
|
+
const levelMatch = stdout.match(/level:\s*(\d+)/);
|
|
196
|
+
return levelMatch ? parseInt(levelMatch[1]) : -1;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
return -1;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Check if UIAutomator2 server is installed
|
|
204
|
+
* @param {string} serial - Device serial number
|
|
205
|
+
* @returns {Promise<boolean>} True if installed
|
|
206
|
+
*/
|
|
207
|
+
async function isUIAutomator2Installed(serial) {
|
|
208
|
+
try {
|
|
209
|
+
const { stdout } = await execAsync(`adb -s ${serial} shell pm list packages`);
|
|
210
|
+
return stdout.includes('io.appium.uiautomator2.server');
|
|
211
|
+
} catch (error) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get list of installed apps (non-system)
|
|
218
|
+
* @param {string} serial - Device serial number
|
|
219
|
+
* @returns {Promise<Array>} List of package names
|
|
220
|
+
*/
|
|
221
|
+
async function getInstalledApps(serial) {
|
|
222
|
+
try {
|
|
223
|
+
const { stdout } = await execAsync(`adb -s ${serial} shell pm list packages -3`);
|
|
224
|
+
return stdout.split('\n')
|
|
225
|
+
.filter(line => line.trim())
|
|
226
|
+
.map(line => line.replace('package:', '').trim());
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Export functions
|
|
233
|
+
module.exports = {
|
|
234
|
+
detectUSBDevices,
|
|
235
|
+
detectWirelessDevices,
|
|
236
|
+
discoverAllAndroidDevices,
|
|
237
|
+
getDeviceBattery,
|
|
238
|
+
isUIAutomator2Installed,
|
|
239
|
+
getInstalledApps
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// CLI mode
|
|
243
|
+
if (require.main === module) {
|
|
244
|
+
(async () => {
|
|
245
|
+
console.log('🤖 Detecting Android devices...\n');
|
|
246
|
+
|
|
247
|
+
const devices = await discoverAllAndroidDevices();
|
|
248
|
+
|
|
249
|
+
if (devices.length === 0) {
|
|
250
|
+
console.log('No Android devices detected.');
|
|
251
|
+
console.log('\nMake sure:');
|
|
252
|
+
console.log(' 1. Device is connected via USB or wirelessly');
|
|
253
|
+
console.log(' 2. USB debugging is enabled');
|
|
254
|
+
console.log(' 3. Device is authorized (check device screen)');
|
|
255
|
+
console.log(' 4. ADB is properly installed');
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
console.log(`Found ${devices.length} device(s):\n`);
|
|
260
|
+
|
|
261
|
+
for (const device of devices) {
|
|
262
|
+
console.log(`📱 ${device.name}`);
|
|
263
|
+
console.log(` Serial: ${device.serial}`);
|
|
264
|
+
console.log(` Android: ${device.androidVersion}`);
|
|
265
|
+
console.log(` Connection: ${device.connectionType.toUpperCase()}`);
|
|
266
|
+
if (device.ip) console.log(` IP: ${device.ip}`);
|
|
267
|
+
|
|
268
|
+
const battery = await getDeviceBattery(device.serial);
|
|
269
|
+
if (battery >= 0) console.log(` Battery: ${battery}%`);
|
|
270
|
+
|
|
271
|
+
const hasUI2 = await isUIAutomator2Installed(device.serial);
|
|
272
|
+
console.log(` UIAutomator2: ${hasUI2 ? '✓ Installed' : '✗ Not installed'}`);
|
|
273
|
+
|
|
274
|
+
console.log('');
|
|
275
|
+
}
|
|
276
|
+
})();
|
|
277
|
+
}
|