@@ -30,18 +30,37 @@ import {
3030 isFlutterDriverCommand ,
3131 waitForFlutterServerToBeActive ,
3232} from './utils' ;
33- import { util } from 'appium/support' ;
33+ import { logger , util } from 'appium/support' ;
3434import { androidPortForward , androidRemovePortForward } from './android' ;
3535import { iosPortForward , iosRemovePortForward } from './iOS' ;
3636import type { PortForwardCallback , PortReleaseCallback } from './types' ;
3737import _ from 'lodash' ;
3838
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+
3955export class AppiumFlutterDriver extends BaseDriver < FlutterDriverConstraints > {
4056 // @ts -ignore
4157 public proxydriver : XCUITestDriver | AndroidUiautomator2Driver ;
4258 public flutterPort : number | null | undefined ;
4359 private internalCaps : DriverCaps < FlutterDriverConstraints > | undefined ;
4460 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 ;
4564 click = click ;
4665 findElOrEls = findElOrEls ;
4766 getText = getText ;
@@ -193,12 +212,44 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
193212 }
194213
195214 async executeCommand ( command : any , ...args : any ) {
196- if ( isFlutterDriverCommand ( command ) ) {
215+ if (
216+ this . currentContext === this . NATIVE_CONTEXT_NAME &&
217+ isFlutterDriverCommand ( command )
218+ ) {
197219 return await super . executeCommand ( command , ...args ) ;
198220 }
221+
222+ this . handleContextSwitch ( command , args ) ;
223+ logger . default . info (
224+ `Executing the proxy command: ${ command } with args: ${ args } ` ,
225+ ) ;
199226 return await this . proxydriver . executeCommand ( command as string , ...args ) ;
200227 }
201228
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+
202253 public async createSession (
203254 ...args : any [ ]
204255 ) : Promise < DefaultCreateSessionResult < FlutterDriverConstraints > > {
@@ -382,8 +433,20 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
382433 return await this . proxydriver . execute ( script , args ) ;
383434 }
384435
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 ;
387450 }
388451
389452 async deleteSession ( ) {
@@ -400,6 +463,8 @@ export class AppiumFlutterDriver extends BaseDriver<FlutterDriverConstraints> {
400463
401464 async mobilelaunchApp ( appId : string , args : string [ ] , environment : any ) {
402465 let activateAppResponse ;
466+ this . currentContext = this . NATIVE_CONTEXT_NAME ;
467+ this . proxyWebViewActive = false ;
403468 const launchArgs = _ . assign (
404469 { arguments : [ ] as string [ ] } ,
405470 { arguments : args , environment } ,
0 commit comments