需要从 Android“概览屏幕”中隐藏程序内容

Posted

技术标签:

【中文标题】需要从 Android“概览屏幕”中隐藏程序内容【英文标题】:Need to hide content of program from Android "Overview Screen" 【发布时间】:2014-12-04 01:33:33 【问题描述】:

我正在为一位注重安全的雇主开发一款 android 应用。他担心出现在Overview Screen(又名最近任务列表)上的屏幕快照泄露敏感信息,并希望我在系统拍摄该照片之前放置程序的启动屏幕。不幸的是,我还没有找到任何方法。

我尝试过的事情:

onPause 函数中增加启动画面的视图。 (无效,即使使用 bringToFrontsetVisibility(View.VISIBLE)。) 在onCreate 中膨胀启动屏幕的视图并在onPause 中使用bringToFront。 (同样,没有效果。) 在onPause 中调用setVisible(false)。 (似乎几乎可以工作,因为当从程序切换时屏幕会瞬间闪烁到黑色,但显然在快照之前系统再次使其可见。) 在onPause 中视图的最顶部项目上调用setVisibility(View.INVISIBLE)。 (好像可以,但快照显然是在它生效之前拍摄的。)

我是一名中等成就的 Android 开发人员,但我不禁觉得我缺少一个简单的解决方案。

【问题讨论】:

试试onCreateThumbnail(),因为我认为这就是这里使用的。或者,use FLAG_SECURE 简单地阻止所有内容(相对于启动屏幕)。 @CommonsWare,完美!如果你能把它变成答案,我会很乐意接受。 【参考方案1】:

就我个人而言,我会go with FLAG_SECURE,并简单地阻止在任何地方显示这些东西:

public class FlagSecureTestActivity extends Activity 
  @Override
  public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    getWindow().setFlags(LayoutParams.FLAG_SECURE,
                         LayoutParams.FLAG_SECURE);

    setContentView(R.layout.main);
  

但是,IIRC,您可以覆盖 onCreateThumbnail() 以提供您自己的图像以用于最近的任务列表。请注意,这可能在 Android 5.0 中发生了变化,因为他们已经彻底检查了最近的任务列表,因此请务必在 5.0 设备或模拟器上测试您的代码。

【讨论】:

不幸的是,onCreateThumbnail 似乎不起作用。它从来没有在这里调用过(Android 4.4 和 5.0),我发现了这个:code.google.com/p/android/issues/detail?id=29370>。 FLAG_SECURE 也有其自身的问题,部分描述如下:***.com/a/11121897/12193>。嗯,保持冷静,继续前进。 ;-) 添加 FLAG_SECURE 并且我的用户无法截屏应用程序。我只想隐藏内容应用程序,我该怎么做。谢谢。 @JackHuynh:抱歉,我不知道“隐藏内容应用”是什么意思。 @CommonsWare,它的脸书信使,当应用程序进入后台时,它有一个掩码来保护应用程序。 @JackHuynh:抱歉,我不知道有什么可靠的方法来实现。【参考方案2】:

这是一个隐藏应用程序内容的解决方案,当应用程序进入后台时,它会用启动屏幕覆盖它。 这不是使用 FLAG_SECURE 技术,我只是覆盖屏幕的 onPause 和 onResume 方法,并修改视图以显示覆盖所有内容的视图。

首先我在一个单独的文件中创建我的初始屏幕作为一个名为 splash_screen_custom 的相对布局,我还在文件中为该相对布局指定了一个 id customSplash。请注意高度设置,我遇到了按钮具有预设高度的问题,因此通过将此封面屏幕设置为高高度,它将覆盖所有按钮(当然,如果您不覆盖按钮,则不需要此设置)。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
     android:id="@+id/customSplash"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_
     android:layout_
     android:background="@color/backgroundColor"
     android:elevation="5dp"
         >

     <ImageView
         android:id="@+id/imageView"
         android:layout_
         android:layout_
         android:layout_centerInParent="true"
         app:srcCompat="@drawable/yourImage" />
</RelativeLayout>

在这个例子中,我试图覆盖的屏幕是一个相对布局,因此我可以通过我试图覆盖的视图的 addView 和 removeView 方法简单地添加和删除我的启动屏幕。

override fun onPause() 

    var parentView = findViewById<RelativeLayout>(R.id.parentView)
    var splashScreen = layoutInflater.inflate(R.layout.splash_screen_custom, null)
    parentView.addView(splashScreen, parentView.width, parentView.height)

    super.onPause()



override fun onResume() 
    var parentView = findViewById<RelativeLayout>(R.id.parentView)
    parentView.removeView(findViewById<RelativeLayout>(R.id.customSplash))
    super.onResume()


【讨论】:

我后来意识到的小错误......这将导致屏幕转换在转换之间也显示启动屏幕(显然因为 onPause 将被调用)。您可以简单地创建一个标志来禁用特定意图。这不像我希望的那样干净。但是,如果您在将应用程序置于后台时确实需要启动画面,这是我找到的最干净的方式。【参考方案3】:

我只想根据@D.Maul 的回答为 react-native android 提供另一个版本:

一些边缘情况的错误:

[1] 对话框正在显示 [2] 打开相机时会显示一个非常快速的 SplashScreen

代码

@Override
protected void onPause() 
  try 
    // Hide app preview with SplahScreen
    FrameLayout parentView = findViewById(android.R.id.content);
    if (parentView != null && parentView.findViewById(R.id.splash_activity) == null) 
      View splashScene = this.getLayoutInflater().inflate(R.layout.splash_activity, null);
      parentView.addView(splashScene, parentView.getWidth(), parentView.getHeight());
    
   catch (Exception e) 
    // do nothing
  

  super.onPause();


@Override
protected void onResume() 
  try 
    // Remove SplashScreen
    FrameLayout parentView = findViewById(android.R.id.content);
    if (parentView != null) 
      parentView.removeView(this.findViewById(R.id.splash_activity));
    
   catch (Exception e) 
    // do nothing
  

  super.onResume();

【讨论】:

嗨@tran 这似乎在我的模拟器上大部分时间都可以工作,但在我的物理 OnePlus 8 Pro 上它永远不会工作。我试图删除 onResume 调用以验证启动屏幕是否正在实际呈现,它就是这样。那么这可能是一个时间/性能问题,是在截取屏幕截图和渲染叠加层之间的竞赛。我发现 Android 删除了用于设置缩略图的 API (onCreateThumbnail) 并且没有为它提供其他解决方案,这让我感到沮丧。以上真的对你在物理设备上也有用吗? 嗨,是的,上次我测试它在我的像素 2 上工作。但由于上述边缘情况,我不使用它。我现在使用 FLAG_SECURE 以获得更好的安全性,因为它是由操作系统处理的。例如:getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); 是的,我们目前正在这样做,但我们的用户抱怨无法截屏(我理解他们),我们只是被允许启用此功能,但现在这可能是显示塞子。【参考方案4】:

基于@D.Maul 的回答,但Java 版本,我没有添加视图,而是尝试了这个。它运行良好,但有时最近的快照显示应用内容不知道如何处理它。

private Dialog dialog = null;

@Override
public void onCreate(Bundle savedInstanceState) 
  super.onCreate(savedInstanceState);
  dialog = new Dialog(this, android.R.style.Theme_Light);
  dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
  dialog.setContentView(R.layout.customlaunch);


@Override
protected void onPause() 
    dialog.show();
    super.onPause();

    
@Override
protected void onResume() 
     dialog.hide();
     super.onResume();

【讨论】:

【参考方案5】:

您可以考虑使用ActivityManager.addAppTask(Activity, Intent, ActivityManager.TaskDescription, Bitmap) 启动应用程序任务,而不是启动一个活动,您传入的位图将用作概览/最近屏幕中的缩略图。

此 api 上的文档是 here,但是,它仅在 Lollipop 中可用。

【讨论】:

以上是关于需要从 Android“概览屏幕”中隐藏程序内容的主要内容,如果未能解决你的问题,请参考以下文章

Android 屏幕适配屏幕适配通用解决方案 ② ( 自定义组件解决方案 | 需要解决的问题 : 设计稿坐标数据转为屏幕真实坐标数据 | 实现步骤 )

Android 屏幕适配屏幕适配通用解决方案 ② ( 自定义组件解决方案 | 需要解决的问题 : 设计稿坐标数据转为屏幕真实坐标数据 | 实现步骤 )

Android 屏幕适配屏幕适配基础概念 ① ( Android 与 iOS 屏幕宽高比种类 | 屏幕像素密度 DPI )

Android 屏幕适配屏幕适配通用解决方案 ③ ( 自定义组件解决方案 | 获取设备状态栏高度 | 获取设备屏幕数据 )

Android 屏幕适配屏幕适配通用解决方案 ③ ( 自定义组件解决方案 | 获取设备状态栏高度 | 获取设备屏幕数据 )

Android 屏幕适配屏幕适配通用解决方案 ④ ( 自定义组件解决方案 | 计算设计稿与实际布局的比例系数 )