android正常录屏流程需要申请权限,只需要调用正常的api,用户自己点击确定按钮,即可获取到录屏权限,上层app获取录屏权限的流程,废话不多说,下面看代码:

public void takeScreenshot(Activity activity, int width, int height, ScreenshotCallback cb) {this.width = width;this.height = height;this.cb = cb;mMediaProjectionManager = (MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);if (mMediaProjectionManager == null) {return;}activity.startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), MEDIA_PROJECTION_CODE);}

这是申请上层录屏权限的部分,createScreenCaptureIntent()此api就是跳转到MediaProjectionManager中去跳转dialog,引导用户获取权限,然后,底层会给我们返回一个Intent ,intent里面包含的权限信息,我们需要在上层写一个OnactivityForReslut方法用来接收底层给我们的权限信息,代码如下:

/*** This method must be called under the activity's onActivityResult()* @param resultCode resultCode* @param data data*/public void onActivityResult(int resultCode, Intent data) {imageAvailable = 0;mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);if (mMediaProjection == null) {mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);}try {virtualDisplay = mMediaProjection.createVirtualDisplay("Screenshot", width, height, 60,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(), null, null);mImageReader.setOnImageAvailableListener(ScreenShotUtil.this, null);} catch (Exception e) {e.printStackTrace();}}

这段代码解释一下,首先,创建一个ImageReader对象,然后,创建一个虚拟桌面,即virtualDisplay对象,imageReader就来读这个虚拟桌面,获取这个虚拟桌面,然后,我们在要保存的地方调用获取权限的方法,代码如下:

ScreenShotUtil.getInstance().takeScreenshot(activity, getWidth(), getHeight(),new ScreenShotUtil.ScreenshotCallback() {@Overridepublic void onScreenshot(Bitmap bitmap) {FileOutputStream fos = null;try {fos = new FileOutputStream(file);bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));fos.flush();Toast.makeText(getContext(), R.string.save_success, Toast.LENGTH_SHORT).show();} catch (Exception ignored) {Toast.makeText(getContext(), R.string.save_failed, Toast.LENGTH_SHORT).show();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (isExit) {activity.exit();} else {activity.showWriteBottomBar();}isSaving = false;bitmap.recycle();}}});

好了,上层就是这么简单的,那我们来看看底层是怎么实现的这个流程呢?

首先,如果要调用这个录屏权限,前面说道 要获取权限要调用createScreenCaptureIntent()方法,这个方法在哪呢?MediaProjectionManager类在fragment/base/media/android/media/projection中,里面有下面这个方法

/*** Returns an Intent that <b>must</b> passed to startActivityForResult()* in order to start screen capture. The activity will prompt* the user whether to allow screen capture.  The result of this* activity should be passed to getMediaProjection.*/public Intent createScreenCaptureIntent() {Intent i = new Intent();i.setClassName("com.android.systemui","com.android.systemui.media.MediaProjectionPermissionActivity");return i;}

此方法一看就看出来了,这是跳转到MediaProjectionPermissionActivity类中去处理逻辑了,这个类重要的部分其实也不多,无非就是弹了一个dialog,但是,这个类里面有相关服务的创建以及类的传输工作,下面我们就来看看

IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);mService = IMediaProjectionManager.Stub.asInterface(b);

由此,创建了binder通道,并且拿到了Service,当然,MediaProjectionManager本身就是一个service,这个service就是用来为上层赋予权限的。那么创建这两个通道的作用什么呢?

    private Intent getMediaProjectionIntent(int uid, String packageName, boolean permanentGrant)throws RemoteException {IMediaProjection projection = mService.createProjection(uid, packageName,MediaProjectionManager.TYPE_SCREEN_CAPTURE, permanentGrant);Intent intent = new Intent();intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());return intent;}

在这里,通过service来创建一个projection对象,拿到这个对象之后,由binder创建代理对象,统一交给intent来传递出去,intent中的数据总要拿出来处理的,那在哪里处理呢?在ManagerProjectManager中创建的对象,当然在这里面进行结果的处理了,处理的方法如下:

/*** Retrieve the MediaProjection obtained from a succesful screen* capture request. Will be null if the result from the* startActivityForResult() is anything other than RESULT_OK.** @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,* int, android.content.Intent)}* @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,* int, android.content.Intent)}*/public MediaProjection getMediaProjection(int resultCode, @NonNull Intent resultData) {if (resultCode != Activity.RESULT_OK || resultData == null) {return null;}IBinder projection = resultData.getIBinderExtra(EXTRA_MEDIA_PROJECTION);if (projection == null) {return null;}return new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));}

由此可见,这里返回了一个projection对象,这个对象用来干嘛呢?就是我们上面说的,用这个对象来创建一个虚拟的显示桌面,由ImageReader来写入这个虚拟桌面,创建虚拟桌面的方法在哪?由projection对象创建,当然在MediaProjection中,这个类也在media/java/media/projection/包中,这个包中有一个创建虚拟桌面的方法,如下:

   /*** Creates a {@link android.hardware.display.VirtualDisplay} to capture the* contents of the screen.** @param name The name of the virtual display, must be non-empty.* @param width The width of the virtual display in pixels. Must be* greater than 0.* @param height The height of the virtual display in pixels. Must be* greater than 0.* @param dpi The density of the virtual display in dpi. Must be greater* than 0.* @param surface The surface to which the content of the virtual display* should be rendered, or null if there is none initially.* @param flags A combination of virtual display flags. See {@link DisplayManager} for the full* list of flags.* @param callback Callback to call when the virtual display's state* changes, or null if none.* @param handler The {@link android.os.Handler} on which the callback should be* invoked, or null if the callback should be invoked on the calling* thread's main {@link android.os.Looper}.** @see android.hardware.display.VirtualDisplay*/public VirtualDisplay createVirtualDisplay(@NonNull String name,int width, int height, int dpi, int flags, @Nullable Surface surface,@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);return dm.createVirtualDisplay(this, name, width, height, dpi, surface, flags, callback,handler, null /* uniqueId */);}

至此,整个流程已经走完了,说到底,无非就是对象之间的传递,有binder进行c/s之间的权限信息的传递,有的公司可能想要自己定制这一块流程,不想弹这个权限的dialog,首先,如果想要做这个功能就必须有root权限,或者,你能在源码中编译,恰好,我们公司有这个需求,下面的实现方式,解决了不弹窗的问题,直接赋予权限,而不用用户手动点击:

 public void takeScreenshot(Activity activity, int width, int height, ScreenshotCallback cb) {this.width = width;this.height = height;this.cb = cb;int uid;MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);if (mediaProjectionManager == null) {return;} else {String packageName = activity.getPackageName();if (packageName == null) {return;}IBinder b = ServiceManager.getService(activity.MEDIA_PROJECTION_SERVICE);IMediaProjectionManager mService = IMediaProjectionManager.Stub.asInterface(b);PackageManager packageManager = activity.getPackageManager();ApplicationInfo aInfo;try {aInfo = packageManager.getApplicationInfo(packageName, 0);uid = aInfo.uid;IMediaProjection projection = mService.createProjection(uid, packageName,MediaProjectionManager.TYPE_SCREEN_CAPTURE, !mService.hasProjectionPermission(uid, packageName));takeScreen(new MediaProjection(activity, projection));} catch (RemoteException e) {Log.e(TAG, "Error checking projection permissions", e);} catch (PackageManager.NameNotFoundException e) {Log.e(TAG, "unable to look up package name", e);}}}

这样,就可以解决权限问题,当然,在清单文件中必须加上

<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>

这条权限,不然编译不过,因为binder获取service中有这个权限!

大家有不明白的,可以在下面留言,一起学习

android 录屏流程以及权限管理(底层权限修改及讲解)相关推荐

  1. Android录屏应用开发研究

    1截屏接口 在Android5.0之前如果希望截图屏幕,是需要获取系统root权限的.但在Android5.0之后Android开放了新的接口android.media.projection,开发者使 ...

  2. android 屏幕录制方案,Android录屏的三种解决方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  3. android 录屏自动运行,自动化录屏方案简介 for Android

    原标题:自动化录屏方案简介 for Android 前言 针对移动端项目的评测,为了记录并评估产品表现,时常需要对设备进行录屏以作后续分析. 那么,应该如何在Python脚本中可靠.可控地实现安卓设备 ...

  4. android录屏时不截入自定义悬浮框

    前提:使用MediaProjectionManager录屏方案. 问题:会截入自定义悬浮框 解决方案 1.本质上得修改framework层代码surfaceflinger去除悬浮框,在画布中就去除该悬 ...

  5. Android录屏并利用FFmpeg转换成gif(一)录屏

    Android录屏并利用FFmpeg转换成gif(一) 录屏 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲 ...

  6. Android录屏并利用FFmpeg转换成gif(二)交叉编译FFmpeg源码

    Android录屏并利用FFmpeg转换成gif(二) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  7. Android录屏并利用FFmpeg转换成gif(三) 在Android中使用ffmpeg命令

    Android录屏并利用FFmpeg转换成gif(三) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  8. Android录屏分析(Android12源码)

    Android录屏分析 目录 Android录屏分析 prepare方法(准备录制) MediaProjection.MediaRecorder.VirtualDisplay的介绍 开始与结束 缩略图 ...

  9. android 录屏 github,GitHub - mabeijianxi/ScreenRecordPushStream: Android 录屏推流demo

    ScreenRecordPushStream 这是一个基于 rtmp 协议的 Android 录屏推流demo (Demo APK 下载) 使用方法 一. 服务器搭建 mkdir nms cd nms ...

最新文章

  1. Django 全文检索6.3
  2. 无法嵌入互操作类型 请改用适用的接口。
  3. Delphi中多线程用Synchronize实现VCL数据同步显示
  4. 一文看懂谷歌 NYC 算法与优化业务全景:三大项目组12个子领域详解(附重点论文下载)
  5. 使用2to3.py 转换 python2.x 代码 到python3
  6. android游戏开发框架libgdx的使用(十五)—TWL布局
  7. MySQL读写分离详解(一)——基本原理
  8. kernel32.dll动态链接库报错解决方法win7,怎么修复kernel32.dll文件缺失
  9. 【转】win7旗舰版英文版下载(64位|32位)|Windows7英文版ISO镜像
  10. 大气的品牌化妆品官网模板
  11. dbc批量插入、批量删除、批量更新
  12. iPhone十周年撞上华为AI芯片 谁更有看头?
  13. 大数据Hadoop之——Hadoop HDFS多目录磁盘扩展与数据平衡实战操作
  14. Javascript清除IE缓存
  15. 题解2020届天梯赛总决赛L2-4哲哲打游戏
  16. 解决支付宝买家状态非法,无法继续交易 错误码:BUYER_ENABLE_STATUS_FORBID
  17. 概率论—贝叶斯定理 解析
  18. WeLink协作文档,职场的贴心助手
  19. 17、java.lang.UnsatisfiedLinkError: No implementation 处理方法
  20. 4米乘以12米CAD图_新农村路灯4米6米8米12米太阳能路灯led太阳能景观灯

热门文章

  1. 华为欲在澳大利亚建智慧城市
  2. 关于Unity RaycastHit2D 的使用心得
  3. 【pycharm基础设置】
  4. ASP.NET Core 2.0 : 七.一张图看透启动背后的秘密
  5. R语言dplyr包summarise_all函数计算dataframe数据中所有数值数据列的均值和中位数、使用sapply筛选数值数据列(Summarize all Numeric Variables
  6. 微信小程序应用号开发教程!博卡君通宵吐血赶稿
  7. 鸿蒙手机价格多少啊,华为首批鸿蒙手机上线!价格被曝光后,网友:先买为敬!...
  8. mesh(三角面片)数据解析
  9. WIN11右键打开方式没有记事本,记事本无法使用问题
  10. automake生成静态库文件_Automake 详解