-
Notifications
You must be signed in to change notification settings - Fork 189
feat: Add WebSocket-based log broadcast support for Android #969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces WebSocket-based log broadcast support for Android (and interface for iOS), enabling real-time logcat monitoring through event-driven handlers. The implementation adds a StringWebSocketClient for handling WebSocket connections, new interfaces for managing WebSocket events, and extends AndroidDriver with logcat broadcast capabilities.
Key Changes:
- New
StringWebSocketClientclass for WebSocket communication with message, error, connection, and disconnection handlers IListensToLogcatMessagesinterface and implementation inAndroidDriverfor logcat streaming- Four generic WebSocket handler interfaces (
ICanHandleMessages,ICanHandleErrors,ICanHandleConnects,ICanHandleDisconnects)
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 26 comments.
Show a summary per file
| File | Description |
|---|---|
src/Appium.Net/Appium/Android/AndroidDriver.cs |
Adds IListensToLogcatMessages implementation with methods to start/stop broadcasts and manage listeners |
src/Appium.Net/Appium/Android/Interfaces/IListensToLogcatMessages.cs |
Defines interface for Android logcat message broadcasting |
src/Appium.Net/Appium/iOS/Interfaces/IListensToSyslogMessages.cs |
Defines parallel interface for iOS syslog message broadcasting |
src/Appium.Net/Appium/WebSocket/StringWebSocketClient.cs |
Core WebSocket client implementation for string message handling |
src/Appium.Net/Appium/WebSocket/ICanHandleMessages.cs |
Generic interface for message handler registration |
src/Appium.Net/Appium/WebSocket/ICanHandleErrors.cs |
Interface for error handler registration |
src/Appium.Net/Appium/WebSocket/ICanHandleConnects.cs |
Interface for connection handler registration |
src/Appium.Net/Appium/WebSocket/ICanHandleDisconnects.cs |
Interface for disconnection handler registration |
test/integration/Android/Session/Logs/LogcatBroadcastTests.cs |
Integration tests covering listener assignment, broadcast lifecycle, and error handling |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Appium.Net/Appium/Android/Interfaces/IListensToLogcatMessages.cs
Outdated
Show resolved
Hide resolved
…source management
… better resource management
…oved encapsulation
…nt modification during enumeration
…n logic for improved error reporting
| /// <param name="port">The port of the host where Appium server is running.</param> | ||
| public void StartLogcatBroadcast(string host, int port) | ||
| { | ||
| ExecuteScript("mobile: startLogsBroadcast", new Dictionary<string, object>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried BiDi instead of this extension command?
https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-startlogsbroadcast
https://github.com/search?q=org%3Aappium%20entryAdded&type=code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KazuCocoa, I attempted several different methods using BiDI, but unfortunately, none of them worked for me.
I'm also experiencing a problem with the BiDi test that you added recently (this might be connected to my issue).
When I attempt to establish a connection, I encounter this error:
❌ FAILED: RunBiDiScript (1358ms)
System.Net.WebSockets.WebSocketException : Unable to connect to the remote server
----> System.Net.Http.HttpRequestException : IPv4 address 0.0.0.0 and IPv6 address ::0 are unspecified addresses that cannot be used as a target address. (Parameter 'hostName') (0.0.0.0:4723)
----> System.ArgumentException : IPv4 address 0.0.0.0 and IPv6 address ::0 are unspecified addresses that cannot be used as a target address. (Parameter 'hostName')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you share the appium server-side log as well?
I'm also experiencing a problem with the BiDi test that you added recently (this might be connected to my issue).
When i ran dotnet test test/integration/Appium.Net.Integration.Tests.csproj -f net8.0 --filter "FullyQualifiedName~Appium.Net.Integration.Tests.Android.BiDiTests" on my local:
[f6166589][AndroidUiautomator2Driver@63b2] Responding to client with driver.createSession() result: {"capabilities":{"platformName":"Android","webSocketUrl":"ws://192.168.5.20:4723/bidi/f6166589-401f-45e0-854a-073385995062","automationName":"UIAutomator2","deviceName":"emulator-5554","platform":"LINUX","webStorageEnabled":false,"takesScreenshot":true,"javascriptEnabled":true,"databaseEnabled":false,"networkConnectionEnabled":true,"locationContextEnabled":false,"warnings":{},"desired":{"platformName":"Android","webSocketUrl":true,"automationName":"UIAutomator2","deviceName":"Android Emulator"},"deviceUDID":"emulator-5554","pixelRatio":"2.625","statBarHeight":63,"viewportRect":{"left":0,"top":63,"width":1080,"height":2337},"deviceApiLevel":32,"platformVersion":"12","deviceManufacturer":"Google","deviceModel":"sdk_gphone64_arm64","deviceScreenSize":"1080x2400","deviceScreenDensity":420}}
[f6166589][HTTP] <-- POST /session 200 20100 ms - 858
[AppiumDriver@12ee] Bidi websocket connection made for session f6166589-401f-45e0-854a-073385995062
[AndroidUiautomator2Driver@63b2] --> BIDI message #1
[AndroidUiautomator2Driver@63b2] Executing bidi command 'session.status' with params {} by passing to driver method 'bidiStatus'
[AndroidUiautomator2Driver@63b2] Responding to bidi command 'session.status' with {"ready":true,"message":"AndroidUiautomator2Driver is ready to accept commands"}
[AndroidUiautomator2Driver@63b2] <-- BIDI message #1
[HTTP] <-- GET /bidi/f6166589-401f-45e0-854a-073385995062 - - ms - -
[AndroidUiautomator2Driver@63b2] BiDi socket connection closed (code 1006, reason: '')
[f6166589][HTTP] --> DELETE /session/f6166589-401f-45e0-854a-073385995062
[f6166589][AndroidUiautomator2Driver@63b2] Calling AppiumDriver.deleteSession() with args: ["f6166589-401f-45e0-854a-073385995062"]
[f6166589][AppiumDriver@12ee] Event 'quitSessionRequested' logged at 1763333223903 (14:47:03 GMT-0800 (Pacific Standard Time))
[f6166589][AppiumDriver@12ee] Removing session f6166589-401f-45e0-854a-073385995062 from our master session list
[f6166589][AppiumDriver@12ee] Closing bidi socket(s) associated with session f6166589-401f-45e0-854a-073385995062
appium was 3.1.1, uia2 driver was 6.1.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KazuCocoa, does BiDi require a specific minimum version of Appium/UIAutomator2 to function?
EDIT: Looks like I'm a bit behind with the versions:
https://gist.github.com/Dor-bl/95d17ca78974d6883da682fba6e49d10
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minimal could be appium 2 and uia2 3.7.10. Old ones might have issues though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at the log.entryAdded hanlding in each driver implementation tonight
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've opened an issue on the Appium server:
appium/appium#21741
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in appium/appium-android-driver#1031, the context property in the source object is optional and should not be relied on. While I agree with @KazuCocoa in that there's no harm in adding it on the driver side, if Selenium is expecting this property, then this issue should be primarily fixed on the Selenium side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nvborisenko, can we apply a fix on the Selenium side, following the above comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I can accept it. But why:
In this case NATIVE_APP is magic string. Is it even required when we want to subscribe?
We subscribe like:
await bidi.Log.OnEntryAddedAsync(Console.WriteLine, new() { Contexts = ["NATIVE_APP"] });According spec contexts property is not required: https://w3c.github.io/webdriver-bidi/#cddl-type-sessionsubscribeparameters. But appium server-side implementation requires it.
…rmance and responsiveness
…mproved performance
…rs test for cleaner code
…oved performance and responsiveness
…ing' for messageSemaphore and removing unnecessary variable declarations
…nce and responsiveness
…y WebSocket implementation
KazuCocoa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left minor comments, otherwise lgtm in best knowledge
|
@KazuCocoa, I've encountered an issue. The tests have suddenly started failing. Perhaps you can identify the problem from the logs? I haven't made any recent code changes that would explain this. .NET Error: Appium logs: |
|
I guess that occurred after deleting the session ? |
|
UIA2 |
It also occurs when I only run one test at a time.. |
|
Hm, interesting. I haven't seen the error case in several log via bidi tests like testing with Ruby, Python and our test cases in driver repos. Do you have test script snippet for it? I can take a look later |
Just the tests from this PR |
|
Ah, I see. I ran this test with |
Could it be some network issues on my end? |
|
Hm. appium 3.1.1 and uia2 6.1.1 in running env. (from appium log)
|
|
If you could see timestamp info as well, we might be able to guess when such a 404 returned |
|
[AppiumDriver@dec7] Appium v3.1.1 creating new AndroidUiautomator2Driver (v6.3.0) session |
|
❌ FAILED: CanStartLogcatBroadcastWithCustomHost (47ms) 2025-11-23 20:56:17:266 - [58e6df27][AppiumDriver@79ef] Event 'newSessionStarted' logged at 1763931377266 (21:56:17 GMT+0100 (Central European Standard Time)) |
|
What happens if you change |
Same issue 😔 |
|
Hm, then I have no idea. |
|
One potential related thing is
Also, it makes sense to double check with another library, such as https://www.npmjs.com/package/wscat if the same url got the same result |
Yea. I also found this address odd. |
|
It might be dotnet-client/src/Appium.Net/Appium/Service/AppiumServiceBuilder.cs Lines 456 to 457 in e94fbe3
The appium server log kicked by this test had below It looks like this test case doesn't kill the running appium server process, so it probably makese sense to make sure the host doesn't have appium process |
Great catch @KazuCocoa .
|
…connection failures
…st to use a fixed IP address

List of changes
This pull request introduces a new capability to the
AndroidDriverclass for handling Android logcat message broadcasts via WebSocket. It adds a dedicated interface for listening to logcat messages and implements a set of methods for starting/stopping broadcasts and managing event handlers. Additionally, supporting interfaces for handling WebSocket messages, connections, disconnections, and errors are introduced.Logcat broadcast and listener functionality
IListensToLogcatMessagesinterface (src/Appium.Net/Appium/Android/Interfaces/IListensToLogcatMessages.cs) to define methods for starting/stopping logcat broadcasts and managing listeners for messages, errors, connections, and disconnections.AndroidDriver, including starting/stopping broadcasts and adding/removing listeners for different WebSocket events. The driver now uses aStringWebSocketClientinstance for handling logcat events. [1] [2]WebSocket event handler interfaces
ICanHandleMessages<T>,ICanHandleConnects,ICanHandleDisconnects, andICanHandleErrorsinterfaces in theWebSocketnamespace to provide standardized APIs for registering and removing event handlers for messages, connections, disconnections, and errors, respectively. [1] [2] [3] [4]Dependency updates
AndroidDriverto import the newOpenQA.Selenium.Appium.WebSocketnamespace for WebSocket support.These changes enable real-time logcat monitoring and event-driven handling in Android automation tests using Appium.
Related to: #255
Types of changes
What types of changes are you proposing/introducing to the .NET client?
Put an
xin the boxes that applyDocumentation
This can be done by navigating to the documentation section on http://appium.io selecting the appropriate command/endpoint, and clicking the 'Edit this doc' link to update the C# example
Integration tests
Details
Please provide more details about changes if necessary. You can provide code samples showing how they work and possible use cases if there are new features. Also, you can create gists with pasted C# code samples or put them here using markdown.
About markdown please read Mastering markdown and Writing on GitHub
Tests Results