Android 截屏 录屏 与获取log

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Android 截屏 录屏 与获取log

1.截屏

1.申请权限

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

2.创建service 拉起媒体服务

public class RecordService extends Service {
 
    public static MediaProjection mMediaProjection;
    MediaProjectionManager mMediaProjectionManager;
    boolean isMediaRecording;
    VirtualDisplay virtualDisplay;
    private MediaRecorder mediaRecorder;
    int width ;
    int height ;
    int dpi ;
    String filePathName;
    public RecordService() {
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
 
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        createNotificationChannel();
        int mResultCode = intent.getIntExtra("code", -1);
        Intent mResultData = intent.getParcelableExtra("data");
        int action = intent.getIntExtra("action", 0);
        width = intent.getIntExtra("width", 0);
        height = intent.getIntExtra("height", 0);
        dpi = intent.getIntExtra("dpi", 0);
 
        Log.e("test",width +"     "+height+"       "+dpi);
        //mResultData = intent.getSelector();
        mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);
        if(action == 0){
            takePhoto();
        }
        else if(action ==1){
            try {
                recordScreen();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
        stopRecording();
    }
 
    private void recordScreen() throws InterruptedException {
        Log.e("test","recordScreen");
        createMediaRecorder();
        //@SuppressLint("WrongConstant") ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3);
        if(virtualDisplay == null){
            virtualDisplay = mMediaProjection.createVirtualDisplay("screen_shot",
                    width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    mediaRecorder.getSurface(), null, null);
        }
       else {
            virtualDisplay.setSurface(mediaRecorder.getSurface());
        }
 
        startRecording();
    }
 
    /**
     * 开始 媒体录制
     *
     *
     */
    public void startRecording() {
        //createMediaRecorder();
        mediaRecorder.start();
        isMediaRecording = true;
    }
 
 
 
    /**
     * 停止 媒体录制
     */
    public void stopRecording() {
        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();
        mediaRecorder = null;
        isMediaRecording = false;
        filePathName = null;
    }
 
 
    private MediaRecorder createMediaRecorder() {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        String filePath=Environment.getExternalStorageDirectory()+"/ScreenVideo/";
        if(!new File(filePath).exists()){
            new File(filePath).mkdirs();
        }
        filePathName= filePath+simpleDateFormat.format(new Date())+".mp4";
        mediaRecorder = new MediaRecorder();
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setOutputFile(filePathName);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setVideoSize(width, height);
        mediaRecorder.setVideoFrameRate(60);
        mediaRecorder.setVideoEncodingBitRate(5 * width * height);
        try{
            mediaRecorder.prepare();
        }catch (Exception e){
            e.printStackTrace();
        }
        return mediaRecorder;
    }
 
    public void takePhoto(){
        @SuppressLint("WrongConstant") ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3);
        mMediaProjection.createVirtualDisplay("screen_shot",
                width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                imageReader.getSurface(), null, null);
        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireNextImage();//获取下一帧截屏,这里可以控制你是否要单个或者直接录屏
                int width = image.getWidth();
                int height = image.getHeight();
                final Image.Plane[] planes = image.getPlanes();
                final ByteBuffer buffer = planes[0].getBuffer();
                int pixelStride = planes[0].getPixelStride();
                int rowStride = planes[0].getRowStride();
                int rowPadding = rowStride - pixelStride * width;
                Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
                bitmap.copyPixelsFromBuffer(buffer);
                if (bitmap != null) {
                    try {
                        // 获取内置SD卡路径
                        String sdCardPath = Environment.getExternalStorageDirectory().getPath();
                        Log.e("test",sdCardPath);
                        // 图片文件路径
                        String filePath = sdCardPath + File.separator + System.currentTimeMillis()+".png";
                        File file = new File(filePath);
                        FileOutputStream fos = new FileOutputStream(file);
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                        fos.flush();
                        fos.close();
                        Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();
                        Log.e("1111111","保存成功");
                        reader.close();
                    } catch (Exception e) {
                        Log.e("test",e.toString());
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "bitmap == null", Toast.LENGTH_SHORT).show();
                }
                image.close();
            }
        }, null);
    }
 
    private void createNotificationChannel() {
        Notification.Builder builder = new Notification.Builder(this.getApplicationContext()); //获取一个Notification构造器
        Intent nfIntent = new Intent(this, MainActivity.class); //点击后跳转的界面,可以设置跳转数据
 
        builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent
                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)
                //.setContentTitle("SMI InstantView") // 设置下拉列表里的标题
                .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
                .setContentText("is running......") // 设置上下文内容
                .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
 
        /*以下是对Android 8.0的适配*/
        //普通notification适配
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId("notification_id");
        }
        //前台服务notification适配
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
            NotificationChannel channel = new NotificationChannel("notification_id", "notification_name", NotificationManager.IMPORTANCE_LOW);
            notificationManager.createNotificationChannel(channel);
        }
 
        Notification notification = builder.build(); // 获取构建好的Notification
        notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
        startForeground(110, notification);
    }
}

3.MainActivity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    Button btn_take,btn_record,btn_log,btn_stopLog;
    MediaProjectionManager mediaProjectionManager;
    int width, height, dpi;
    static int TAKEPHOTO = 0;
    static int RECORDSCREEN = 1;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_record = findViewById(R.id.recordscreen);
        btn_take = findViewById(R.id.takephoto);
        btn_log = findViewById(R.id.getLog);
        btn_stopLog = findViewById(R.id.stopLog);
        getPermission();
        LogUtils logUtils = new LogUtils();
        btn_log.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                logUtils.getLog("logcat");
            }
        });
 
        btn_stopLog.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                logUtils.stopLog();
            }
        });
 
        btn_take.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startScreenShot();
            }
        });
 
        btn_record.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               stopService(new Intent(MainActivity.this,RecordService.class));
            }
        });
    }
 
 
 
    private void startScreenShot() {
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        if (windowManager != null) {
            DisplayMetrics displayMetrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(displayMetrics);
            width = displayMetrics.widthPixels;
            height = displayMetrics.heightPixels;
            dpi = displayMetrics.densityDpi;
            Log.e("test",width +"     "+height+"       "+dpi);
        }
 
 
        mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        if (mediaProjectionManager != null) {
            startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 10086);
        }
    }
 
    /**
     * @param requestCode
     * @param resultCode
     * @param data
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_CANCELED) {
            Log.e(TAG, "User cancel");
        } else {
            Intent service = new Intent(this, RecordService.class);
            service.putExtra("code", resultCode);
            service.putExtra("data", data);
            service.putExtra("action",RECORDSCREEN);
            service.putExtra("width",width);
            service.putExtra("height",height);
            service.putExtra("dpi",dpi);
            startForegroundService(service);
        }
 
 
//        width = 500;
//        height = 500;
//        dpi = 10;
 
 
    }
 
    public void getPermission(){
        try{
            //需要的权限
            String[] permArr={
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,
            };
            boolean needReq = false;
            for(int i=0;i<permArr.length;i++){
                if(ContextCompat.checkSelfPermission(this, permArr[i])!= PackageManager.PERMISSION_GRANTED){
                    needReq = true;
                    break;
                }
            }
            if(needReq)
                ActivityCompat.requestPermissions(this,permArr,1);
        }catch (Exception e){
            Log.w("动态申请权限时,发生异常。",e);
        }
    }
 
 
}

3.LogUtils

 public void getLog(String command){
        new Thread(new Runnable() {
            @Override
            public void run() {
                FileOutputStream os = null;
                Process p = null;
                try {
                    SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
                    Runtime.getRuntime().exec("logcat -c");
                    p = Runtime.getRuntime().exec(command);
                    InputStream is = p.getInputStream();
                    File file = new File(sdCardPath+"/log/"+simpleDateFormat.format(new Date())+".log");
                    if(!file.exists()) {
                        //先得到文件的上级目录,并创建上级目录,在创建文件
                        file.getParentFile().mkdir();
                        try {
                            //创建文件
                            file.createNewFile();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    os = new FileOutputStream(file);
                    int len = 0;
                    byte[] buf = new byte[1024];
                    while ((-1 != (len = is.read(buf)))) {
                        os.write(buf, 0, len);
                    }
                } catch (IOException e) {
                    Log.e("test",e.toString());
                    e.printStackTrace();
                }finally {
                    Log.e("test","finally");
                    try {
                        os.flush();
                        os.close();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
 
                }
            }
        }).start();
    }


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
9月前
|
监控 Android开发 C语言
深度解读Android崩溃日志案例分析2:tombstone日志
深度解读Android崩溃日志案例分析2:tombstone日志
698 0
|
3月前
|
前端开发 数据处理 Android开发
Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍
本文深入探讨了Flutter前端开发中的调试技巧与工具使用方法,涵盖调试的重要性、基本技巧如打印日志与断点调试、常用调试工具如Android Studio/VS Code调试器和Flutter Inspector的介绍,以及具体操作步骤、常见问题解决、高级调试技巧、团队协作中的调试应用和未来发展趋势,旨在帮助开发者提高调试效率,提升应用质量。
89 8
|
4月前
|
存储 Java Android开发
Android|记一个导致 logback 无法输出日志的问题
在给一个 Android 项目添加 logback 日志框架时,遇到一个导致无法正常输出日志的问题,这里记录一下。
77 2
|
4月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
196 1
|
9月前
|
监控 安全 API
orhanobut/logger - 强大的Android日志打印库
orhanobut/logger - 强大的Android日志打印库
396 1
|
9月前
|
Android开发
Android Mediatek 禁用 UART 日志输出
Android Mediatek 禁用 UART 日志输出
133 0
|
9月前
|
存储 缓存 监控
通过bugly日志分析,了解到的Android盲区知识
通过bugly日志分析,了解到的Android盲区知识
220 0
|
网络协议 Android开发 虚拟化
Android Studio无法运行程序调试程序出现Unable to connect to ADB.Check the Event Log for possible issues.Verify th
Android Studio无法运行程序调试程序出现Unable to connect to ADB.Check the Event Log for possible issues.Verify th
121 0
Android Studio无法运行程序调试程序出现Unable to connect to ADB.Check the Event Log for possible issues.Verify th
|
3月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
927 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。

热门文章

最新文章