@@ -30,18 +30,37 @@ import {
30
30
isFlutterDriverCommand ,
31
31
waitForFlutterServerToBeActive ,
32
32
} from './utils' ;
33
- import { util } from 'appium/support' ;
33
+ import { logger , util } from 'appium/support' ;
34
34
import { androidPortForward , androidRemovePortForward } from './android' ;
35
35
import { iosPortForward , iosRemovePortForward } from './iOS' ;
36
36
import type { PortForwardCallback , PortReleaseCallback } from './types' ;
37
37
import _ from 'lodash' ;
38
38
39
+ import type { RouteMatcher } from '@appium/types' ;
40
+
41
+ const WEBVIEW_NO_PROXY = [
42
+ [ `GET` , new RegExp ( `^/session/[^/]+/appium` ) ] ,
43
+ [ `GET` , new RegExp ( `^/session/[^/]+/context` ) ] ,
44
+ [ `GET` , new RegExp ( `^/session/[^/]+/element/[^/]+/rect` ) ] ,
45
+ [ `GET` , new RegExp ( `^/session/[^/]+/log/types$` ) ] ,
46
+ [ `GET` , new RegExp ( `^/session/[^/]+/orientation` ) ] ,
47
+ [ `POST` , new RegExp ( `^/session/[^/]+/appium` ) ] ,
48
+ [ `POST` , new RegExp ( `^/session/[^/]+/context` ) ] ,
49
+ [ `POST` , new RegExp ( `^/session/[^/]+/log$` ) ] ,
50
+ [ `POST` , new RegExp ( `^/session/[^/]+/orientation` ) ] ,
51
+ [ `POST` , new RegExp ( `^/session/[^/]+/touch/multi/perform` ) ] ,
52
+ [ `POST` , new RegExp ( `^/session/[^/]+/touch/perform` ) ] ,
53
+ ] as import ( '@appium/types' ) . RouteMatcher [ ] ;
54
+
39
55
export class AppiumFlutterDriver extends BaseDriver < FlutterDriverConstraints > {
40
56
// @ts -ignore
41
57
public proxydriver : XCUITestDriver | AndroidUiautomator2Driver ;
42
58
public flutterPort : number | null | undefined ;
43
59
private internalCaps : DriverCaps < FlutterDriverConstraints > | undefined ;
44
60
public proxy : JWProxy | undefined ;
61
+ private proxyWebViewActive : boolean = false ;
62
+ public readonly NATIVE_CONTEXT_NAME : string = `NATIVE_APP` ;
63
+ public currentContext : string = this . NATIVE_CONTEXT_NAME ;
45
64
click = click ;
46
65
findElOrEls = findElOrEls ;
47
66
getText = getText ;
@@ -193,12 +212,44 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
193
212
}
194
213
195
214
async executeCommand ( command : any , ...args : any ) {
196
- if ( isFlutterDriverCommand ( command ) ) {
215
+ if (
216
+ this . currentContext === this . NATIVE_CONTEXT_NAME &&
217
+ isFlutterDriverCommand ( command )
218
+ ) {
197
219
return await super . executeCommand ( command , ...args ) ;
198
220
}
221
+
222
+ this . handleContextSwitch ( command , args ) ;
223
+ logger . default . info (
224
+ `Executing the proxy command: ${ command } with args: ${ args } ` ,
225
+ ) ;
199
226
return await this . proxydriver . executeCommand ( command as string , ...args ) ;
200
227
}
201
228
229
+ private handleContextSwitch ( command : string , args : any [ ] ) : void {
230
+ if ( command === 'setContext' ) {
231
+ const isWebviewContext =
232
+ typeof args [ 0 ] === 'string' && args [ 0 ] . includes ( 'WEBVIEW' ) ;
233
+ if ( typeof args [ 0 ] === 'string' && args [ 0 ] . length > 0 ) {
234
+ this . currentContext = args [ 0 ] ;
235
+ } else {
236
+ logger . default . warn (
237
+ `Attempted to set context to invalid value: ${ args [ 0 ] } . Keeping current context: ${ this . currentContext } ` ,
238
+ ) ;
239
+ }
240
+
241
+ if ( isWebviewContext ) {
242
+ this . proxyWebViewActive = true ;
243
+ } else {
244
+ this . proxyWebViewActive = false ;
245
+ }
246
+ }
247
+ }
248
+
249
+ public getProxyAvoidList ( ) : RouteMatcher [ ] {
250
+ return WEBVIEW_NO_PROXY ;
251
+ }
252
+
202
253
public async createSession (
203
254
...args : any [ ]
204
255
) : Promise < DefaultCreateSessionResult < FlutterDriverConstraints > > {
@@ -382,8 +433,20 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
382
433
return await this . proxydriver . execute ( script , args ) ;
383
434
}
384
435
385
- canProxy ( ) {
386
- return false ;
436
+ public proxyActive ( ) : boolean {
437
+ // In WebView context, all request should go to each driver
438
+ // so that they can handle http request properly.
439
+ // On iOS, WebView context is handled by XCUITest driver while Android is by chromedriver.
440
+ // It means XCUITest driver should keep the XCUITest driver as a proxy,
441
+ // while UIAutomator2 driver should proxy to chromedriver instead of UIA2 proxy.
442
+ return (
443
+ this . proxyWebViewActive &&
444
+ ! ( this . proxydriver instanceof XCUITestDriver )
445
+ ) ;
446
+ }
447
+
448
+ public canProxy ( ) : boolean {
449
+ return this . proxyWebViewActive ;
387
450
}
388
451
389
452
async deleteSession ( ) {
@@ -400,6 +463,8 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
400
463
401
464
async mobilelaunchApp ( appId : string , args : string [ ] , environment : any ) {
402
465
let activateAppResponse ;
466
+ this . currentContext = this . NATIVE_CONTEXT_NAME ;
467
+ this . proxyWebViewActive = false ;
403
468
const launchArgs = _ . assign (
404
469
{ arguments : [ ] as string [ ] } ,
405
470
{ arguments : args , environment } ,
0 commit comments