mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
feat(sidecar): add IosDriverBackend using Maestro IOSDriver + env pass-through
This commit is contained in:
1 parent
bff3a49324
commit
9338b240b2
2 files changed
+76
-4
No files matched your search
@@ -26,6 +26,8 @@ val maestroVersion = "1.40.0"
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("dev.mobile:maestro-client:$maestroVersion")
|
implementation("dev.mobile:maestro-client:$maestroVersion")
|
||||||
implementation("dev.mobile:maestro-utils:$maestroVersion")
|
implementation("dev.mobile:maestro-utils:$maestroVersion")
|
||||||
|
implementation("dev.mobile:maestro-ios:$maestroVersion")
|
||||||
|
implementation("dev.mobile:maestro-ios-driver:$maestroVersion")
|
||||||
|
|
||||||
implementation("io.grpc:grpc-netty-shaded:$grpcVersion")
|
implementation("io.grpc:grpc-netty-shaded:$grpcVersion")
|
||||||
implementation("io.grpc:grpc-protobuf:$grpcVersion")
|
implementation("io.grpc:grpc-protobuf:$grpcVersion")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package dev.sanderling.sidecar
|
package dev.sanderling.sidecar
|
||||||
|
|
||||||
interface DriverBackend {
|
interface DriverBackend {
|
||||||
fun launch(bundleId: String, clearState: Boolean)
|
fun launch(bundleId: String, clearState: Boolean, env: Map<String, String> = emptyMap())
|
||||||
fun terminate(bundleId: String)
|
fun terminate(bundleId: String)
|
||||||
fun tap(x: Int, y: Int)
|
fun tap(x: Int, y: Int)
|
||||||
fun tapSelector(selector: String)
|
fun tapSelector(selector: String)
|
||||||
@@ -131,7 +131,7 @@ class StubDriverBackend(private val platform: String) : DriverBackend {
|
|||||||
@Volatile var lastInputText: String? = null
|
@Volatile var lastInputText: String? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override fun launch(bundleId: String, clearState: Boolean) {
|
override fun launch(bundleId: String, clearState: Boolean, env: Map<String, String>) {
|
||||||
launchCount++
|
launchCount++
|
||||||
lastBundleId = bundleId
|
lastBundleId = bundleId
|
||||||
if (clearState) {
|
if (clearState) {
|
||||||
@@ -386,9 +386,9 @@ class MaestroDriverBackend(private val serial: String?) : DriverBackend {
|
|||||||
driver.open()
|
driver.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launch(bundleId: String, clearState: Boolean) {
|
override fun launch(bundleId: String, clearState: Boolean, env: Map<String, String>) {
|
||||||
if (clearState) driver.clearAppState(bundleId)
|
if (clearState) driver.clearAppState(bundleId)
|
||||||
driver.launchApp(bundleId, emptyMap(), java.util.UUID.randomUUID())
|
driver.launchApp(bundleId, env, java.util.UUID.randomUUID())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun terminate(bundleId: String) = driver.stopApp(bundleId)
|
override fun terminate(bundleId: String) = driver.stopApp(bundleId)
|
||||||
@@ -486,6 +486,76 @@ private fun pngHeight(bytes: ByteArray): Int {
|
|||||||
(bytes[22].toInt() and 0xFF shl 8) or (bytes[23].toInt() and 0xFF)
|
(bytes[22].toInt() and 0xFF shl 8) or (bytes[23].toInt() and 0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IosDriverBackend(private val udid: String) : DriverBackend {
|
||||||
|
private val driver: maestro.drivers.IOSDriver
|
||||||
|
|
||||||
|
init {
|
||||||
|
val httpClient = xcuitest.api.OkHttpClientInstance.get()
|
||||||
|
val metrics = maestro.utils.NoOpMetrics()
|
||||||
|
val installer = xcuitest.installer.LocalXCTestInstaller(
|
||||||
|
udid,
|
||||||
|
"localhost",
|
||||||
|
false,
|
||||||
|
9100,
|
||||||
|
metrics,
|
||||||
|
httpClient,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
val xcTestDriverClient = xcuitest.XCTestDriverClient(installer, httpClient, false)
|
||||||
|
val device = ios.xctest.XCTestIOSDevice(udid, xcTestDriverClient) { emptySet() }
|
||||||
|
driver = maestro.drivers.IOSDriver(device, maestro.utils.NoopInsights, metrics)
|
||||||
|
driver.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun launch(bundleId: String, clearState: Boolean, env: Map<String, String>) {
|
||||||
|
if (clearState) driver.clearAppState(bundleId)
|
||||||
|
driver.launchApp(bundleId, env, java.util.UUID.randomUUID())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun terminate(bundleId: String) = driver.stopApp(bundleId)
|
||||||
|
|
||||||
|
override fun tap(x: Int, y: Int) = driver.tap(maestro.Point(x, y))
|
||||||
|
|
||||||
|
override fun tapSelector(selector: String) {
|
||||||
|
val root = driver.contentDescriptor(false)
|
||||||
|
val bounds = findBoundsBySelector(root, selector) ?: return
|
||||||
|
driver.tap(maestro.Point((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inputText(text: String) = driver.inputText(text)
|
||||||
|
|
||||||
|
override fun swipe(fromX: Int, fromY: Int, toX: Int, toY: Int, durationMillis: Long) =
|
||||||
|
driver.swipe(maestro.Point(fromX, fromY), maestro.Point(toX, toY), maxOf(durationMillis, 250L))
|
||||||
|
|
||||||
|
override fun pressKey(key: String) {
|
||||||
|
StubDriverBackend.KEY_MAP[key]?.let { keyCode ->
|
||||||
|
keyCodeToMaestro(keyCode)?.let { driver.pressKey(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun screenshot(): Triple<ByteArray, Int, Int> {
|
||||||
|
val buf = okio.Buffer()
|
||||||
|
driver.takeScreenshot(buf, false)
|
||||||
|
val bytes = buf.readByteArray()
|
||||||
|
return Triple(bytes, pngWidth(bytes), pngHeight(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hierarchy(): String =
|
||||||
|
com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()
|
||||||
|
.writeValueAsString(driver.contentDescriptor(false))
|
||||||
|
|
||||||
|
override fun recentLogs(sinceUnixMillis: Long, minLevel: String): List<LogLine> = emptyList()
|
||||||
|
|
||||||
|
override fun waitForIdle(durationMillis: Long) {
|
||||||
|
driver.waitForAppToSettle(null, null, durationMillis.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun healthy() = runCatching { driver.contentDescriptor(false); true }.getOrElse { false }
|
||||||
|
|
||||||
|
override fun metrics(bundleId: String) = MetricsSample(0.0, 0L, 0L)
|
||||||
|
}
|
||||||
|
|
||||||
private fun keyCodeToMaestro(adbKeyCode: String): maestro.KeyCode? {
|
private fun keyCodeToMaestro(adbKeyCode: String): maestro.KeyCode? {
|
||||||
return when (adbKeyCode) {
|
return when (adbKeyCode) {
|
||||||
"KEYCODE_BACK" -> maestro.KeyCode.BACK
|
"KEYCODE_BACK" -> maestro.KeyCode.BACK
|
||||||
|
|||||||
Reference in new issue
Block a user