Вопрос или проблема
Я работаю над приложением для Android, которое использует службу доступности для обеспечения безопасного поиска. Оно работает следующим образом: определяет, когда пользователь выполняет поиск или открывает вкладку в поддерживаемом браузере, а затем перенаправляет пользователя на новую вкладку браузера с оригинальным URL и добавленным параметром URL для безопасного поиска. Однако я сталкиваюсь с проблемой, при которой служба правильно открывает новую вкладку с URL для безопасного поиска, но, когда она пытается повторно выполнить проверки на соблюдение безопасного поиска, она перехватывает старый URL (без параметра безопасного поиска). В результате служба попадает в цикл открытия новых вкладок.
Вот код, отвечающий за обеспечение безопасного поиска:
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
if (!isActive || event == null) return // Логика включения или отключения службы
val packageName = event.packageName?.toString() ?: return
if (packageName in supportedBrowsers) {
// Получаем текущий URL из узла
val nodeInfo = event.source ?: return
val currentUrl = extractUrlFromNodeInfo(nodeInfo) // Код для извлечения URL размещён ниже в моем посте
if (currentUrl != null) {
Log.d(TAG, "onAccessibilityEvent: Текущий URL = $currentUrl")
// Проверяем, является ли текущий URL одной из домашних страниц для игнорирования
if (isHomePage(currentUrl)) {
Log.d(TAG, "onAccessibilityEvent: URL является домашней страницей, игнорируем.")
}
else {
// Проверяем, является ли текущий URL уже URL безопасного поиска
val safeSearchKey = safeSearchKeys[packageName] ?: return
if (isSafeSearchActive(currentUrl, safeSearchKey)) {
Log.d(TAG, "onAccessibilityEvent: Безопасный поиск уже активен. Модификация не требуется.")
}
// Если URL не является URL безопасного поиска
else {
// Применить безопасный поиск и перенаправить
val safeUrl = applySafeSearch(currentUrl, safeSearchKey)
Log.d(TAG, "onAccessibilityEvent: Перенаправление на безопасный URL = $safeUrl")
openUrlInSameBrowser(packageName, safeUrl)
}
}
}
else {
Log.d(TAG, "onAccessibilityEvent: URL не найден при смене вкладки")
}
}
else {
Log.d(TAG, "onAccessibilityEvent: Браузер не поддерживается")
}
}
Код для извлечения URL:
private fun extractUrlFromNodeInfo(nodeInfo: AccessibilityNodeInfo): String? {
// Проверяем, является ли текущий узел EditText для извлечения URL
if (nodeInfo.className == "android.widget.EditText") {
val text = nodeInfo.text?.toString()
if (text != null && (text.contains("www.") || text.contains(".com") || text.contains(".net") || text.contains(".org"))) {
return if (text.startsWith("http://") || text.startsWith("https://")) {
text
}
else {
"https://$text"
}
}
}
// Обходим дочерние узлы, чтобы найти URL
for (i in 0 until nodeInfo.childCount) {
val child = nodeInfo.getChild(i)
if (child != null) {
val result = extractUrlFromNodeInfo(child)
if (result != null) {
Log.d(TAG, "extractUrlFromNodeInfo: URL найден в дочернем узле = $result")
return result
}
}
}
return null
}
Код для проверки, активен ли безопасный поиск:
private val safeSearchKeys = mapOf(
"com.android.chrome" to "&safe=active",
"com.brave.browser" to "safesearch.brave.com"
)
private fun isSafeSearchActive(url: String, safeSearchKey: String): Boolean {
return url.contains(safeSearchKey)
}
Код для открытия новой вкладки
private fun openUrlInSameBrowser(packageName: String, safeUrl: String) {
Log.d(TAG, "openUrlInSameBrowser: Открытие безопасного URL в браузере = $safeUrl")
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(safeUrl)).apply {
setPackage(packageName)
flags = Intent.FLAG_ACTIVITY_NEW_TASK // Запуск новой задачи
}
startActivity(intent)
}
Есть ли какой-либо другой более простой способ принудительно включить безопасный поиск, который я упустил, или у кого-то есть решение моей проблемы.
Ответ или решение
Для решения вашей проблемы, когда служба доступности не захватывает обновленные URL-адреса в новых вкладках браузера, необходимо учитывать, что события доступности могут не срабатывать для каждой открываемой вкладки, особенно если новая вкладка инициируется таким же событием, которое уже обрабатывается вашим сервисом. Вы можете изменить свою логику, чтобы избежать бесконечного цикла открытия новых вкладок.
Вот некоторые рекомендации для улучшения вашего кода и решения проблемы:
1. Используйте setTimeout
для задержки
Если обработка события происходит слишком быстро, возможно, стоит добавить небольшую задержку перед повторной проверкой URL-адреса. Это обеспечит возможность браузеру обновить URL.
private fun retryWithDelay(packageName: String, safeUrl: String) {
Handler(Looper.getMainLooper()).postDelayed({
openUrlInSameBrowser(packageName, safeUrl)
}, 1000) // Задержка в 1 секунду
}
2. Измените логику обработки событий
Добавьте переменную состояния, чтобы отслеживать, был ли URL уже модифицирован, чтобы избежать повторного вызова изменения.
private var isRedirecting = false
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
if (!isActive || event == null) return // Логика для включения или отключения сервиса
val packageName = event.packageName?.toString() ?: return
if (packageName in supportedBrowsers) {
val nodeInfo = event.source ?: return
val currentUrl = extractUrlFromNodeInfo(nodeInfo)
if (currentUrl != null) {
Log.d(TAG, "onAccessibilityEvent: Current URL = $currentUrl")
if (isHomePage(currentUrl)) {
Log.d(TAG, "onAccessibilityEvent: URL is a homepage, ignoring.")
return
}
// Проверяем активность безопасного поиска
val safeSearchKey = safeSearchKeys[packageName] ?: return
if (isSafeSearchActive(currentUrl, safeSearchKey)) {
Log.d(TAG, "onAccessibilityEvent: Safe search is already active. No modification needed.")
} else if (!isRedirecting) {
isRedirecting = true
val safeUrl = applySafeSearch(currentUrl, safeSearchKey)
Log.d(TAG, "onAccessibilityEvent: Redirecting to safe URL = $safeUrl")
retryWithDelay(packageName, safeUrl)
}
} else {
Log.d(TAG, "onAccessibilityEvent: No URL found during tab change")
}
} else {
Log.d(TAG, "onAccessibilityEvent: Browser not supported")
}
}
3. Оптимизация метода извлечения URL
Возможно, стоит сделать метод extractUrlFromNodeInfo
более стабильным, чтобы гарантировать, что он всегда возвращает актуальный URL. Рассмотрите возможность массива для хранения всех найденных URL-адресов.
4. Проверка дополнительных условий
Убедитесь, что при вызове метода openUrlInSameBrowser
вы проверяете, не перехватывается ли URL обработкой другого события, чтобы убедиться, что накопленные URL не ведут к циклам.
5. Использование флага для контроля редиректов
Добавьте очистку флага isRedirecting
в onAccessibilityEvent
, чтобы сбросить состояние после завершения редиректа. Это важно, чтобы ваш сервис мог обрабатывать новые события после того, как предыдущие были выполнены.
Заключение
С точки зрения более простой реализации безопасного поиска, вы можете также рассмотреть возможность использования стандартных API браузеров, если они доступны, чтобы установить параметры безопасного поиска по умолчанию, что может упростить вашу логику.
Следуя этим рекомендациям, вы сможете избежать бесконечного цикла открытия новых вкладок и обеспечить более стабильное поведение вашего приложения.