如何解决如何使用辅助功能从浏览器获取URL
我已启用了无障碍服务权限,现在我想从地址栏中获取网址。
我尝试了以下方法:
accessibility_service_config.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" />
AccessService.java
public 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后才能获得URL。我也想在地址栏中的facebook.com时打开新标签并关闭现有标签。
有什么合适的方法吗?
解决方法
我要在此处添加一些内容,以及我们如何改进您的解决方案。如果您接受以下限制可能会更好:
- 该应用程序具有受支持的浏览器的嵌入式列表。不支持任何其他浏览器。
- 可访问性服务将在地址栏文本字段中查找 id ,并尝试从此处拦截URL。无法直接捕获将要加载的URL。要找到此ID,我们应该对目标浏览器进行一些逆向工程:通过可访问性服务收集所有字段,并将其ID和值与用户输入进行比较。
- 从上一点出发,下一个限制是我们将仅支持当前版本的浏览器。将来,第三方浏览器开发人员可能会更改ID,我们将必须更新拦截器才能继续提供支持。这可以通过更新应用程序或通过将浏览器软件包提供给远程服务器的ID映射来完成
- 我们检测到手动输入或在按下链接时重定向(因为在这种情况下,新的URL也将在地址栏中显示)。顺便说一句,你说的意思不清楚
我只想在地址栏中将其击中后获取URL。
- 最后一个限制。尽管我们能够能够拦截 URL和重定向用户到另一个页面,但我们无法阻止网站加载或开始加载由于异步解析浏览器应用程序屏幕的延迟。例如。保护用户免受对欺诈网站的任何访问并不真正安全
实现:
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" />
随时问任何问题,我会尽力帮助
,首先,在accessibility_service XML中添加标志和包
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackAllMask"
android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode|flagRequestEnhancedWebAccessibility|flagReportViewIds|flagRetrieveInteractiveWindows"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="0"
android:canRequestFilterKeyEvents="true"
android:packageNames="com.android.chrome"
android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />
在AndroidManifest中:
<service android:name=".MyAccessibilityService"
android:label="@string/accessibility_title"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service" />
</service>
java类:
public class ASUrl extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if(AccessibilityEvent.eventTypeToString(event.getEventType()).contains("WINDOW")){
AccessibilityNodeInfo nodeInfo = event.getSource();
dfs(nodeInfo);
}
}
/**
* Method to loop through all the views and try to find a URL.
* @param info
*/
public void getUrlsFromViews(AccessibilityNodeInfo info) {
if(info == null)
return;
if(info.getText() != null && info.getText().length() > 0)
System.out.println(info.getText() + " class: "+info.getClassName());
for(int i=0;i<info.getChildCount();i++){
AccessibilityNodeInfo child = info.getChild(i);
getUrlsFromViews(child);
if(child != null){
child.recycle();
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。