这里使用Java语言编写实现,完整代码如下:
文件 AndroidMainfest.xml 的主要配置
- "1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.demoapp">
-
-
- <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" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
-
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true">
- <activity
- android:name=".MainActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- intent-filter>
- activity>
-
-
- <activity
- android:name=".ScreenRecordingActivity"
- android:exported="false"
- android:launchMode="singleTask">activity>
-
- <service
- android:name=".ScreenRecordingService"
- android:enabled="true"
- android:exported="true"
- android:foregroundServiceType="mediaProjection" />
- application>
-
- manifest>
文件activity_screen_recording.xml的内容
- "1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout 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"
- android:orientation="vertical"
- tools:context=".MainActivity"
- tools:ignore="MissingConstraints">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingTop="0dp">
-
-
-
-
- <TextView
- android:id="@+id/textview_recording_info"
- android:layout_width="wrap_content"
- android:layout_height="100dp"
- android:layout_marginTop="20dp"
- android:layout_gravity="center"
- android:textColor="#333333"
- android:textSize="20sp"
- android:textStyle="bold"
- android:text="--"
- android:maxLines="5" />
-
- <Button
- android:id="@+id/btn_recording_start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="40dp"
- android:text="开始录制" />
-
- <Button
- android:id="@+id/btn_recording_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="40dp"
- android:text="停止录制" />
- LinearLayout>
-
- androidx.constraintlayout.widget.ConstraintLayout>
文件ScreenRecordingActivity.java的完整代码
- package com.example.demoapp;
-
- import android.Manifest;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.content.pm.PackageManager;
- import android.media.projection.MediaProjectionManager;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.util.DisplayMetrics;
- import android.view.MenuItem;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
-
- import androidx.activity.result.ActivityResultLauncher;
- import androidx.activity.result.contract.ActivityResultContracts;
- import androidx.annotation.NonNull;
- import androidx.annotation.Nullable;
- import androidx.appcompat.app.ActionBar;
- import androidx.appcompat.app.AppCompatActivity;
- import androidx.core.app.ActivityCompat;
- import androidx.core.content.ContextCompat;
-
- import com.example.myandroidnfcapp.R;
-
- /**
- * @Function: 屏幕录制视频。
- * @Author: ChengJh。
- * @Date: 2023/09/06。
- * @Description: https://blog.csdn.net/qq_46546793/article/details/123279152 和 https://blog.csdn.net/weixin_42602900/article/details/128340037 。
- */
- public class ScreenRecordingActivity extends AppCompatActivity {
- private static final String TAG = ScreenRecordingActivity.class.getSimpleName();
-
- //录屏服务
- private ScreenRecordingService mService;
- private int mServiceStatus = ScreenRecordingService.statusInit;
- private boolean clickedStart = false;
- private ActivityResultLauncher activityLauncher;
-
- private TextView textViewInfo;
-
- private boolean prepared = false;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_screen_recording);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setHomeButtonEnabled(true);
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setTitle("录屏管理页面");
- }
-
- textViewInfo = findViewById(R.id.textview_recording_info);
-
- Button btnStart = (Button) findViewById(R.id.btn_recording_start);
- btnStart.setOnClickListener(view -> {
- startRecord();
- });
-
- Button btnStop = (Button) findViewById(R.id.btn_recording_stop);
- btnStop.setOnClickListener(view -> {
- stopRecord();
- });
-
- //注: registerForActivityResult()方法, 只能在onCreate()中注册, onStart()之后就不能注册了。。
- activityLauncher = registerForActivityResult(
- new ActivityResultContracts.StartActivityForResult(), o -> {
- System.out.println(TAG + "_registerForActivityResult_callback_" + o.getResultCode());
- if (o.getResultCode() == Activity.RESULT_OK) {
- actionAfterConfirmAgreed(o.getResultCode(), o.getData());
- }
- });
- }
-
- @Override
- public void onStart() {
- super.onStart();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- /** 在Activity的六个核心回调 onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy() 中,
- * onStart()、onResume()、onPause()、onStop() 会在 onRestart() 之后再次触发。
- * 因此, 有的任务如果放在其中某个函数内触发, 可能需要加个标记变量控制一下。
- */
- if (!prepared) {
- prepared = true;
- checkPermission();
- }
- }
-
- @Override
- public void onDestroy() {
- /** 页面销毁的时候, 可以不停止录屏 */
- // stopRecord();
- if (mServiceStatus >= ScreenRecordingService.statusServiceConnected) {
- unbindService(serviceConnection);
- }
- super.onDestroy();
- }
-
- // 标题栏返回按钮事件。
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- //this.finish();
- this.onBackPressed();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- // @Override
- // //返回方法, 获取返回的信息。
- // protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
- // super.onActivityResult(requestCode, resultCode, data);
- // System.out.println(TAG + "_onActivityResult");
- // //首先判断请求码是否一致, 结果是否ok 。
- // if (requestCode == ScreenRecordingService.requestCode && resultCode == RESULT_OK) {
- // actionAfterUserAgree(resultCode, data);
- // }
- // }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
- grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- System.out.println(TAG + "_onRequestPermissionsResult");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && requestCode == ScreenRecordingService.requestCodeForPermisssion) {
- for (int i = 0; i < permissions.length; i++) {
- if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- }
- connectService();
- }
- }
-
- /**
- * 权限申请
- */
- private void checkPermission() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- String[] permissions = new String[]{
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_EXTERNAL_STORAGE
- };
- for (String permission : permissions) {
- if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(this, permissions, ScreenRecordingService.requestCodeForPermisssion);
- return;
- }
- }
- }
-
- connectService();
- }
-
- //连接服务。
- public void connectService() {
- System.out.println(TAG + "_connectService");
- //通过intent为中介绑定Service, 会自动创建。
- Intent intent = new Intent(this, ScreenRecordingService.class);
- //绑定过程连接, 选择绑定模式。
- bindService(intent, serviceConnection, BIND_AUTO_CREATE);
- }
-
- //连接服务成功与否, 具体连接过程。
- //调用连接接口, 实现连接, 回调连接结果。
- private final ServiceConnection serviceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
- System.out.println(TAG + "_ServiceConnection_onServiceConnected");
- //服务连接成功, 需要通过Binder获取服务, 达到Activity和Service通信的目的
- ScreenRecordingService.ScreenRecordBinder binder = (ScreenRecordingService.ScreenRecordBinder) iBinder;
- //通过Binder获取Service
- mService = binder.getScreenRecordService();
- mService.setListener(new ScreenRecordingService.ScreenRecordingServiceListener() {
- @Override
- public void onPrepareComplete() {
- if (clickedStart && mService.startRecord()) {
- textViewInfo.setText("正在录屏");
- }
- }
-
- @Override
- public void onRecordingFinish(String videoPath) {
- textViewInfo.setText("视频文件路径: " + videoPath);
- }
- });
- if (mService.isRunning()) {
- System.out.println(TAG + "_ServiceConnection_RunAlready");
- mServiceStatus = ScreenRecordingService.statusConfirmAgreed;
- textViewInfo.setText("正在录屏");
- if (clickedStart) {
- Toast.makeText(ScreenRecordingActivity.this, "已在录屏服务中", Toast.LENGTH_SHORT).show();
- }
- return;
- }
- mServiceStatus = ScreenRecordingService.statusServiceConnected;
- if (clickedStart) {
- actionAfterServiceConnected();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- //连接失败。
- Toast.makeText(ScreenRecordingActivity.this, "录屏服务未连接成功", Toast.LENGTH_SHORT).show();
- }
- };
-
- private void actionAfterConfirmAgreed(int resultCode, @Nullable Intent data) {
- mServiceStatus = ScreenRecordingService.statusConfirmAgreed;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- if (mService != null) {
- //获取录屏屏幕范围参数。
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- mService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
-
- Intent intent = new Intent(this, ScreenRecordingService.class);
- intent.putExtra("code", resultCode);
- intent.putExtra("data", data);
- startForegroundService(intent);
- } else {
- System.out.println(TAG + "_onActivityResult_exception");
- }
- }
- }
-
- private void actionAfterServiceConnected() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- //获取到服务, 初始化录屏管理者。
- MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
- //通过管理者, 创建录屏请求, 通过Intent。
- Intent captureIntent = projectionManager.createScreenCaptureIntent();
- //将请求码作为标识一起发送, 调用该接口, 需有返回方法。
- //startActivityForResult(captureIntent, ScreenRecordingService.requestCode);
- activityLauncher.launch(captureIntent);
- }
- }
-
- private void nextActionByStatus() {
- switch (mServiceStatus) {
- case ScreenRecordingService.statusInit:
- //点击请求录屏时, 第一件事, 检查权限。
- checkPermission();
- break;
- case ScreenRecordingService.statusPermissionOK:
- connectService();
- break;
- case ScreenRecordingService.statusServiceConnected:
- actionAfterServiceConnected();
- break;
- default:
- if (mService != null) {
- if (mService.startRecord()) {
- textViewInfo.setText("正在录屏");
- }
- }
- break;
- }
- }
-
- private void startRecord() {
- System.out.println(TAG + "_startRecord_" + (null == mService));
- clickedStart = true;
- if (mService != null && mService.isRunning()) {
- //如果在录制, 弹出提示。
- Toast.makeText(ScreenRecordingActivity.this, "当前正在录屏, 请不要重复点击哦", Toast.LENGTH_SHORT).show();
- } else {
- //如果不在录制, 就开启录制。
- nextActionByStatus();
- }
- }
-
- private void stopRecord() {
- clickedStart = false;
- if (null == mService || !mService.isRunning()) {
- //没有录屏, 无需停止, 弹出提示。
- Toast.makeText(ScreenRecordingActivity.this, "还没有录屏, 无需停止", Toast.LENGTH_SHORT).show();
- } else {
- //停止录屏。
- mService.stopRecord();
- }
- }
-
- }
文件 ScreenRecordingService.java 的完整代码
- package com.example.demoapp;
-
- import android.app.Notification;
- import android.app.NotificationChannel;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.app.Service;
- import android.content.Intent;
- import android.graphics.BitmapFactory;
- 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.Binder;
- import android.os.Build;
- import android.os.Environment;
- import android.os.IBinder;
- import android.util.Log;
- import android.widget.Toast;
-
- import androidx.annotation.Nullable;
-
- import com.example.myandroidnfcapp.MainActivity;
- import com.example.myandroidnfcapp.R;
-
- import java.io.File;
- import java.io.IOException;
- import java.util.Objects;
-
- public class ScreenRecordingService extends Service {
- private static final String TAG = ScreenRecordingService.class.getSimpleName();
-
- public static final int statusInit = 0;
- public static final int statusPermissionOK = 1;
- public static final int statusServiceConnected = 2;
- public static final int statusConfirmAgreed = 3;
-
- public static final int requestCodeForPermisssion = 110;
- public static final int requestCode = 111;
-
- private MediaProjectionManager mediaProjectionManager;
- //录屏工具MediaProjection。
- private MediaProjection mediaProjection;
- //录像机MediaRecorder。
- private MediaRecorder mediaRecorder;
- //用于录屏的虚拟屏幕。
- private VirtualDisplay virtualDisplay;
- //录制屏幕的宽高像素。
- private int mWidth = 720;
- private int mHeight = 1280;
- private int mDpi = 1;
- //视频存储路径
- private String mVideoPath = "";
- //标志, 判断是否正在录屏
- private boolean running = false;
-
- //回调接口, 以及接口中要做的事。
- public interface ScreenRecordingServiceListener {
- void onPrepareComplete();
-
- void onRecordingFinish(String videoPath);
- }
-
- private ScreenRecordingServiceListener listener;
-
- @Override
- public void onCreate() {
- super.onCreate();
- // HandlerThread serviceThread = new HandlerThread("service_thread", android.os.Process.THREAD_PRIORITY_BACKGROUND);
- // serviceThread.start();
- // running = false;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- // 注: mediaProjection的生成 必须在Service中进行。
- createNotificationChannel();
-
- int resultCode = intent.getIntExtra("code", -1);
- Intent resultData = intent.getParcelableExtra("data");
- Log.i(TAG, "onStartCommand_resultCode=" + resultCode);
- Log.i(TAG, "onStartCommand_resultData=" + resultData);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- if (null == mediaProjectionManager) {
- mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
- }
- mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, Objects.requireNonNull(resultData));
- //mediaProjection = ((MediaProjectionManager) Objects.requireNonNull(getSystemService(Context.MEDIA_PROJECTION_SERVICE))).getMediaProjection(resultCode, resultData);
- Log.i(TAG, "mediaProjection_created");
- }
-
- if (listener != null) {
- listener.onPrepareComplete();
- }
-
- return super.onStartCommand(intent, flags, startId);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public boolean onUnbind(Intent intent) {
- return super.onUnbind(intent);
- }
-
- //返回的Binder。
- public class ScreenRecordBinder extends Binder {
- //返回Service的方法。
- public ScreenRecordingService getScreenRecordService() {
- return ScreenRecordingService.this;
- }
- }
-
- @Nullable
- @Override
- //返回一个Binder用于通信, 需要一个获取Service的方法。
- public IBinder onBind(Intent intent) {
- return new ScreenRecordBinder();
- }
-
- //设置需要录制的屏幕参数。
- public void setConfig(int width, int height, int dpi) {
- mWidth = width;
- mHeight = height;
- mDpi = dpi;
- }
-
- public void setMediaProjectionManager(MediaProjectionManager projectionManager) {
- mediaProjectionManager = projectionManager;
- }
-
- public void setListener(ScreenRecordingServiceListener callback) {
- listener = callback;
- }
-
- //返回判断, 判断其是否在录屏。
- public boolean isRunning() {
- return running;
- }
-
- //服务的两个主要逻辑之一 ~ 开始录屏。
- public boolean startRecord() {
- Log.i(TAG, "startRecord");
- //首先判断是否有录屏工具以及是否在录屏
- if (null == mediaProjection || running) {
- return false;
- }
- //初始化录像机, 录音机Recorder。
- createRecorder();
- //根据获取的屏幕参数创建虚拟的录屏屏幕。
- createVirtualDisplay();
- //本来不加异常也可以, 但是这样就不知道是否start成功。
- //万一start没有成功, 但是running置为true了, 就产生了错误也无提示。
- //提示开始录屏了, 但是并没有工作。
- try {
- //准备工作都完成了, 可以开始录屏了。
- mediaRecorder.start();
- //标志位改为正在录屏。
- running = true;
- Toast.makeText(this, "录屏开启成功", Toast.LENGTH_SHORT).show();
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- //有异常, start出错, 没有开始录屏。
- Toast.makeText(this, "录屏开启失败", Toast.LENGTH_SHORT).show();
- //标志位变回没有录屏的状态。
- running = false;
- return false;
- }
- }
-
- //服务的两个主要逻辑之一 ~ 停止录屏。
- public boolean stopRecord() {
- Log.i(TAG, "stopRecord");
- if (!running) {
- //没有在录屏, 无法停止。
- return false;
- }
- //无论设备是否还原或者有异常, 但是确实录屏结束, 修改标志位为未录屏。
- running = false;
- //本来加不加捕获异常都可以, 但是为了用户体验度, 添加会更好。
- try {
- //Recorder停止录像, 重置还原, 以便下一次使用。
- mediaRecorder.stop();
- mediaRecorder.reset();
- //释放virtualDisplay的资源。
- virtualDisplay.release();
- } catch (Exception e) {
- e.printStackTrace();
- //有异常, 保存失败。
- Toast.makeText(this, "录屏结束异常", Toast.LENGTH_SHORT).show();
- return false;
- }
- //无异常, 保存成功。
- Toast.makeText(this, "录屏结束 而且 保存成功", Toast.LENGTH_SHORT).show();
- if (listener != null) {
- listener.onRecordingFinish(mVideoPath);
- }
- return true;
- }
-
- //初始化Recorder录像机。
- public void createRecorder() {
- Log.i(TAG, "createRecorder");
- //创建Recorder。
- mediaRecorder = new MediaRecorder();
- //设置音频来源。
- mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- //设置视频来源。
- mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
- //设置视频格式为mp4。
- mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
- //设置视频存储地址。
- mVideoPath = getOutputFile().getAbsolutePath();
- //保存在该位置。
- mediaRecorder.setOutputFile(mVideoPath);
- //设置视频大小, 清晰度。
- mediaRecorder.setVideoSize(mWidth, mHeight);
- //设置视频编码为H264。
- mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- //设置音频编码。
- mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- //设置视频码率。
- mediaRecorder.setVideoEncodingBitRate(2 * mWidth * mHeight);
- mediaRecorder.setVideoFrameRate(16);
- //初始化完成, 进入准备阶段, 准备被使用。
- try {
- mediaRecorder.prepare();
- } catch (IOException e) {
- e.printStackTrace();
- //异常提示
- Toast.makeText(this, "Recorder录像机准备失败", Toast.LENGTH_SHORT).show();
- }
- }
-
- public void createVirtualDisplay() {
- //虚拟屏幕通过MediaProjection获取, 传入一系列传过来的参数。
- try {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- virtualDisplay = mediaProjection.createVirtualDisplay("VirtualScreen", mWidth, mHeight, mDpi,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);
- }
- } catch (Exception e) {
- e.printStackTrace();
- Toast.makeText(this, "virtualDisplay创建异常", Toast.LENGTH_SHORT).show();
- }
- }
-
- //获取输出存储文件夹的位置。
- public static File getOutputDirectory() {
- String directoryFilePathName = Environment.
- getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
- .getAbsolutePath()
- + "/ScreenRecording/";
- //创建该文件夹。
- File directoryFile = new File(directoryFilePathName);
- if (!directoryFile.exists()) {
- //如果该文件夹不存在。
- if (!directoryFile.mkdirs()) {
- //如果没有创建成功。
- return null;
- }
- }
- //创建成功了, 返回该目录。
- return directoryFile;
- }
-
- private File getOutputFile() {
- File directoryFile = getOutputDirectory();
- File file = new File(directoryFile, "SR" + System.currentTimeMillis() + ".mp4");
- // if (!file.exists()) {
- // try {
- // file.createNewFile();
- // } catch (Exception e) {
- // e.printStackTrace();
- // }
- // }
- Log.i(TAG, "filePath_" + file.getAbsolutePath());
- return file;
- }
-
- private void createNotificationChannel() {
- Notification.Builder builder = new Notification.Builder(this.getApplicationContext()); //获取一个Notification构造器。
- Intent nIntent = new Intent(this, MainActivity.class); //点击后跳转的界面, 可以设置跳转数据。
-
- builder.setContentIntent(PendingIntent.getActivity(this, 0, nIntent, 0))
- .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)
- //.setContentTitle("ScreenRecording") // 设置下拉列表里的标题
- .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
- .setContentText("is running......") // 设置上下文内容
- .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
-
- /** 以下是对Android 8.0的适配 */
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- final String channelId = "MyChannelId";
- final String channelName = "MyChannelName";
-
- //普通notification适配。
- builder.setChannelId(channelId);
-
- //前台服务notification适配。
- NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
- notificationManager.createNotificationChannel(channel);
- }
-
- Notification notification = builder.build(); // 获取构建好的Notification对象。
- notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音。
- startForeground(requestCode, notification);
- }
-
- }
特别鸣谢下面链接:
(0) https://blog.csdn.net/qq_46546793/article/details/123279152
(0) https://blog.csdn.net/weixin_42602900/article/details/128340037