106_检索 Android 设备的状态栏通知

转自appiumpro

image
在 Appium 历史的大部分时间里,用户都无法检查 Android 设备上收到的通知,尤其是“状态栏”通知,只能从状态栏上下拉才能看到。 为了自动验证接收到的通知,蛮力方法意味着导航到这个通知视图,并希望能够幸运地阅读该页面上的文本元素。 最近,Appium 团队找到了一种通过 Appium 设置助手应用程序读取通知的方法。 这是一个安装在 Appium 会话旁边的小应用程序,它促进了设备级别的功能,而这不仅仅是通过 UiAutomator2或 Espresso 实现的。

基本上,Appium 设置应用程序可以被授予读取任何传入通知的权限。 然后,它可以保存这些通知,以便主 Appium 进程使用 ADB 进行检索。 所有这些复杂性都集中在一个 Appium 命令中(首次发布于 Appium 1.16) :

driver.executeScript("mobile: getNotifications");

要使这个命令起作用,Appium 设置应用程序当然必须被授予通知读取权限。 这可以在 Android 系统设置的“ Notification Access”区域手动完成(根据设备的不同,导航到此视图的精确方式也不同)。 或者,您可以使用 Appium 将其自动化,作为设备配置步骤的一部分。

目前,此方法的返回值有点复杂。 在 JSON,情况会是这样的:

{
"statusBarNotifications": [
{
"isGroup":false,
"packageName":"io.appium.settings",
"isClearable":false,
"isOngoing":true,
"id":1,
"tag":null,
"notification":{
"title":null,
"bigTitle":"Appium Settings",
"text":null,
"bigText":"Keep this service running, so Appium for Android can properly interact with several system APIs",
"tickerText":null,
"subText":null,
"infoText":null,
"template":"android.app.Notification$BigTextStyle"
},
"userHandle":0,
"groupKey":"0|io.appium.settings|1|null|10133",
"overrideGroupKey":null,
"postTime":1576853518850,
"key":"0|io.appium.settings|1|null|10133",
"isRemoved":false
}
]
}

但是,当然,在 Appium Java 客户机中,我们不会得到 JSON 响应,因此我们的工作是适当地强制转换响应:

Map<String, Object> notifications = (Map<String, Object>)driver.executeScript("mobile: getNotifications");

当我们在对象中导航的时候,我们需要保持强制转换。 基本上,我们有一个主键 statusBarNotifications,它返回一个通知对象数组。 每个通知对象本身都有大量与之关联的元数据(例如,您可以使用此元数据根据应用程序的包 ID 进行筛选)。 该对象的通知键包含我们要查找的主要内容,包括通知的标题和文本。

这项技术特别强大,因为已经授予 Appium 特殊权限,您可以读取设备上任何应用程序的通知。

就是这样! 查看一个完整的例子,其中我们遍历了自 Appium 启动以来收到的每个通知,并将其打印到控制台,确保我们适当地选择了具有内容的通知文本和标题的类型:

public class Edition106_Android_Notifications {
private String APP = "https://github.com/cloudgrey-io/the-app/releases/download/v1.10.0/TheApp-v1.10.0.apk";
private AndroidDriver driver;

@Before
public void setUp() throws Exception {
DesiredCapabilities capabilities = new DesiredCapabilities();

capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("automationName", "UiAutomator2");
capabilities.setCapability("app", APP);

driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), capabilities);
}

@After
public void tearDown() {
if (driver != null) {
driver.quit();
}
}

@Test
@SuppressWarnings("unchecked")
public void testNotifications() {
Map<String, Object> res = (Map<String, Object>)driver.executeScript("mobile: getNotifications");
List<Map<String, Object>> notifications = (List<Map<String, Object>>)res.get("statusBarNotifications");
for (Map<String, Object> notification : notifications) {
Map<String, String> innerNotification = (Map<String, String>)notification.get("notification");
if (innerNotification.get("bigTitle") != null) {
System.out.println(innerNotification.get("bigTitle"));
} else {
System.out.println(innerNotification.get("title"));
}
if (innerNotification.get("bigText") != null) {
System.out.println(innerNotification.get("bigText"));
} else {
System.out.println(innerNotification.get("text"));
}
}
}
}