两个类实现Android录制屏幕功能

一、申请权限


  • AndroidManifest配置

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

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

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





  • Android6.0后的动态权限

public static void checkPermission(AppCompatActivity activity) {

        if (Build.VERSION.SDK_INT >= 23) {

            int checkPermission =

                    ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);

            if (checkPermission != PackageManager.PERMISSION_GRANTED) {

                //动态申请

                ActivityCompat.requestPermissions(activity, new String[]{

                        Manifest.permission.RECORD_AUDIO,

                        Manifest.permission.READ_PHONE_STATE,

                        Manifest.permission.READ_EXTERNAL_STORAGE,

                        Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);

            }

        }

    }





二、申请允许录制屏幕


  1. 检查权限

  2. 初始化MediaProjectionManager

  3. 申请录制屏幕,会出现提示屏幕录制的系统弹窗

  4. onActivityResult拿到是否允许的结果

  5. 在结果成功时开启Service进行录制屏幕

该类代码如下


import android.Manifest;

import android.app.Activity;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.media.projection.MediaProjectionManager;

import android.os.Build;

import android.support.v4.app.ActivityCompat;

import android.support.v4.content.ContextCompat;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.Toast;



import com.screen.recorder.demo.service.ScreenRecordService;



/**

 * @author by talon, Date on 19/6/23.

 * note:

 */

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE = 1;

    private MediaProjectionManager mMediaProjectionManager;



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);



        checkPermission(this); //检查权限



        mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);

    }



    public void StartRecorder(View view) {

        createScreenCapture();

    }



    public void StopRecorder(View view){

        Intent service = new Intent(this, ScreenRecordService.class);

        stopService(service);

    }





    public static void checkPermission(AppCompatActivity activity) {

        if (Build.VERSION.SDK_INT >= 23) {

            int checkPermission =

                    ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)

                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);

            if (checkPermission != PackageManager.PERMISSION_GRANTED) {

                //动态申请

                ActivityCompat.requestPermissions(activity, new String[]{

                        Manifest.permission.RECORD_AUDIO,

                        Manifest.permission.READ_PHONE_STATE,

                        Manifest.permission.READ_EXTERNAL_STORAGE,

                        Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);

            }

        }

    }





    private void createScreenCapture() {

        Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();

        startActivityForResult(captureIntent, REQUEST_CODE);

    }





    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {

            try {

                Toast.makeText(this, "允许录屏", Toast.LENGTH_SHORT).show();



                Intent service = new Intent(this, ScreenRecordService.class);

                service.putExtra("resultCode", resultCode);

                service.putExtra("data", data);

                startService(service);



            } catch (Exception e) {

                e.printStackTrace();

            }

        } else {

            Toast.makeText(this, "拒绝录屏", Toast.LENGTH_SHORT).show();

        }

    }



}



对应的视图代码如下


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity">



    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="开始录制"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent"

        android:onClick="StartRecorder"/>





    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="停止录制"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintLeft_toLeftOf="parent"

        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintTop_toTopOf="parent"

        android:onClick="StopRecorder"/>



</LinearLayout>



三、进行录制屏幕


  1. 拿到传递由onActivityResult回调产生的resultCodedata

  2. 获取手机屏幕的宽高与dpi

  3. 创建MediaProjection MediaRecorder VirtualDisplay

  4. createMediaRecorder方法中配置保存视频的信息,文件的路径、文件名、清晰度等

该类代码如下


import android.app.Service;

import android.content.Context;

import android.content.Intent;

import android.hardware.display.DisplayManager;

import android.hardware.display.VirtualDisplay;

import android.media.MediaRecorder;

import android.media.projection.MediaProjection;

import android.media.projection.MediaProjectionManager;

import android.os.Environment;

import android.os.IBinder;

import android.util.Log;



import com.screen.recorder.demo.utils.ScreenUtils;



import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;



/**

 * @author by talon, Date on 19/6/23.

 * note:

 */

public class ScreenRecordService extends Service {



    private final String TAG = "ScreenRecordService";



    /**

     * 是否为标清视频

     */

    private boolean isVideoSd = false;



    private int mScreenWidth;

    private int mScreenHeight;



#### 《设计思想解读开源框架》

![](https://img-blog.csdnimg.cn/img_convert/ed4d9b1f3d75e762062ac21e3e09884f.webp?x-oss-process=image/format,png)

**第一章、 热修复设计**

* **第一节、 AOT/JIT & dexopt 与 dex2oat**

* **第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题**

* **第三节、热修复设计之热修复原理**

* **第四节、Tinker 的集成与使用(自动补丁包生成)**

  ![](https://img-blog.csdnimg.cn/img_convert/3255019c54a8c29e787ecf847cc117fc.webp?x-oss-process=image/format,png)

  **第二章、 插件化框架设计**

* **第一节、 Class 文件与 Dex 文件的结构解读**

* **第二节、 Android 资源加载机制详解**

* **第三节、 四大组件调用原理**

* **第四节、 so 文件加载机制**

* **第五节、 Android 系统服务实现原理**

  ![](https://img-blog.csdnimg.cn/img_convert/eab00c4b05ae36c86bca802e8f27a0d3.webp?x-oss-process=image/format,png)

  **第三章、 组件化框架设计**

* **第一节、阿里巴巴开源路由框——ARouter 原理分析**

* **第二节、APT 编译时期自动生成代码&动态类加载**

* **第三节、 Java SPI 机制**

* **第四节、 AOP&IOC**

* **第五节、 手写组件化架构**

  ![](https://img-blog.csdnimg.cn/img_convert/11c3d3977b6a535083773c88511b75dc.webp?x-oss-process=image/format,png)

  **第四章、图片加载框架**

* **第一节、图片加载框架选型**

* **第二节、Glide 原理分析**

* **第三节、手写图片加载框架实战**

  ![](https://img-blog.csdnimg.cn/img_convert/becef8c146e2939fbf9cb573f5761feb.webp?x-oss-process=image/format,png)

  **第五章、网络访问框架设计**

* **第一节、网络通信必备基础**

* **第二节、OkHttp 源码解读**

* **第三节、Retrofit 源码解析**

  ![](https://img-blog.csdnimg.cn/img_convert/9dc9e536d09bf41a4472f824027c438a.webp?x-oss-process=image/format,png)

  **第六章、 RXJava 响应式编程框架设计**

* **第一节、链式调用**

* **第二节、 扩展的观察者模式**

* **第三节、事件变换设计**

* **第四节、Scheduler 线程控制**

  ![](https://img-blog.csdnimg.cn/img_convert/a41988cae7cae57db0b2f1e2542b8d2b.webp?x-oss-process=image/format,png)

  **第七章、 IOC 架构设计**

* **第一节、 依赖注入与控制反转**

* **第二节、ButterKnife 原理上篇、中篇、下篇**

* **第三节、Dagger 架构设计核心解密**

  ![](https://img-blog.csdnimg.cn/img_convert/f4093d13438eca00431b8950a4b9c7b1.webp?x-oss-process=image/format,png)

  **第八章、 Android 架构组件 Jetpack**

* **第一节、 LiveData 原理**

* **第二节、 Navigation 如何解决 tabLayout 问题**

* **第三节、 ViewModel 如何感知 View 生命周期及内核原理**

* **第四节、 Room 架构方式方法**

* **第五节、 dataBinding 为什么能够支持 MVVM**

* **第六节、 WorkManager 内核揭秘**

* **第七节、 Lifecycles 生命周期**

  ![](https://img-blog.csdnimg.cn/img_convert/b7f41a18fec8a024323b7002b8e9f3ec.webp?x-oss-process=image/format,png)
  **本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…**
  ![](https://img-blog.csdnimg.cn/img_convert/1423eba16440055ebcdf38e0e5c9f01f.webp?x-oss-process=image/format,png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

*

* **第三节、 ViewModel 如何感知 View 生命周期及内核原理**

* **第四节、 Room 架构方式方法**

* **第五节、 dataBinding 为什么能够支持 MVVM**

* **第六节、 WorkManager 内核揭秘**

* **第七节、 Lifecycles 生命周期**

  [外链图片转存中...(img-ZtkBBsin-1714553298990)]
  **本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…**
  [外链图片转存中...(img-sFPeOnLZ-1714553298990)]



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值