@@ -12,7 +12,7 @@ async function adbExecWithDevice(adb: ADBInstance, udid: UDID, args: string[]):
1212export async function getDeviceProperty (
1313 adb : ADBInstance ,
1414 udid : UDID ,
15- prop : string
15+ prop : string ,
1616) : Promise < string | undefined > {
1717 try {
1818 return await adbExecWithDevice ( adb , udid , [ 'shell' , 'getprop' , prop ] ) ;
@@ -44,24 +44,33 @@ export async function configureWifiProxy(
4444 adb : ADBInstance ,
4545 udid : UDID ,
4646 isRealDevice : boolean ,
47- proxyConfig ?: ProxyOptions
47+ proxyConfig ?: ProxyOptions ,
4848) : Promise < string > {
49- logger . info ( `configureWifiProxy(udid=${ udid } , isRealDevice=${ isRealDevice } , proxyConfig=${ JSON . stringify ( proxyConfig ) } )` )
49+ logger . info (
50+ `configureWifiProxy(udid=${ udid } , isRealDevice=${ isRealDevice } , proxyConfig=${ JSON . stringify ( proxyConfig ) } )` ,
51+ ) ;
5052 try {
51- const isConfigValid = proxyConfig
52- && proxyConfig . ip
53- && proxyConfig . ip . trim ( ) . length > 0
54- && ! isNaN ( proxyConfig . port )
55- && proxyConfig . port > 0 ;
53+ const isConfigValid =
54+ proxyConfig &&
55+ proxyConfig . ip &&
56+ proxyConfig . ip . trim ( ) . length > 0 &&
57+ ! isNaN ( proxyConfig . port ) &&
58+ proxyConfig . port > 0 ;
5659
5760 if ( ! isConfigValid ) {
58- logger . warn ( `Invalid proxy config: ${ JSON . stringify ( proxyConfig ) } . Proxy will be disabled for udid ${ udid } .` ) ;
61+ logger . warn (
62+ `Invalid proxy config: ${ JSON . stringify ( proxyConfig ) } . Proxy will be disabled for udid ${ udid } .` ,
63+ ) ;
5964 }
6065
6166 const host = isConfigValid ? `${ proxyConfig . ip } :${ proxyConfig . port } ` : ':0' ;
6267
6368 if ( isRealDevice && isConfigValid ) {
64- await adbExecWithDevice ( adb , udid , [ 'reverse' , `tcp:${ proxyConfig . port } ` , `tcp:${ proxyConfig . port } ` ] ) ;
69+ await adbExecWithDevice ( adb , udid , [
70+ 'reverse' ,
71+ `tcp:${ proxyConfig . port } ` ,
72+ `tcp:${ proxyConfig . port } ` ,
73+ ] ) ;
6574 }
6675
6776 return await adbExecWithDevice ( adb , udid , [
@@ -83,16 +92,16 @@ export async function configureWifiProxy(
8392 *
8493 * @param adb - The ADB instance established by Appium.
8594 * @param udid - The Unique Device Identifier (UDID) of the Android device or emulator.
86- * @returns A Promise resolving to an object containing the IP and port of the proxy
87- * ({ ip: string, port: number }), or undefined if no proxy is configured,
95+ * @returns A Promise resolving to an object containing the IP and port of the proxy
96+ * ({ ip: string, port: number }), or undefined if no proxy is configured,
8897 * or if the configuration is invalid (e.g., malformed port).
8998 * @throws {Error } Throws an error if the ADB command execution fails.
9099 */
91100export async function getCurrentWifiProxyConfig (
92101 adb : ADBInstance ,
93- udid : UDID
102+ udid : UDID ,
94103) : Promise < ProxyOptions | undefined > {
95- logger . info ( `getCurrentWifiProxyConfig(udid=${ udid } )` ) ;
104+ logger . info ( `getCurrentWifiProxyConfig(udid=${ udid } )` ) ;
96105 try {
97106 // Execute ADB command to get the current global HTTP proxy setting
98107 const proxySettingsCommandResult = await adbExecWithDevice ( adb , udid , [
@@ -104,14 +113,20 @@ export async function getCurrentWifiProxyConfig(
104113 ] ) ;
105114
106115 // ADB returns ":0" or "null" when the proxy is disabled.
107- if ( ! proxySettingsCommandResult || proxySettingsCommandResult === ':0' || proxySettingsCommandResult === 'null' ) {
116+ if (
117+ ! proxySettingsCommandResult ||
118+ proxySettingsCommandResult === ':0' ||
119+ proxySettingsCommandResult === 'null'
120+ ) {
108121 logger . info ( `No active proxy for udid ${ udid } .` ) ;
109122 return undefined ;
110- }
123+ }
111124
112125 // Ensure the format is IP:PORT (must contain at least one ':').
113126 if ( ! proxySettingsCommandResult . includes ( ':' ) ) {
114- logger . warn ( `Invalid proxy settings format detected for udid ${ udid } : '${ proxySettingsCommandResult } '.` ) ;
127+ logger . warn (
128+ `Invalid proxy settings format detected for udid ${ udid } : '${ proxySettingsCommandResult } '.` ,
129+ ) ;
115130 return undefined ;
116131 }
117132
@@ -122,45 +137,62 @@ export async function getCurrentWifiProxyConfig(
122137 // Validate IP and port values.
123138 // IP should not be empty after trimming, and port must be a valid number greater than 0.
124139 if ( ! ip . trim ( ) || isNaN ( port ) || port <= 0 ) {
125- logger . warn ( `Invalid proxy settings detected for udid ${ udid } : (ip=${ ip } , port=${ port } )` ) ;
126- return undefined ;
140+ logger . warn ( `Invalid proxy settings detected for udid ${ udid } : (ip=${ ip } , port=${ port } )` ) ;
141+ return undefined ;
127142 }
128143
129144 const proxyOptions : ProxyOptions = {
130- ip : ip . trim ( ) ,
131- port : port ,
145+ ip : ip . trim ( ) ,
146+ port : port ,
132147 } as ProxyOptions ;
133148
134149 logger . info ( `Found active proxy for udid ${ udid } : ${ JSON . stringify ( proxyOptions ) } ` ) ;
135150 return proxyOptions ;
136-
137151 } catch ( error : any ) {
138152 throw new Error ( `Error getting wifi proxy settings for ${ udid } : ${ error . message } ` ) ;
139153 }
140154}
141155
142156/**
143157 * Retrieves the list of all active ADB reverse port forwardings for a specific device.
144- * * This method executes 'adb reverse --list' to identify which device ports are
145- * currently bridged to the host machine. It is essential for diagnosing
158+ * * This method executes 'adb reverse --list' to identify which device ports are
159+ * currently bridged to the host machine. It is essential for diagnosing
146160 * connectivity between the mobile device and local proxy servers.
147161 *
148162 * @param adb - The ADB instance provided by the Appium driver.
149163 * @param udid - The Unique Device Identifier (UDID) of the target Android device.
150164 * @returns A Promise resolving to the raw string output of the 'adb reverse --list' command.
151165 * @throws {Error } If the command fails to execute or the device is unreachable.
152166 */
153- export async function getAdbReverseTunnels (
167+ export async function getAdbReverseTunnels ( adb : ADBInstance , udid : UDID ) : Promise < string > {
168+ try {
169+ return await adbExecWithDevice ( adb , udid , [ 'reverse' , '--list' ] ) ;
170+ } catch ( error : any ) {
171+ throw new Error ( `Failed to list active reverse tunnels for device ${ udid } : ${ error . message } ` ) ;
172+ }
173+ }
174+
175+ /**
176+ * Removes a specific reverse tunnel established on the device for the given port.
177+ * * Note: While the reverse tunnel is automatically created within the
178+ * `configureWifiProxy` method (for real devices), ADB reverse tunnels are
179+ * not automatically closed when a test session ends.
180+ * * Since `configureWifiProxy` establishes a bridge between the device and the
181+ * proxy host on a specific port, failing to clear it can lead to "Port already in use"
182+ * errors in subsequent sessions.
183+ * * @param adb - The ADB instance
184+ * @param udid - The device unique identifier
185+ * @param port - The specific port to remove from reverse tunnels
186+ */
187+ export async function removeReverseTunnel (
154188 adb : ADBInstance ,
155- udid : UDID
189+ udid : UDID ,
190+ port : number | string ,
156191) : Promise < string > {
157192 try {
158- return await adbExecWithDevice ( adb , udid , [
159- 'reverse' ,
160- '--list' ,
161- ] ) ;
162- } catch ( error : any ) {
163- throw new Error ( `Failed to list active reverse tunnels for device ${ udid } : ${ error . message } ` ) ;
193+ return await adbExecWithDevice ( adb , udid , [ 'reverse' , '--remove' , `tcp:${ port } ` ] ) ;
194+ } catch ( error : any ) {
195+ throw new Error ( `Error removing reverse tunnel for port ${ port } on ${ udid } : ${ error . message } ` ) ;
164196 }
165197}
166198
0 commit comments