我启用了可访问性服务权限,现在我想从地址栏中获取 url。
我尝试过以下事情:
无障碍服务配置.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackAllMask"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="0"
android:canRequestFilterKeyEvents="true"
android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />
访问服务.javapublic class AccessService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source == null)
return;
final String packageName = String.valueOf(source.getPackageName());
String BROWSER_LIST = "com.android.chrome";
List<String> browserList
= Arrays.asList(BROWSER_LIST.split(",\\s*"));
if (event.getEventType()
== AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
if (!browserList.contains(packageName)) {
return;
}
}
if (browserList.contains(packageName)) {
try {
if (AccessibilityEvent
.eventTypeToString(event.getEventType())
.contains("WINDOW")) {
AccessibilityNodeInfo nodeInfo = event.getSource();
getUrlsFromViews(nodeInfo);
}
} catch (StackOverflowError ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public void getUrlsFromViews(AccessibilityNodeInfo info) {
try {
if (info == null)
return;
if (info.getText() != null && info.getText().length() > 0) {
String capturedText = info.getText().toString();
Bundle arguments = new Bundle();
if (capturedText.contains("https://")
|| capturedText.contains("http://")) {
if (capturedText.contains("facebook.com")) {
// open new tab
}
}
}
for (int i = 0; i < info.getChildCount(); i++) {
AccessibilityNodeInfo child = info.getChild(i);
getUrlsFromViews(child);
if (child != null) {
child.recycle();
}
}
} catch (StackOverflowError ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public void onInterrupt() {
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
}
}
我在这里面临的问题是,当我在地址栏中键入 facebook.com 并点击 url 时,我只得到 facebook.com
或 m.facebook.com
因此,我无法采取任何行动。我只想在地址栏中点击它后获取 URL。我也想在地址栏中打开新标签并关闭现有标签。
有没有合适的方法来做到这一点?
最佳答案
我有一些要补充的内容以及我们如何改进您的解决方案。如果您接受以下限制可能会更好:
I want to get the URL only after it is hit in the address bar.
实现:
public class UrlInterceptorService extends AccessibilityService {
private HashMap<String, Long> previousUrlDetections = new HashMap<>();
@Override
protected void onServiceConnected() {
AccessibilityServiceInfo info = getServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.packageNames = packageNames();
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_VISUAL;
//throttling of accessibility event notification
info.notificationTimeout = 300;
//support ids interception
info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS |
AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
this.setServiceInfo(info);
}
private String captureUrl(AccessibilityNodeInfo info, SupportedBrowserConfig config) {
List<AccessibilityNodeInfo> nodes = info.findAccessibilityNodeInfosByViewId(config.addressBarId);
if (nodes == null || nodes.size() <= 0) {
return null;
}
AccessibilityNodeInfo addressBarNodeInfo = nodes.get(0);
String url = null;
if (addressBarNodeInfo.getText() != null) {
url = addressBarNodeInfo.getText().toString();
}
addressBarNodeInfo.recycle();
return url;
}
@Override
public void onAccessibilityEvent(@NonNull AccessibilityEvent event) {
AccessibilityNodeInfo parentNodeInfo = event.getSource();
if (parentNodeInfo == null) {
return;
}
String packageName = event.getPackageName().toString();
SupportedBrowserConfig browserConfig = null;
for (SupportedBrowserConfig supportedConfig: getSupportedBrowsers()) {
if (supportedConfig.packageName.equals(packageName)) {
browserConfig = supportedConfig;
}
}
//this is not supported browser, so exit
if (browserConfig == null) {
return;
}
String capturedUrl = captureUrl(parentNodeInfo, browserConfig);
parentNodeInfo.recycle();
//we can't find a url. Browser either was updated or opened page without url text field
if (capturedUrl == null) {
return;
}
long eventTime = event.getEventTime();
String detectionId = packageName + ", and url " + capturedUrl;
//noinspection ConstantConditions
long lastRecordedTime = previousUrlDetections.containsKey(detectionId) ? previousUrlDetections.get(detectionId) : 0;
//some kind of redirect throttling
if (eventTime - lastRecordedTime > 2000) {
previousUrlDetections.put(detectionId, eventTime);
analyzeCapturedUrl(capturedUrl, browserConfig.packageName);
}
}
private void analyzeCapturedUrl(@NonNull String capturedUrl, @NonNull String browserPackage) {
String redirectUrl = "your redirect url is here";
if (capturedUrl.contains("facebook.com")) {
performRedirect(redirectUrl, browserPackage);
}
}
/** we just reopen the browser app with our redirect url using service context
* We may use more complicated solution with invisible activity to send a simple intent to open the url */
private void performRedirect(@NonNull String redirectUrl, @NonNull String browserPackage) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(redirectUrl));
intent.setPackage(browserPackage);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, browserPackage);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
catch(ActivityNotFoundException e) {
// the expected browser is not installed
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(redirectUrl));
startActivity(i);
}
}
@Override
public void onInterrupt() { }
@NonNull
private static String[] packageNames() {
List<String> packageNames = new ArrayList<>();
for (SupportedBrowserConfig config: getSupportedBrowsers()) {
packageNames.add(config.packageName);
}
return packageNames.toArray(new String[0]);
}
private static class SupportedBrowserConfig {
public String packageName, addressBarId;
public SupportedBrowserConfig(String packageName, String addressBarId) {
this.packageName = packageName;
this.addressBarId = addressBarId;
}
}
/** @return a list of supported browser configs
* This list could be instead obtained from remote server to support future browser updates without updating an app */
@NonNull
private static List<SupportedBrowserConfig> getSupportedBrowsers() {
List<SupportedBrowserConfig> browsers = new ArrayList<>();
browsers.add( new SupportedBrowserConfig("com.android.chrome", "com.android.chrome:id/url_bar"));
browsers.add( new SupportedBrowserConfig("org.mozilla.firefox", "org.mozilla.firefox:id/url_bar_title"));
return browsers;
}
}
和无障碍服务配置:<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:canRetrieveWindowContent="true"
android:settingsActivity=".ServiceSettingsActivity" />
随时提出任何问题,我会尽力提供帮助
关于android - 如何使用无障碍服务从浏览器获取 url,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63880266/