屏幕叠加检测到阻止Android权限

ale*_*mix 42 permissions android oneplusthree

我注意到我的新手机上的Android应用程序存在一个奇怪的问题.SDK 23权限弹出窗口(如外部存储)将被下面附加的警报阻止.我最初认为这与我的手机有关,但它似乎并没有影响我的任何其他安装的应用程序.

这个问题可能与安装调试版本有关,还是我的权限处理有问题?我认为它可能与我正在使用的其中一个广告平台有关但我尝试禁用它们仍然出现了

在此输入图像描述

我已经粘贴了下面生成此权限请求的图像保存功能.我正在使用Dexter来编写一大堆可怕的样板文件

public static void saveToExternalStorageIfAllowed(final Context context, final Bitmap bitmapImage, final String title) {
    final Tracker t = ((LoLHistory) context.getApplicationContext()).getTracker(LoLHistory.TrackerName.APP_TRACKER);

    // saving to publicly visible/accessible folder. Requires write permission
    int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        // do not have permissions to write, request
        t.send(new HitBuilders.EventBuilder()
                .setCategory("FILE")
                .setAction("PermissionMissing")
                .setLabel("WRITE_EXTERNAL")
                .build());
        Dexter.checkPermission(new PermissionListener() {
            @Override
            public void onPermissionGranted(PermissionGrantedResponse response) {
                t.send(new HitBuilders.EventBuilder()
                        .setCategory("FILE")
                        .setAction("PermissionGranted")
                        .setLabel("WRITE_EXTERNAL")
                        .build());

                saveToExternalStorage(context, bitmapImage, title);
            }

            @Override
            public void onPermissionDenied(PermissionDeniedResponse response) {
                t.send(new HitBuilders.EventBuilder()
                        .setCategory("FILE")
                        .setAction("PermissionDenied")
                        .setLabel("WRITE_EXTERNAL")
                        .build());
            }

            @Override
            public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {/* ... */}
        }, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    } else {
        saveToExternalStorage(context, bitmapImage, title);
    }
}

private static void saveToExternalStorage(Context context, Bitmap bitmapImage, String title) {
    Tracker t = ((LoLHistory) context.getApplicationContext()).getTracker(LoLHistory.TrackerName.APP_TRACKER);

    // create image folder if does not exist
    File imagesFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), context.getString(R.string.app_name));
    if (!imagesFolder.mkdirs() && !imagesFolder.isDirectory()) {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // failed to create and is not a directory. Something went wrong...
            t.send(new HitBuilders.EventBuilder()
                    .setCategory("FILE")
                    .setAction("CreateDirFailed")
                    .setLabel(imagesFolder.getPath())
                    .build());
        } else {
            t.send(new HitBuilders.EventBuilder()
                    .setCategory("FILE")
                    .setAction("CreateDirFailedMediaNotMounted")
                    .setLabel(imagesFolder.getPath())
                    .build());
        }
    }

    // delete image if already exists so FOS can create a new one
    File image = new File(imagesFolder, title + ".jpg");
    if (image.exists()) {
        // image already exists, deleting to start from clean state
        if (!image.delete()) {
            // failed to delete
            t.send(new HitBuilders.EventBuilder()
                    .setCategory("FILE")
                    .setAction("DeleteFailed")
                    .setLabel(image.getPath())
                    .build());
        }
    }

    // compress bitmap and write to file stream. FOS creates file if does not exist
    FileOutputStream out = null;
    try {
        out = new FileOutputStream(image);
        bitmapImage.compress(Bitmap.CompressFormat.JPEG, 50, out);
        out.flush();
    } catch (Exception e) {
        e.printStackTrace();
        t.send(new HitBuilders.ExceptionBuilder()
                .setDescription(e.getLocalizedMessage())
                .setFatal(true)
                .build());
    } finally {
        try {
            if (out != null) {
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            t.send(new HitBuilders.ExceptionBuilder()
                    .setDescription(e.getLocalizedMessage())
                    .setFatal(true)
                    .build());
        }
    }

    // get Uri from saved image
    Uri uriSavedImage = Uri.fromFile(image);

    // media scan the new file so it shows up in the gallery
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    mediaScanIntent.setData(uriSavedImage);
    context.sendBroadcast(mediaScanIntent);
}
Run Code Online (Sandbox Code Playgroud)

更新:由于很多人都提到它,如前所述,这个问题不是因为安装了覆盖应用程序.在Draw over其他应用程序菜单下,我有以下应用程序:Google Play音乐,Google Play服务,照片,TalkBack,Twitch,Twitter.所有这些都设置为否.

此外,我还测试了其他应用程序,例如Google Hangouts和Twitter,这些应用程序也有需要危险权限的操作,我可以在没有此问题的情况下提供这些权限.


解决方案:我已经将R. Zagorski的答案标记为解决方案,因为它包含了很多一般情况.对我来说,这实际上是一个Toast破坏我的权限流.这个弹出窗口浪费了很多时间,让我走上了完全错误的道路......

这是Toast我在权限弹出窗口出现后的前几秒看到的:

在此输入图像描述

R. *_*ski 53

此弹出窗口是由清单声明的manifest.PERMISSION.SYSTEM_ALERT_WINDOW权限引起的.这三种权限是开发人员必须注意的:

  1. 正常权限 - 对它们不做任何事情,只需在Manifest中声明
  2. 易受攻击的权限 - 在Manifest中声明并在第一时间获得许可.可以通过系统设置更改它们
  3. 以上危险权限:SYSTEM_ALERT_WINDOWWRITE_SETTINGS属于此类别.必须授予它们,但在系统设置中不可见.要求它你不使用标准方式(int checkSelfPermission (String permission))但你必须检查Settings.canDrawOverlays()Settings.System.canWrite()适当

如果您没有SYSTEM_ALERT_WINDOW权限:

  1. 检查Toast在与权限弹出窗口交互时是否可见.虽然Overlay Detected弹出窗口没有提到它,但它Toast也算作叠加层
  2. 检查您的任何依赖项是否需要它.

如果您不确定是否使用此权限,则可以执行以下几个测试用例:

  1. 请自行申请此权限:

    public class MainActivity extends AppCompatActivity {
    
        public final static int REQUEST_CODE = 10101;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (checkDrawOverlayPermission()) {
                startService(new Intent(this, PowerButtonService.class));
            }
        }
    
        public boolean checkDrawOverlayPermission() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return true;
            }
            if (!Settings.canDrawOverlays(this)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, REQUEST_CODE);
                return false;
            } else {
                return true;
            }
        }
    
        @Override
        @TargetApi(Build.VERSION_CODES.M)
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == REQUEST_CODE) {
                if (Settings.canDrawOverlays(this)) {
                    startService(new Intent(this, PowerButtonService.class));
                }
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 检查这个是不是你的情况下,

  3. 看看这篇文章要注意,当通过Play商店安装app时,会自动授予此权限(我没有检查过,因此无法确认)

可以理解权限模型,有时需要更多挖掘.

  • 祝酒?严重Android?由于你内置的便利通知系统,事情正在破碎!?!??!?! (8认同)
  • 这个问题是由Toast引起的.这个弹出窗口让我走上了完全错误的轨道......如果当你尝试与权限弹出窗口进行交互时看到"Toast",你会看到这个叠加检测到弹出窗口... Android,为什么? (3认同)
  • 一个非常不寻常的案例 实际上,在查看"Toast"源代码时:[第1行](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/Toast.java#408 )和[第2行](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/Toast.java#432),`Toast`视图被固定到在应用程序或活动上下文上调用的全局`WindowManager`.我原以为没想过,简单的"Toast"可能会导致这样的问题. (3认同)

Ahm*_*yed 9

这不是问题,你只需安装一个覆盖应用程序,最常见的是

  • Facebook Messenger
  • Whatsapp启用了弹出窗口
  • 再见聊天头
  • Viber的
  • 任何在屏幕上显示菜单或其他内容的应用都是叠加应用.

关闭它,然后试试.

  • 而且...简直就是土司吐司!这就是我的情况。 (2认同)