如何禁用 Google 辅助 API(现在点击)

How to disable Google Assist API (Now on Tap)

Google 最近发布了 Android Marshmallow with Now on Tap,它可以扫描应用程序内容并向用户提供附加信息。

不幸的是,对于我们的应用程序,信息看起来不太相关,Google 忽略了我们在 onProvideContentAssist()onProvideAssistData().

中设置的数据

These specs 看起来相当高级,而且还包含“可以建议”和“附加信息”之类的词,所以似乎 Google 正式允许自己忽略应用程序开发人员提供的数据。

所以我们决定禁用 Now on Tap,但这似乎不是很简单。 根据上面提供的文档,在这种情况下我们应该使用 FLAG_SECURE 。但是随后用户无法捕获屏幕截图,Google Now on Tap 开始将以下面向用户的消息归咎于我们的应用:

Results not available
This app has blocked Now on Tap

但 Opera 似乎以某种方式温和地阻止了 Now on Tap 的私人标签。它为他们显示了更多应用友好的消息:

Nothing on tap

Opera 如何阻止 Now on Tap?

有没有人知道如何阻止 Google 协助 API(Now on Tap)而不会从他们那边责怪我们的应用程序?

视图 class 有一个方法 setAssistBlocked:

Controls whether assist data collection from this view and its children is enabled (that is, whether {@link #onProvideStructure} and {@link #onProvideVirtualStructure} will be called). The default value is false, allowing normal assist collection. Setting this to false will disable assist collection.

@param enabled Set to true to disable assist data collection, or false (the default) to allow it.

遗憾的是这个方法被注解了@hide,所以我们看不到或者直接使用。

但是我们可以通过一个小的反射调用来使用它:

private void setAssistBlocked(View view, boolean blocked) {
        try {
            Method setAssistBlockedMethod = View.class.getMethod("setAssistBlocked", boolean.class);
            setAssistBlockedMethod.invoke(view, blocked);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

要阻止 activity 中的所有内容,您可以使用:

final View rootContent = findViewById(android.R.id.content);
setAssistBlocked(rootContent, true);

Opera 这样做可能是因为他们没有更新浏览器来报告辅助数据(这需要与不使用普通视图层次结构的应用程序特别合作,例如浏览器)。

但是,如果您的问题是 Now on Tap 没有返回相关数据,解决方案是阻止它正在获取的数据——所做的只是确保data it returns 你的应用程序永远不会改进,因为它从来没有看到它可以提供更好建议的数据。阻止它当然不会导致它使用其他数据,它只会让它对您的应用变得愚蠢。

您不应该试图让您的应用变得愚蠢。

另一种可能的解决方案,我最终需要尝试,由 :

暗示

Further, in this case there is no reason to do this, because you can use this: https://developer.android.com/reference/android/view/View.html#dispatchProvideStructure(android.view.ViewStructure)

dispatchProvideStructure() 的代码注释指出:"Dispatch creation of ViewStructure down the hierarchy."(强调我的)。

因此,创建 FrameLayoutNoAssistFrameLayout 子类,将 dispatchProvideStructure() 重写为空操作,并将其用作 activity 布局的根容器.这将阻止 ViewStructure 自动填充 activity.

正文中的任何内容

但是,它不会阻止任何可以从您的主要内容区域之外的内容推断出来的内容,例如您的操作栏,因为那将在 NoAssistFrameLayout 的视图层次结构之外。 可能其中没有太多涉及隐私的内容,但这是该技术的局限性。


好的,我已经试过了,似乎确实有效:

/***
 Copyright (c) 2015 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 From _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.assist.no;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewStructure;
import android.widget.FrameLayout;

public class NoAssistFrameLayout extends FrameLayout {
  public NoAssistFrameLayout(Context context) {
    super(context);
  }

  public NoAssistFrameLayout(Context context,
                             AttributeSet attrs) {
    super(context, attrs);
  }

  public NoAssistFrameLayout(Context context,
                             AttributeSet attrs,
                             int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public NoAssistFrameLayout(Context context,
                             AttributeSet attrs,
                             int defStyleAttr,
                             int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  @Override
  public void dispatchProvideStructure(ViewStructure structure) {
    // no, thanks
  }
}