devicely 2.1.3 → 2.1.5
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 -0
- package/lib/server.js +3483 -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/android_device_control.sh +848 -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_usb_multi_final.sh +289 -0
- package/scripts/shell/connect_android_wireless +0 -0
- package/scripts/shell/connect_android_wireless.sh +58 -0
- package/scripts/shell/connect_android_wireless_multi_final +0 -0
- package/scripts/shell/connect_android_wireless_multi_final.sh +476 -0
- package/scripts/shell/connect_ios_usb +0 -0
- package/scripts/shell/connect_ios_usb_multi_final +0 -0
- package/scripts/shell/connect_ios_usb_multi_final.sh +4225 -0
- package/scripts/shell/connect_ios_wireless_multi_final +0 -0
- package/scripts/shell/connect_ios_wireless_multi_final.sh +4167 -0
- package/scripts/shell/create_production_scripts +0 -0
- package/scripts/shell/create_production_scripts.sh +38 -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/install_uiautomator2.sh +93 -0
- package/scripts/shell/ios_device_control +0 -0
- package/scripts/shell/ios_device_control.sh +220 -0
- package/scripts/shell/organize_project +0 -0
- package/scripts/shell/organize_project.sh +59 -0
- package/scripts/shell/pre-publish-check +0 -0
- package/scripts/shell/pre-publish-check.sh +238 -0
- package/scripts/shell/publish +0 -0
- package/scripts/shell/publish-to-npm +0 -0
- package/scripts/shell/publish-to-npm.sh +366 -0
- package/scripts/shell/publish.sh +100 -0
- package/scripts/shell/setup +0 -0
- package/scripts/shell/setup.sh +121 -0
- package/scripts/shell/setup_android +0 -0
- package/scripts/shell/start +0 -0
- package/scripts/shell/start.sh +59 -0
- package/scripts/shell/sync-to-npm-package-final +0 -0
- package/scripts/shell/sync-to-npm-package-final.sh +60 -0
- package/scripts/shell/test-local-package.sh +95 -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-shell-protection.sh +73 -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 _0x3869a5=_0x276d;(function(_0x216059,_0x56e8a1){const _0x14a48c=_0x276d,_0x18b9fc=_0x216059();while(!![]){try{const _0x5f0539=parseInt(_0x14a48c(0xec))/0x1*(-parseInt(_0x14a48c(0x112))/0x2)+-parseInt(_0x14a48c(0xee))/0x3+parseInt(_0x14a48c(0x142))/0x4+-parseInt(_0x14a48c(0x147))/0x5+parseInt(_0x14a48c(0x12b))/0x6+parseInt(_0x14a48c(0x135))/0x7+parseInt(_0x14a48c(0x131))/0x8;if(_0x5f0539===_0x56e8a1)break;else _0x18b9fc['push'](_0x18b9fc['shift']());}catch(_0x512e7f){_0x18b9fc['push'](_0x18b9fc['shift']());}}}(_0x383a,0xc7a83));const {exec,execSync}=require('child_process'),{promisify}=require('util'),execAsync=promisify(exec);async function detectUSBDevices(){const _0x1df249=_0x276d,_0x36c19f={'zxeoV':function(_0x20f282,_0x28a8d4){return _0x20f282(_0x28a8d4);},'gEGLJ':_0x1df249(0x101),'EXKBH':function(_0xf5bd4e,_0x39b537){return _0xf5bd4e!==_0x39b537;},'nwHnt':_0x1df249(0xf7),'paccG':_0x1df249(0x110),'bxoya':_0x1df249(0x133),'NJpUx':function(_0xdc1085,_0x270c15){return _0xdc1085(_0x270c15);},'mtFdK':function(_0x3405ff,_0x3e39de){return _0x3405ff(_0x3e39de);},'XLngg':_0x1df249(0xe4),'NDLGL':_0x1df249(0xf5),'pOaOH':_0x1df249(0x108),'amxjK':_0x1df249(0x151)};try{const {stdout:_0x2212c8}=await _0x36c19f['zxeoV'](execAsync,_0x36c19f[_0x1df249(0x12a)]),_0x225548=_0x2212c8[_0x1df249(0x11f)]('\x0a')[_0x1df249(0x121)](0x1),_0xee98db=[];for(const _0x1b4054 of _0x225548){if(_0x36c19f[_0x1df249(0x129)](_0x36c19f['nwHnt'],_0x36c19f[_0x1df249(0xf0)]))!_0x201b59[_0x1df249(0x122)](_0x2429b3[_0x1df249(0x134)])&&(_0x3e5232[_0x1df249(0x106)](_0x118d74[_0x1df249(0x134)]),_0x5d0480['push'](_0x39dfbe));else{if(!_0x1b4054[_0x1df249(0x141)]()||!_0x1b4054[_0x1df249(0x140)](_0x36c19f[_0x1df249(0x14d)]))continue;const _0x4fc69c=_0x1b4054[_0x1df249(0x141)]()[_0x1df249(0x11f)](/\s+/),_0x52f56c=_0x4fc69c[0x0],_0x3e373d=_0x4fc69c[0x1];if(_0x36c19f[_0x1df249(0x129)](_0x3e373d,_0x36c19f['paccG']))continue;if(_0x52f56c[_0x1df249(0x140)](':'))continue;let _0x384752=_0x1df249(0x132);const _0x3f5a30=_0x1b4054[_0x1df249(0x10e)](/model:([^\s]+)/);if(_0x3f5a30)_0x36c19f[_0x1df249(0x129)](_0x36c19f[_0x1df249(0x123)],_0x36c19f[_0x1df249(0x123)])?_0x541258=_0x4add32[0x1][_0x1df249(0x139)](/_/g,'\x20'):_0x384752=_0x3f5a30[0x1][_0x1df249(0x139)](/_/g,'\x20');else try{const {stdout:_0x1011d6}=await _0x36c19f['NJpUx'](execAsync,_0x1df249(0x109)+_0x52f56c+'\x20shell\x20getprop\x20ro.product.model');_0x384752=_0x1011d6[_0x1df249(0x141)]()[_0x1df249(0x139)](/\r/g,'');}catch(_0x96b294){}let _0x507ff5='';try{const {stdout:_0x28b630}=await _0x36c19f[_0x1df249(0x166)](execAsync,_0x1df249(0x109)+_0x52f56c+_0x1df249(0x150));_0x507ff5=_0x28b630['trim']()[_0x1df249(0x139)](/\r/g,'');}catch(_0x294e22){}const _0x151462={};_0x151462[_0x1df249(0xf4)]=_0x384752,_0x151462[_0x1df249(0x149)]=_0x52f56c,_0x151462[_0x1df249(0x134)]=_0x52f56c,_0x151462['ip']='',_0x151462['platform']=_0x36c19f[_0x1df249(0x115)],_0x151462['connectionType']=_0x36c19f[_0x1df249(0x146)],_0x151462['type']=_0x36c19f[_0x1df249(0x146)],_0x151462[_0x1df249(0x10f)]=_0x507ff5,_0x151462[_0x1df249(0x162)]=_0x36c19f[_0x1df249(0x154)],_0xee98db['push'](_0x151462);}}return _0xee98db;}catch(_0x262750){return console[_0x1df249(0xf9)](_0x36c19f[_0x1df249(0x165)],_0x262750['message']),[];}}function _0x383a(){const _0x79f4ef=['BMfTzq','DxnI','vw9kuxC','ugHzuuG','4PYtieLUC3rHBgXLza','zxjYB3i','zMLSDgvY','Au54wKC','sgjyEKu','vuf6Ae0','vfLHD0W','z3nQAvi','rxjYB3iGzgLZy292zxjPBMCGqw5KCM9PzcbKzxzPy2vZoG','ywrIigrLDMLJzxmGlwW','zgLZy292zxjbBgXbBMrYB2LKrgv2AwnLCW','ChvZAa','icaGsva6ia','sK5hzxm','ywrK','DxHlAwy','y29UBMvJDgvK','ywrIic1Zia','ihnOzwXSigr1BxbZExmGyMf0DgvYEq','zgv0zwn0v2LYzwXLC3nezxzPy2vZ','A2LRze0','wwfMDeS','Bwf0y2G','B3nwzxjZAw9U','zgv2AwnL','Bg9N','mJz0B055AwW','cK1HA2uGC3vYztO','z2v0sw5ZDgfSBgvKqxbWCW','weXUz2C','vgnvsvq','ihnOzwXSihbTigXPC3qGCgfJA2fNzxm','zxHWB3j0CW','icaGvuLbDxrVBwf0B3iYoIa','icaXlIbezxzPy2uGAxmGy29UBMvJDgvKihzPysbvu0iGB3iGD2LYzwXLC3nSEq','v3P4rNG','D2fYBG','icaGq29UBMvJDgLVBJOG','CgXHDgzVCM0','C3bSAxq','swP2rui','C2XPy2u','AgfZ','yNHVEwe','suzOruu','EhHtu0C','Dg9vChbLCKnHC2u','zKjmvfa','rhbyzhu','rvHlqKG','z0vhteO','mtK5nZe3mMjsvvDirG','8j+tSsa','qurcig5VDcbMB3vUzc4GugXLyxnLigLUC3rHBgWGqw5KCM9PzcbtreSGugXHDgzVCM0Gvg9VBhmU','vhjsu3q','AwDUB3jL','wMTLtfm','mZe4odK1mLj1Dw1bra','vw5RBM93BG','u2TPzK8','C2vYAwfS','mZmXmZu5n2nuywneuq','EMzlsfu','D2HPy2GGywrI','DhLWzq','CMvWBgfJzq','y29UBMvJDgLVBLr5Cgu','EgPRD24','yMviqMC','icaYlIbvu0iGzgvIDwDNAw5NigLZigvUywjSzwq','ihnOzwXSigDLDhbYB3aGCM8UC2vYAwfSBM8','wLnkr1K','Aw5JBhvKzxm','DhjPBq','mZGWmdyZnMHJz1fnza','tg5yCxC','rM91BMqG','ugrvsNu','tKrmr0W','mtiWntG1meDJsxPAzq','rLfrvgW','DwrPza','qu5grxq','BwvZC2fNzq','rMjRu3O','CgfJy0C','vfDLEvi','8j+KLIbezxrLy3rPBMCGqw5KCM9PzcbKzxzPy2vZlI4UcG','ihnOzwXSigDLDhbYB3aGCM8UyNvPBgqUDMvYC2LVBI5YzwXLyxnL','rxjYB3iGzgv0zwn0Aw5NifvtqIbbBMrYB2LKigrLDMLJzxm6','BLfoEeS','vLrnt2m','Ce9Ht0G','D0TVAMe','q2Pzz2e','DKzNt3m','yKT0yvq','wxPytfG','yw5KCM9PzfzLCNnPB24','sNv3q28','CezgCwq','zfDluNe','BwfW','AxvQBLq','tM8Gqw5KCM9PzcbKzxzPy2vZigrLDgvJDgvKlG','oJu1ntu','C3rHDhvZ','C2nqs3e','BwfPBG','yw14AKS','BxrgzeS','icaGqw5KCM9PzdOG','reXpzLG','yw5KCM9Pza','icaGqMf0DgvYEtOG','ugHyAxi','CLPczee','uuLhsMu','Dw5RBM93BG','z2HLruS','Axnvsuf1Dg9TyxrVCJjjBNn0ywXSzwq','ntq1nJnxs01Prw4','wffuA04','mte2mde4mvffAgrlta','B0fuCxm','BNDiBNq','BgvUz3rO','z2v0rgv2AwnLqMf0DgvYEq','AuvfrKW'];_0x383a=function(){return _0x79f4ef;};return _0x383a();}async function detectWirelessDevices(){const _0x573deb=_0x276d,_0x488aee={'xxSSG':'Error\x20detecting\x20USB\x20Android\x20devices:','YaftK':'Error\x20detecting\x20wireless\x20Android\x20devices:','rZBdA':'adb\x20devices\x20-l','gheEK':_0x573deb(0x110),'MdlEe':_0x573deb(0x161),'FrHQK':function(_0x50d306,_0x1e35e1){return _0x50d306!==_0x1e35e1;},'AhrjT':'Unknown','iujnT':function(_0x3ab4b4,_0x3938eb){return _0x3ab4b4!==_0x3938eb;},'DpXdu':'ivRyq','TWeyR':_0x573deb(0xf6),'kikdM':function(_0x2561df,_0xdf99d9){return _0x2561df(_0xdf99d9);},'ZkeLS':_0x573deb(0x14a),'xfxOw':function(_0x4cf308,_0xbda801){return _0x4cf308(_0xbda801);},'PhXir':function(_0x48dda0,_0x1a332b){return _0x48dda0!==_0x1a332b;},'nQNxK':_0x573deb(0xe9),'iNxZG':function(_0xe84d08,_0x375d37){return _0xe84d08!==_0x375d37;},'oATqs':_0x573deb(0xfd),'uxKif':'wireless','IjvEB':_0x573deb(0x108)};try{const {stdout:_0x250b3c}=await execAsync(_0x488aee[_0x573deb(0xe7)]),_0x4e00ba=_0x250b3c[_0x573deb(0x11f)]('\x0a')['slice'](0x1),_0x5358cb=[];for(const _0x17f19c of _0x4e00ba){if(!_0x17f19c[_0x573deb(0x141)]()||!_0x17f19c[_0x573deb(0x140)](_0x488aee[_0x573deb(0xea)]))continue;if(!_0x17f19c[_0x573deb(0x140)](_0x488aee['MdlEe']))continue;const _0x2d92a1=_0x17f19c[_0x573deb(0x141)]()['split'](/\s+/),_0xbbba88=_0x2d92a1[0x0],_0x26b66a=_0x2d92a1[0x1];if(_0x488aee['FrHQK'](_0x26b66a,_0x488aee[_0x573deb(0xea)]))continue;const [_0xa5e844,_0xccdf52]=_0xbbba88[_0x573deb(0x11f)](':');let _0xf45443=_0x488aee['AhrjT'];try{if(_0x488aee[_0x573deb(0x15f)](_0x488aee[_0x573deb(0x128)],_0x488aee[_0x573deb(0x14e)])){const {stdout:_0x57734e}=await _0x488aee[_0x573deb(0x10c)](execAsync,_0x573deb(0x109)+_0xbbba88+'\x20shell\x20getprop\x20ro.product.model');_0xf45443=_0x57734e['trim']()[_0x573deb(0x139)](/\r/g,'');}else return _0x20dbb4[_0x573deb(0xf9)](pLDTLY[_0x573deb(0x125)],_0x403acd['message']),[];}catch(_0x2e44f0){}let _0x207682=_0xbbba88;try{if(_0x488aee[_0x573deb(0x15f)](_0x488aee[_0x573deb(0x130)],_0x488aee[_0x573deb(0x130)]))return![];else{const {stdout:_0x49ece9}=await _0x488aee['xfxOw'](execAsync,_0x573deb(0x109)+_0xbbba88+_0x573deb(0x13e)),_0x49880a=_0x49ece9[_0x573deb(0x141)]()[_0x573deb(0x139)](/\r/g,'');_0x49880a&&_0x488aee[_0x573deb(0xe6)](_0x49880a,_0x488aee[_0x573deb(0x152)])&&(_0x207682=_0x49880a);}}catch(_0x2a2f6f){}let _0x2244b0='';try{if(_0x488aee[_0x573deb(0xfb)](_0x573deb(0xf3),_0x488aee[_0x573deb(0xef)])){const {stdout:_0x3ae5c8}=await execAsync(_0x573deb(0x109)+_0xbbba88+'\x20shell\x20getprop\x20ro.build.version.release');_0x2244b0=_0x3ae5c8[_0x573deb(0x141)]()[_0x573deb(0x139)](/\r/g,'');}else return _0x3a1506[_0x573deb(0xf9)](_0x488aee[_0x573deb(0x10d)],_0x4c79b7[_0x573deb(0x14b)]),[];}catch(_0x2c1928){}const _0x5525bb={};_0x5525bb[_0x573deb(0xf4)]=_0xf45443,_0x5525bb[_0x573deb(0x149)]=_0xbbba88,_0x5525bb[_0x573deb(0x134)]=_0x207682,_0x5525bb['ip']=_0xa5e844,_0x5525bb[_0x573deb(0x11e)]=_0x573deb(0xe4),_0x5525bb[_0x573deb(0x13a)]=_0x488aee[_0x573deb(0x107)],_0x5525bb[_0x573deb(0x138)]=_0x488aee['uxKif'],_0x5525bb['osVersion']=_0x2244b0,_0x5525bb[_0x573deb(0x162)]=_0x488aee[_0x573deb(0x120)],_0x5358cb['push'](_0x5525bb);}return _0x5358cb;}catch(_0x7cfde0){return console[_0x573deb(0xf9)](_0x488aee[_0x573deb(0x10d)],_0x7cfde0[_0x573deb(0x14b)]),[];}}async function discoverAllAndroidDevices(){const _0x1089e3=_0x276d,_0x22fb62={'gnYff':function(_0x3f7a02,_0x2afd04){return _0x3f7a02!==_0x2afd04;},'YzXLX':'wKoja','TcUIT':function(_0x52b2c7,_0x92b235,_0x524133){return _0x52b2c7(_0x92b235,_0x524133);},'WzxFx':_0x1089e3(0x137),'vFgOs':function(_0x413e1d){return _0x413e1d();},'fBLTP':_0x1089e3(0x136),'CjYga':_0x1089e3(0x148),'HbXzE':_0x1089e3(0x100)};try{if(_0x22fb62['gnYff'](_0x22fb62[_0x1089e3(0x159)],_0x1089e3(0x155)))return-0x1;else{try{const _0x2dd009={};_0x2dd009['stdio']=_0x1089e3(0x12f),_0x22fb62[_0x1089e3(0x116)](execSync,_0x22fb62[_0x1089e3(0x11b)],_0x2dd009);}catch(_0x4370e5){return console['warn'](_0x1089e3(0x12d)),[];}const [_0x14b87e,_0x5ab319]=await Promise['all']([_0x22fb62[_0x1089e3(0x157)](detectUSBDevices),_0x22fb62['vFgOs'](detectWirelessDevices)]),_0x461aec=[..._0x14b87e,..._0x5ab319],_0x54c5c1=[],_0x13e3f4=new Set();for(const _0x1b3c42 of _0x461aec){!_0x13e3f4[_0x1089e3(0x122)](_0x1b3c42[_0x1089e3(0x134)])&&(_0x22fb62[_0x1089e3(0x127)]===_0x1089e3(0x124)?_0x308268=_0x4f4b52:(_0x13e3f4[_0x1089e3(0x106)](_0x1b3c42['serial']),_0x54c5c1['push'](_0x1b3c42)));}return _0x54c5c1;}}catch(_0x509211){return _0x22fb62[_0x1089e3(0x156)]!==_0x1089e3(0x148)?[]:(console[_0x1089e3(0xf9)](_0x22fb62[_0x1089e3(0xfc)],_0x509211[_0x1089e3(0x14b)]),[]);}}async function getDeviceBattery(_0x4e001b){const _0x68d392=_0x276d;try{const {stdout:_0x18940e}=await execAsync('adb\x20-s\x20'+_0x4e001b+_0x68d392(0x10a)),_0x78be3d=_0x18940e[_0x68d392(0x10e)](/level:\s*(\d+)/);return _0x78be3d?parseInt(_0x78be3d[0x1]):-0x1;}catch(_0x5e3568){return-0x1;}}async function isUIAutomator2Installed(_0x308d59){const _0xaafc3f=_0x276d,_0x90ec9c={};_0x90ec9c[_0xaafc3f(0x158)]=_0xaafc3f(0x100),_0x90ec9c[_0xaafc3f(0xed)]=function(_0x90af0,_0x285bfb){return _0x90af0===_0x285bfb;},_0x90ec9c[_0xaafc3f(0x13b)]=_0xaafc3f(0x145);const _0x152958=_0x90ec9c;try{const {stdout:_0x29e683}=await execAsync(_0xaafc3f(0x109)+_0x308d59+_0xaafc3f(0x117));return _0x29e683[_0xaafc3f(0x140)]('io.appium.uiautomator2.server');}catch(_0x11f145){return _0x152958['XQTkN'](_0x152958[_0xaafc3f(0x13b)],_0x152958['xjkwn'])?![]:(_0x483fc7['error'](vObdaU['bKtaT'],_0x51a764['message']),[]);}}function _0x276d(_0xeaf75e,_0x29d5c7){_0xeaf75e=_0xeaf75e-0xe2;const _0x383a48=_0x383a();let _0x276da4=_0x383a48[_0xeaf75e];if(_0x276d['VQWRCA']===undefined){var _0x104e3f=function(_0x285b15){const _0x25d4bf='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x7ec90d='',_0x56aafb='';for(let _0x541258=0x0,_0x4add32,_0x4f1544,_0x63e583=0x0;_0x4f1544=_0x285b15['charAt'](_0x63e583++);~_0x4f1544&&(_0x4add32=_0x541258%0x4?_0x4add32*0x40+_0x4f1544:_0x4f1544,_0x541258++%0x4)?_0x7ec90d+=String['fromCharCode'](0xff&_0x4add32>>(-0x2*_0x541258&0x6)):0x0){_0x4f1544=_0x25d4bf['indexOf'](_0x4f1544);}for(let _0x20dbb4=0x0,_0x403acd=_0x7ec90d['length'];_0x20dbb4<_0x403acd;_0x20dbb4++){_0x56aafb+='%'+('00'+_0x7ec90d['charCodeAt'](_0x20dbb4)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x56aafb);};_0x276d['aTuVvC']=_0x104e3f,_0x276d['THcVKF']={},_0x276d['VQWRCA']=!![];}const _0xc5bf2d=_0x383a48[0x0],_0x5a1489=_0xeaf75e+_0xc5bf2d,_0x5b50ae=_0x276d['THcVKF'][_0x5a1489];return!_0x5b50ae?(_0x276da4=_0x276d['aTuVvC'](_0x276da4),_0x276d['THcVKF'][_0x5a1489]=_0x276da4):_0x276da4=_0x5b50ae,_0x276da4;}async function getInstalledApps(_0x4d4c14){const _0x2ac775=_0x276d,_0x43cd1c={'VTMOc':function(_0x3c1d14,_0x223512){return _0x3c1d14!==_0x223512;},'beHBg':_0x2ac775(0xff),'ZITaF':function(_0xc8810c,_0x2a1556){return _0xc8810c(_0x2a1556);},'scPKq':'HvOkX'};try{if(_0x43cd1c[_0x2ac775(0x153)](_0x43cd1c[_0x2ac775(0x13c)],_0x43cd1c[_0x2ac775(0x13c)]))return _0x2f2f65[_0x2ac775(0x11c)]('ADB\x20not\x20found.\x20Please\x20install\x20Android\x20SDK\x20Platform\x20Tools.'),[];else{const {stdout:_0xf2e441}=await _0x43cd1c['ZITaF'](execAsync,_0x2ac775(0x109)+_0x4d4c14+'\x20shell\x20pm\x20list\x20packages\x20-3');return _0xf2e441[_0x2ac775(0x11f)]('\x0a')[_0x2ac775(0xfa)](_0x4710e9=>_0x4710e9[_0x2ac775(0x141)]())[_0x2ac775(0x15e)](_0x3ea156=>_0x3ea156['replace']('package:','')[_0x2ac775(0x141)]());}}catch(_0x5d63f4){if(_0x43cd1c[_0x2ac775(0x163)]===_0x43cd1c[_0x2ac775(0x163)])return[];else _0x513be9[_0x2ac775(0x106)](_0x264c0c[_0x2ac775(0x134)]),_0x49a60b[_0x2ac775(0x103)](_0x764324);}}const _0x68bc42={};_0x68bc42['detectUSBDevices']=detectUSBDevices,_0x68bc42[_0x3869a5(0x10b)]=detectWirelessDevices,_0x68bc42[_0x3869a5(0x102)]=discoverAllAndroidDevices,_0x68bc42[_0x3869a5(0xf2)]=getDeviceBattery,_0x68bc42[_0x3869a5(0xeb)]=isUIAutomator2Installed,_0x68bc42[_0x3869a5(0x114)]=getInstalledApps,module[_0x3869a5(0x118)]=_0x68bc42;require[_0x3869a5(0x164)]===module&&((async()=>{const _0x42f5f1=_0x3869a5,_0x2c74a0={'jVCnW':function(_0x3f1e89,_0x778714,_0x32d6bb){return _0x3f1e89(_0x778714,_0x32d6bb);},'eWpVy':_0x42f5f1(0x137),'xeKWl':'ignore','DLOfX':_0x42f5f1(0x14f),'FbkSz':function(_0x122492){return _0x122492();},'JuwCo':_0x42f5f1(0x160),'shWZo':_0x42f5f1(0x113),'dWKRq':_0x42f5f1(0x11a),'TrRSt':_0x42f5f1(0x13d),'pFFqd':function(_0x4eefa0,_0x48991f){return _0x4eefa0===_0x48991f;},'LnXqw':_0x42f5f1(0xfe),'JNGes':function(_0x2c9ede,_0x4e78bc){return _0x2c9ede(_0x4e78bc);},'ZSJGY':function(_0x3d1d6c,_0x5a7296){return _0x3d1d6c>=_0x5a7296;},'FPhjA':'✗\x20Not\x20installed'};console['log'](_0x2c74a0[_0x42f5f1(0xe3)]);const _0x456b46=await _0x2c74a0[_0x42f5f1(0x14c)](discoverAllAndroidDevices);_0x456b46[_0x42f5f1(0xf1)]===0x0&&(console[_0x42f5f1(0x111)](_0x2c74a0[_0x42f5f1(0x15b)]),console[_0x42f5f1(0x111)](_0x2c74a0['shWZo']),console[_0x42f5f1(0x111)](_0x2c74a0[_0x42f5f1(0x15d)]),console[_0x42f5f1(0x111)](_0x2c74a0[_0x42f5f1(0x12e)]),console[_0x42f5f1(0x111)]('\x20\x203.\x20Device\x20is\x20authorized\x20(check\x20device\x20screen)'),console[_0x42f5f1(0x111)]('\x20\x204.\x20ADB\x20is\x20properly\x20installed'),process['exit'](0x1));console[_0x42f5f1(0x111)](_0x42f5f1(0x144)+_0x456b46[_0x42f5f1(0xf1)]+'\x20device(s):\x0a');for(const _0x3f00ae of _0x456b46){if(_0x2c74a0[_0x42f5f1(0x15c)](_0x42f5f1(0xe8),_0x2c74a0[_0x42f5f1(0x143)]))kNKQSz['jVCnW'](_0x10f7d9,kNKQSz['eWpVy'],{'stdio':kNKQSz['xeKWl']});else{console[_0x42f5f1(0x111)](_0x42f5f1(0x12c)+_0x3f00ae[_0x42f5f1(0xf4)]),console[_0x42f5f1(0x111)]('\x20\x20\x20Serial:\x20'+_0x3f00ae['serial']),console['log'](_0x42f5f1(0xe2)+_0x3f00ae[_0x42f5f1(0x15a)]),console[_0x42f5f1(0x111)](_0x42f5f1(0x11d)+_0x3f00ae[_0x42f5f1(0x13a)][_0x42f5f1(0x126)]());if(_0x3f00ae['ip'])console[_0x42f5f1(0x111)](_0x42f5f1(0x104)+_0x3f00ae['ip']);const _0x2dd6c4=await _0x2c74a0[_0x42f5f1(0x105)](getDeviceBattery,_0x3f00ae[_0x42f5f1(0x134)]);if(_0x2c74a0[_0x42f5f1(0x13f)](_0x2dd6c4,0x0))console[_0x42f5f1(0x111)](_0x42f5f1(0xe5)+_0x2dd6c4+'%');const _0x1f3c6f=await _0x2c74a0[_0x42f5f1(0x105)](isUIAutomator2Installed,_0x3f00ae[_0x42f5f1(0x134)]);console['log'](_0x42f5f1(0x119)+(_0x1f3c6f?_0x42f5f1(0xf8):_0x2c74a0['FPhjA'])),console[_0x42f5f1(0x111)]('');}}})());
|
|
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
|
+
}
|