

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Appium 与设备互动
<a name="appium-endpoint-interaction"></a>

[创建远程访问会话](how-to-create-session.md)后，该设备将可用于 Appium 测试。在整个远程访问会话期间，你可以在设备上随心所欲地运行任意数量的 Appium 会话，对使用的客户端没有限制。例如，你可以先使用 IDE 中的本地 Appium 代码运行测试，然后切换到使用 Appium Inspector 来解决遇到的任何问题。会话最多可持续 [150 分钟](limits.md#service-limits)，但是，如果超过 5 分钟没有活动（通过交互式控制台或 Appium 端点），则会话将超时。

## 在 Appium 会话中使用应用程序进行测试
<a name="appium-endpoint-using-apps"></a>

有几种方法可以为你的 Appium 会话提供应用程序：
+ 将应用程序上传到 Device Farm 并将其安装在会话中。
+ 指定 HTTPS 网址或 Amazon S3 URI 作为`appium:app`功能。
+ 按软件包名称引用已安装的应用程序（`appium:appPackage`在 Android 或 `appium:bundleId` iOS 上使用）。
+ 通过指定`browserName`功能来测试网页应用程序（`Chrome`在 Android 上、iOS `Safari` 上）。

标准[应用程序大小限制](limits.md#file-limits) (4 GB) 适用于所有应用程序来源。

**注意**  
Device Farm 不支持在远程访问会话`appium:app`期间传入本地文件系统路径。

### 上传、安装和使用应用程序
<a name="appium-endpoint-app-uploaded"></a>

要在 Appium 会话中使用已上传的应用程序，请按照以下步骤操作：

1. 

**上传并安装您的应用程序**

   有两种方法可以将应用程序上传并安装到被测设备上：
   + 在您的[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_CreateRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_CreateRemoteAccessSession.html)请求中包含应用程序 ARN。会话开始时，应用程序会自动安装到设备上。您还可以添加辅助应用程序 ARNs，该应用程序将与主应用程序一起安装。
   + 在活动会话期间使用 [https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_InstallToRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_InstallToRemoteAccessSession.html)API 安装应用程序，或者通过 Device Farm 控制台上传应用程序。这样，您就可以在不创建新会话的情况下更改被测应用程序。

1. 

**使用已安装的应用程序**

   安装后，该应用程序将自动注入为任何后续的 Appium 会话的默认`appium:app`功能。如果您添加了辅助应用程序，则它们将被设置为`appium:otherApps`功能。

   例如，如果您使用`com.aws.devicefarm.sample`作为应用程序和`com.aws.devicefarm.other.sample`辅助应用程序之一来创建远程访问会话，那么当您开始创建 Appium 会话时，它将具有类似于以下内容的功能：

   ```
   {
       "value":
       {
           "sessionId": "abcdef123456-1234-5678-abcd-abcdef123456",
           "capabilities":
           {
               "app": "/tmp/com.aws.devicefarm.sample.apk",
               "otherApps": "[\"/tmp/com.aws.devicefarm.other.sample.apk\"]",
               ...
           }
       }
   }
   ```

   如果您在会话期间安装新应用程序，它将取代当前`appium:app`功能。如果先前安装的应用程序具有不同的软件包名称，则它会保留在设备上并移至该`appium:otherApps`功能。

   例如，如果您最初在创建远程访问会话`com.aws.devicefarm.sample`时使用，但随后在会话`com.aws.devicefarm.other.sample`期间安装，则您的 Appium 会话将具有类似于以下内容的功能：

   ```
   {
       "value":
       {
           "sessionId": "abcdef123456-1234-5678-abcd-abcdef123456",
           "capabilities":
           {
               "app": "/tmp/com.aws.devicefarm.other.sample.apk",
               "otherApps": "[\"/tmp/com.aws.devicefarm.sample.apk\"]",
               ...
           }
       }
   }
   ```

**注意**  
有关在远程访问会话中自动上传应用程序的更多信息，请参阅[自动上传应用程序](api-ref.md#upload-example)。

### 使用 HTTPS 网址
<a name="appium-endpoint-app-https-url"></a>

创建 Appium 会话时，您可以将可公开访问的 HTTPS 网址指定为`appium:app`所需的功能。网址必须直接指向可下载的应用程序文件（例如，`.apk`或`.ipa`文件）。Device Farm 从指定的网址下载应用程序，并将其安装到被测设备上。

**重要**  
仅支持 HT URLs TPS。纯HTTP URLs 被拒绝。

例如，以下 Appium 会话创建请求从 HTTPS 网址下载应用程序：

```
{
    "capabilities":
    {
        "alwaysMatch": {},
        "firstMatch":
        [
            {
                "appium:app": "https://example.com/path/to/MyApp.apk"
            }
        ]
    }
}
```

### 使用亚马逊 S3 URI
<a name="appium-endpoint-app-s3-uri"></a>

创建 Appium 会话时，您可以将 Amazon S3 URI（例如`s3://my-bucket/path/to/MyApp.ipa`）指定为`appium:app`所需的功能。Device Farm 从指定的 S3 位置下载应用程序并将其安装到被测设备上。

要使用 S3 URI，必须满足以下要求：
+ 远程访问会话必须从配置了 [IAM 执行角色](custom-test-environments-iam-roles.md)的项目启动。
+ IAM 执行角色的最大会话持续时间必须至少为 150 分钟，因为该角色是在远程访问会话期间担任的。
+ IAM 执行角色必须有权调用 `s3:GetObject` URI 中指定的 S3 对象。我们还建议对同一对象授予`s3:HeadObject`权限，这样 Device Farm 就可以在尝试下载之前验证该对象的存在。

例如，以下 Appium 会话创建请求从 S3 URI 下载应用程序：

```
{
    "capabilities":
    {
        "alwaysMatch": {},
        "firstMatch":
        [
            {
                "appium:app": "s3://my-test-bucket/apps/MyApp.ipa"
            }
        ]
    }
}
```

以下是 IAM 权限策略示例，该策略授予从 Amazon S3 下载应用程序的推荐访问权限，包括可选`s3:HeadObject`权限。有关配置 IAM 执行角色的更多信息，请参阅[使用 IAM 执行角色访问 AWS 资源](custom-test-environments-iam-roles.md)。

**Example**  

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:HeadObject"
      ],
      "Resource": "arn:aws:s3:::my-test-bucket/apps/*"
    }
  ]
}
```

### 使用已安装的应用程序
<a name="appium-endpoint-app-package-name"></a>

如果您要测试的应用程序已安装在设备上，则可以直接通过其软件包名称来引用它，而不必上传它。在 Android 上使用`appium:appPackage`和`appium:appActivity`功能，或者在 iOS 上使用该`appium:bundleId`功能。

例如，以下 Appium 会话创建请求会启动已经安装的安卓应用程序：

```
{
    "capabilities":
    {
        "alwaysMatch": {},
        "firstMatch":
        [
            {
                "appium:appPackage": "com.example.myapp",
                "appium:appActivity": "com.example.myapp.MainActivity"
            }
        ]
    }
}
```

在 iOS 上，请`appium:bundleId`改用：

```
{
    "capabilities":
    {
        "alwaysMatch": {},
        "firstMatch":
        [
            {
                "appium:bundleId": "com.example.myapp"
            }
        ]
    }
}
```

### 测试 Web 应用程序
<a name="appium-endpoint-app-web"></a>

要测试 Web 应用程序，请在您的 Appium 会话创建请求中指定该`browserName`功能。`Chrome`在安卓设备或 iOS 设备`Safari`上使用。

例如，以下请求会在安卓设备上打开 Chrome：

```
{
    "capabilities":
    {
        "alwaysMatch": {},
        "firstMatch":
        [
            {
                "browserName": "Chrome"
            }
        ]
    }
}
```

## 如何使用 Appium 端点
<a name="appium-endpoint-how-to-use"></a>

以下是从控制台、和访问会话的 Appium 端点的 AWS CLI步骤。 AWS SDKs这些步骤包括如何开始使用各种 Appium 客户端测试框架运行测试：

------
#### [ Console ]

1. 在 Web 浏览器中打开远程访问会话页面：  
![远程访问会话页面](http://docs.aws.amazon.com/zh_cn/devicefarm/latest/developerguide/images/aws-device-farm-appium-endpoint.png)

1. 要使用 Appium Inspector 运行会话，请执行以下操作：

   1. 点击按钮**设置 Appi** um 会话

   1. 按照页面上的说明进行操作，了解如何使用 Appium Inspector 启动会话。

1. 要从本地 IDE 运行 Appium 测试，请执行以下操作：

   1. 点击文本 **Appium** 端点网址旁边的 “复制” 图标

   1. 将此 URL 粘贴到您当前指定远程地址或命令执行器的本地 Appium 代码中。要查看特定语言的示例，请单击此示例窗口中您选择的语言的选项卡。

------
#### [ AWS CLI ]

首先， up-to-date通过[下载并安装最新版本来验证您的 AWS CLI 版本是否为最新版本](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

**重要**  
Appium 终端节点字段在旧版本的 AWS CLI 中不可用。

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
$ aws devicefarm get-remote-access-session \
    --arn "arn:aws:devicefarm:us-west-2:123456789876:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"
```

这将显示如下输出：

```
{
    "remoteAccessSession": {
        "arn": "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000",
        "name": "Google Pixel 8",
        "status": "RUNNING",
        "endpoints": {
            "remoteDriverEndpoint": "https://devicefarm-interactive-global.us-west-2.api.aws/remote-endpoint/ABCD1234...",
        ...
}
```

无论您当前指定远程地址或命令执行器，都可以在本地 Appium 代码中使用此 URL。要查看特定语言的示例，请单击此示例窗口中您选择的语言的选项卡。

有关如何直接从命令行与端点交互的示例，您可以使用[命令行工具 curl](https://curl.se/) 直接调用端点： WebDriver 

```
$ curl "https://devicefarm-interactive-global.us-west-2.api.aws/remote-endpoint/ABCD1234.../status"
```

这将显示如下输出：

```
{
    "value":
    {
        "ready": true,
        "message": "The server is ready to accept new connections",
        "build":
        {
            "version": "2.5.1"
        }
    }
}
```

------
#### [ Python ]

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
# To get the URL
import sys
import boto3
from botocore.exceptions import ClientError

def get_appium_endpoint() -> str:
    session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"
    device_farm_client = boto3.client("devicefarm", region_name="us-west-2")

    try:
        resp = device_farm_client.get_remote_access_session(arn=session_arn)
    except ClientError as exc:
        sys.exit(f"Failed to call Device Farm: {exc}")

    remote_access_session = resp.get("remoteAccessSession", {})
    endpoints = remote_access_session.get("endpoints", {})
    endpoint = endpoints.get("remoteDriverEndpoint")

    if not endpoint:
        sys.exit("Device Farm response did not include endpoints.remoteDriverEndpoint")

    return endpoint

# To use the URL
from appium import webdriver
from appium.options.android import UiAutomator2Options

opts = UiAutomator2Options()
driver = webdriver.Remote(get_appium_endpoint(), options=opts)
# ...
driver.quit()
```

------
#### [ Java ]

*注意：此示例使用 AWS 适用于 Java v2 的 SDK，并且与 JDK 版本 11 及更高版本兼容。*

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
// To get the URL
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.devicefarm.DeviceFarmClient;
import software.amazon.awssdk.services.devicefarm.model.GetRemoteAccessSessionRequest;
import software.amazon.awssdk.services.devicefarm.model.GetRemoteAccessSessionResponse;

public class AppiumEndpointBuilder {
    public static String getAppiumEndpoint() throws Exception {
        String session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";

        try (DeviceFarmClient client = DeviceFarmClient.builder()
                .region(Region.US_WEST_2)
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build()) {

            GetRemoteAccessSessionResponse resp = client.getRemoteAccessSession(
                    GetRemoteAccessSessionRequest.builder().arn(session_arn).build()
            );

            String endpoint = resp.remoteAccessSession().endpoints().remoteDriverEndpoint();
            if (endpoint == null || endpoint.isEmpty()) {
                throw new IllegalStateException("remoteDriverEndpoint missing from response");
            }
            return endpoint;
        }
    }
}

// To use the URL
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;

import java.net.URL;

public class ExampleTest {
    public static void main(String[] args) throws Exception {
        String endpoint = AppiumEndpointBuilder.getAppiumEndpoint();
        UiAutomator2Options options = new UiAutomator2Options();
        AndroidDriver driver = new AndroidDriver(new URL(endpoint), options);

        try {
            // ... your test ...
        } finally {
            driver.quit();
        }
    }
}
```

------
#### [ JavaScript ]

*注意：此示例使用 AWS 适用于 v JavaScript 3 的 SDK，使用 Node 18\+ 的 WebDriverIO v8\+。*

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
// To get the URL
import { DeviceFarmClient, GetRemoteAccessSessionCommand } from "@aws-sdk/client-device-farm";

export async function getAppiumEndpoint() {
  const sessionArn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";

  const client = new DeviceFarmClient({ region: "us-west-2" });
  const resp = await client.send(new GetRemoteAccessSessionCommand({ arn: sessionArn }));

  const endpoint = resp?.remoteAccessSession?.endpoints?.remoteDriverEndpoint;
  if (!endpoint) throw new Error("remoteDriverEndpoint missing from response");
  return endpoint;
}

// To use the URL with WebdriverIO
import { remote } from "webdriverio";

(async () => {
  const endpoint = await getAppiumEndpoint();
  const u = new URL(endpoint);

  const driver = await remote({
    protocol: u.protocol.replace(":", ""),
    hostname: u.hostname,
    port: u.port ? Number(u.port) : (u.protocol === "https:" ? 443 : 80),
    path: u.pathname + u.search,
    capabilities: {
      platformName: "Android",
      "appium:automationName": "UiAutomator2",
      // ...other caps...
    },
  });

  try {
    // ... your test ...
  } finally {
    await driver.deleteSession();
  }
})();
```

------
#### [ C\# ]

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
// To get the URL
using System;
using System.Threading.Tasks;
using Amazon;
using Amazon.DeviceFarm;
using Amazon.DeviceFarm.Model;

public static class AppiumEndpointBuilder
{
    public static async Task<string> GetAppiumEndpointAsync()
    {
        var sessionArn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";

        var config = new AmazonDeviceFarmConfig
        {
            RegionEndpoint = RegionEndpoint.USWest2
        };
        using var client = new AmazonDeviceFarmClient(config);

        var resp = await client.GetRemoteAccessSessionAsync(new GetRemoteAccessSessionRequest { Arn = sessionArn });
        var endpoint = resp?.RemoteAccessSession?.Endpoints?.RemoteDriverEndpoint;

        if (string.IsNullOrWhiteSpace(endpoint))
            throw new InvalidOperationException("RemoteDriverEndpoint missing from response");

        return endpoint;
    }
}

// To use the URL
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Android;

class Example
{
    static async Task Main()
    {
        var endpoint = await AppiumEndpointBuilder.GetAppiumEndpointAsync();

        var options = new AppiumOptions();
        options.PlatformName = "Android";
        options.AutomationName = "UiAutomator2";

        using var driver = new AndroidDriver(new Uri(endpoint), options);
        try
        {
            // ... your test ...
        }
        finally
        {
            driver.Quit();
        }
    }
}
```

------
#### [ Ruby ]

会话启动并运行后，Appium 端点网址将通过响应 API 调用时命名的`remoteDriverEndpoint`字段提供：[https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html](https://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetRemoteAccessSession.html)

```
# To get the URL
require 'aws-sdk-devicefarm'

def get_appium_endpoint
  session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"

  client = Aws::DeviceFarm::Client.new(region: 'us-west-2')
  resp = client.get_remote_access_session(arn: session_arn)
  endpoint = resp.remote_access_session.endpoints.remote_driver_endpoint
  raise "remote_driver_endpoint missing from response" if endpoint.nil? || endpoint.empty?
  endpoint
end

# To use the URL
require 'appium_lib_core'

endpoint = get_appium_endpoint
opts = {
  server_url: endpoint,
  capabilities: {
    'platformName' => 'Android',
    'appium:automationName' => 'UiAutomator2'
  }
}

driver = Appium::Core.for(opts).start_driver
begin
  # ... your test ...
ensure
  driver.quit
end
```

------