Android 5.0+ 屏幕錄製實現

前言

Android 從 4.0 開始就提供了手機錄屏方法,可是須要 root 權限,比較麻煩不容易實現。可是從 5.0 開始,系統提供給了 app 錄製屏幕的一系列方法,不須要 root 權限,只須要用戶受權便可錄屏,相對來講較爲簡單。本文是在參考了網絡上其餘錄屏資料後完成的,感謝。如下將介紹開發錄屏功能的一系列步驟以及實現過程當中所遇到的一些須要注意的事項。android

實現步驟

  1. 在清單文件中聲明須要的權限

由於錄製用到麥克風,因此須要加上 AUDIO 權限,git

<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"/>
複製代碼

若是開發的 app targetApi 在 6.0 以上時,還須要動態獲取權限。github

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);
                return;
            } else {
                return;
            }
        }
        return;
    }
    
複製代碼
  1. 獲取用戶錄製屏幕受權

這裏先介紹 MediaProjectionManager , MediaProjectionManager 是系統提供的一種服務,當咱們拿到這個服務對象,能夠建立一個 Intent ,經過這個 Intent 能夠啓動一個彈框樣式的 Activity,若是用戶受權了,那咱們即可以繼續下一步屏幕錄製。須要說明的是,Intent 是去啓動另外一個 Activity 的,有極少極少的機型是沒有對應的受權Activity 的,因此這裏須要多加判斷,防止應用奔潰。網絡

MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.
                            getSystemService(Context.MEDIA_PROJECTION_SERVICE);
                    if (mediaProjectionManager != null){
                        Intent intent = mediaProjectionManager.createScreenCaptureIntent();
                        PackageManager packageManager = activity.getPackageManager();
                        if (packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null){
                            //存在錄屏受權的Activity 
                            activity.startActivityForResult(intent,requestCode);
                        }else {
                            Toast.makeText(activity,R.string.can_not_record_tip,Toast.LENGTH_SHORT).show();
                        }
                    }

複製代碼
  1. 在 onActivityResult 對用戶的受權作處理

即便用戶受權了,贊成錄製操做,仍然須要捕獲異常,由於有可能會出現這樣一種狀況,就是用戶在贊成錄屏的時候系統也正在錄屏,錄屏操做衝突了。app

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK){
            try {
                ScreenUtil.setUpData(resultCode,data);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            ToastUtil.show(this,"拒絕錄屏");
        }
    }
複製代碼
  1. 初始化 MediaRecorder、建立 VirtualDisplay
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void setUpMediaRecorder() {

        mRecordFilePath = getSaveDirectory()  + File.separator+  System.currentTimeMillis() + ".mp4";
        if (mMediaRecorder == null){
            mMediaRecorder = new MediaRecorder();
        }
        //設置音頻來源
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //設置視頻來源
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        //輸出的錄屏文件格式
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        //錄屏文件路徑
        mMediaRecorder.setOutputFile( mRecordFilePath );
        //視頻尺寸
        mMediaRecorder.setVideoSize(mRecordWidth, mRecordHeight);
        //音視頻編碼器
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        //比特率
        mMediaRecorder.setVideoEncodingBitRate((int) (mRecordWidth * mRecordHeight * 3.6));
        //視頻幀率
        mMediaRecorder.setVideoFrameRate(20);

        try {
            mMediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
複製代碼

這一步是整個錄屏操做最爲關鍵的一步!咱們初始化了 MediaRecorder,設置了是否錄上聲音、錄屏文件格式、錄屏文件路徑、音視頻的編碼器、比特率、視頻幀率等 而後將在步驟 3 中的 resultCode 以及 data 做爲必要的參數經過 MediaProjectionManager 建立 VirtualDisplay。VirtualDisplay 能夠理解爲虛擬的呈現器,它能夠捕獲屏幕上的內容,並將其捕獲的內容渲染到 Surface 上(Surace 由 MediaRecorder 提供,經過 getSurface() 方法獲得),MediaRecorder 再進一步將其封裝處理爲 Mp4 文件。ide

通過以上步驟 prepare 以後,當再次調用 MediaRecorder.start() 就能夠開始錄屏了,這裏贊成也須要注意的時,調用 start() 方法開始錄屏以後,不能當即調用 stop()方法中止錄屏,不然會奔潰。測試在測試錄屏功能時立馬中止錄屏,應用奔潰,一直找不到緣由。直到看到了源碼( API 26 )裏的註釋測試

因此爲了反正奔潰,在 stop 的時候捕獲異常,而且置空 MediaRecorder,下次錄屏的時候再從新生成 MediaRecorder。

最後

因爲知識水平有限,不免有錯誤遺漏,歡迎指正!項目地址爲 屏幕錄製ui

相關文章
相關標籤/搜索