9

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

不幸的是,对于我们的应用程序,信息看起来不太相关,谷歌忽略了我们在里面设置的数据onProvideContentAssist()onProvideAssistData().

这些规范看起来相当高级,并且还包含诸如“可以建议”和“附加信息”之类的词,因此 Google 似乎正式允许自己忽略应用程序开发人员提供的数据。

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

结果不可用
此应用已阻止 Now on Tap

在此处输入图像描述

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

什么都没有

在此处输入图像描述

Opera 如何阻止 Now on Tap?

有谁知道如何阻止 Google Assist API(Now on Tap)而不会从他们这边对我们的应用程序负责?

4

3 回答 3

7

View 类有一个方法setAssistBlocked

控制是否启用来自该视图及其子视图的辅助数据收集(即是否会调用 {@link #onProvideStructure} 和 {@link #onProvideVirtualStructure})。默认值为 false,允许正常辅助收集。将此设置为 false 将禁用辅助收集。

@param enabled 设置为 true 以禁用辅助数据收集,或设置为 false(默认值)以允许它。

不幸的是,这个方法是用 注释的@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();
        }
    }

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

final View rootContent = findViewById(android.R.id.content);
setAssistBlocked(rootContent, true);
于 2015-10-10T08:15:14.043 回答
5

Another possible solution, that I'll eventually need to try out, is hinted at by hackbod's one comment:

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)

The code comment for dispatchProvideStructure() states: "Dispatch creation of ViewStructure down the hierarchy." (emphasis mine).

So, create a NoAssistFrameLayout subclass of FrameLayout, override dispatchProvideStructure() to be a no-op, and use that as your root container for your activity layout. This will block the automatic population of the ViewStructure for anything in the body of the activity.

It will not, however, block anything that could be inferred from stuff outside your main content area, such as your action bar, as that would be outside the NoAssistFrameLayout's view hierarchy. Probably there's not much in there that would have privacy implications, but it's a limitation of this technique.


OK, I have tried it, and it does seem to work:

/***
 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
  }
}
于 2015-10-15T23:17:50.053 回答
-2

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

但是,如果您的问题是 Now on Tap 没有返回相关数据,则解决方案不是阻止它获取的数据 - 所做的只是确保它为您的应用返回的数据永远不会改善,因为它永远不会看到它的数据可以给出更好的建议。阻止它当然不会导致它使用其他数据,它只会让你的应用程序变得愚蠢。

您不应该试图让 Now on Tap 对您的应用程序变得愚蠢。

于 2015-10-15T21:44:46.853 回答