Android 调用系统服务接口获取屏幕投影(需要android.uid.system)

在这里插入图片描述

媒体投影

借助 Android 5(API 级别 21)中引入的 android.media.projection API,您可以将设备屏幕中的内容截取为可播放、录制或投屏到其他设备(如电视)的媒体流。

Android 14(API 级别 34)引入了应用屏幕共享功能,让用户能够分享单个应用窗口(而非整个设备屏幕),无论窗口模式如何。应用屏幕共享功能会将状态栏、导航栏、通知和其他系统界面元素从共享显示屏中排除,即使应用屏幕共享功能用于全屏截取应用也是如此。系统只会分享所选应用的内容。

应用屏幕共享功能可让用户运行多个应用,但仅限于与单个应用共享内容,从而确保用户隐私、提高用户工作效率并增强多任务处理能力。

权限

如果您的应用以 Android 14 或更高版本为目标平台,则应用清单必须包含 mediaProjection 前台服务类型的权限声明:

<manifest ...>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <application ...>
        <service
            android:name=".MyMediaProjectionService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false">
        </service>
    </application>
</manifest>

通过调用 startForeground() 启动媒体投影服务。

如果您未在调用中指定前台服务类型,则类型默认为清单中定义的前台服务类型的按位整数。如果清单未指定任何服务类型,系统会抛出 MissingForegroundServiceTypeException

获取MediaProjection示例(常规实现)

AndroidManifest.xml

    <!-- MediaProjection -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
	<application>
		<activity android:name=".MediaProjectionTest"/>
        <service android:name=".MediaProjectionService"
            android:foregroundServiceType="mediaProjection"/>
	</application>

Activity

    MediaProjectionManager projMgr;
	final int REQUEST_CODE = 0x101;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		projMgr = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

		startService(new Intent(this, ForgroundMediaProjectionService.class));
		startActivityForResult(projMgr.createScreenCaptureIntent(), REQUEST_CODE);

	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(requestCode == REQUEST_CODE){
			MediaProjection mp = projMgr.getMediaProjection(resultCode, data);
			if(mp != null){
				//mp.stop();
				//获取到MediaProjection后可以通过MediaCodec编码生成图片/视频/H264流...
			}
		}
	}

Service

	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Notification notification = null;
		Intent activity = new Intent(this, MediaProjectionTest.class);
		activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

		if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
			NotificationChannel channel = new NotificationChannel("ScreenRecorder", "Foreground notification",
					NotificationManager.IMPORTANCE_DEFAULT);
			NotificationManager manager = getSystemService(NotificationManager.class);
			manager.createNotificationChannel(channel);

			notification = new Notification.Builder(this, "ScreenRecorder")
					.setContentTitle("Test")
					.setContentText("Test Screencast...")
					.setContentIntent(PendingIntent.getActivity(this, 0x77,
							activity, PendingIntent.FLAG_UPDATE_CURRENT))
					.build();
		}
		startForeground(1, notification);
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

启动Acrtivity后会弹出授权提示
在这里插入图片描述
点击立即开始 Activity.onActivityResult 可以获取到MediaProjection.


如果App是系统应用(android.uid.systtem), 如何跳过授权窗?

  1. 申请MediaProjection过程拆解

涉及源码
frameworks/base/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
frameworks/base/media/java/android/media/projection/MediaProjectionManager.java
frameworks/base/core/res/res/values/config.xml
frameworks/base/packages/SystemUI/AndroidManifest.xml
frameworks/base/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java

函数createScreenCaptureIntent 返回的Intent 指向的是 SystemUI的一个组件:

frameworks/base/media/java/android/media/projection/MediaProjectionManager.java


    /**
     * Returns an Intent that <b>must</b> be 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();
        final ComponentName mediaProjectionPermissionDialogComponent =
                ComponentName.unflattenFromString(mContext.getResources().getString(
                        com.android.internal.R.string
                        .config_mediaProjectionPermissionDialogComponent));
        i.setComponent(mediaProjectionPermissionDialogComponent);
        return i;
    }

frameworks/base/core/res/res/values/config.xml

<string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>

frameworks/base/packages/SystemUI/AndroidManifest.xml

            <!-- started from MediaProjectionManager -->
            <activity
                android:name=".media.MediaProjectionPermissionActivity"
                android:exported="true"
                android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog"
                android:finishOnCloseSystemDialogs="true"
                android:launchMode="singleTop"
                android:excludeFromRecents="true"
                android:visibleToInstantApps="true"/>

MediaProjectionPermissionActivity 就是弹窗的主体

frameworks/base/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java

   @Override
       public void onCreate(Bundle icicle) {
           super.onCreate(icicle);
   
           mPackageName = getCallingPackage();
           IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
           mService = IMediaProjectionManager.Stub.asInterface(b);
   
           if (mPackageName == null) {
               finish();
               return;
           }
   
           PackageManager packageManager = getPackageManager();
           ApplicationInfo aInfo;
           try {
               aInfo = packageManager.getApplicationInfo(mPackageName, 0);
               mUid = aInfo.uid;
           } catch (PackageManager.NameNotFoundException e) {
               Log.e(TAG, "unable to look up package name", e);
               finish();
               return;
           }
   
           try {
               if (mService.hasProjectionPermission(mUid, mPackageName)) {
                   setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
                   finish();
                   return;
               }
           } catch (RemoteException e) {
               Log.e(TAG, "Error checking projection permissions", e);
               finish();
               return;
           }
   
           TextPaint paint = new TextPaint();
           paint.setTextSize(42);
   
           CharSequence dialogText = null;
           CharSequence dialogTitle = null;
           if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {
               dialogText = getString(R.string.media_projection_dialog_service_text);
               dialogTitle = getString(R.string.media_projection_dialog_service_title);
           } else {
               String label = aInfo.loadLabel(packageManager).toString();
   
               // If the label contains new line characters it may push the security
               // message below the fold of the dialog. Labels shouldn't have new line
               // characters anyways, so just truncate the message the first time one
               // is seen.
               final int labelLength = label.length();
               int offset = 0;
               while (offset < labelLength) {
                   final int codePoint = label.codePointAt(offset);
                   final int type = Character.getType(codePoint);
                   if (type == Character.LINE_SEPARATOR
                           || type == Character.CONTROL
                           || type == Character.PARAGRAPH_SEPARATOR) {
                       label = label.substring(0, offset) + ELLIPSIS;
                       break;
                   }
                   offset += Character.charCount(codePoint);
               }
   
               if (label.isEmpty()) {
                   label = mPackageName;
               }
   
               String unsanitizedAppName = TextUtils.ellipsize(label,
                       paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
               String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
   
               String actionText = getString(R.string.media_projection_dialog_text, appName);
               SpannableString message = new SpannableString(actionText);
   
               int appNameIndex = actionText.indexOf(appName);
               if (appNameIndex >= 0) {
                   message.setSpan(new StyleSpan(Typeface.BOLD),
                           appNameIndex, appNameIndex + appName.length(), 0);
               }
               dialogText = message;
               dialogTitle = getString(R.string.media_projection_dialog_title, appName);
           }
   
           View dialogTitleView = View.inflate(this, R.layout.media_projection_dialog_title, null);
           TextView titleText = (TextView) dialogTitleView.findViewById(R.id.dialog_title);
           titleText.setText(dialogTitle);
   
           mDialog = new AlertDialog.Builder(this)
                   .setCustomTitle(dialogTitleView)
                   .setMessage(dialogText)
                   .setPositiveButton(R.string.media_projection_action_text, this)
                   .setNegativeButton(android.R.string.cancel, this)
                   .setOnCancelListener(this)
                   .create();
   
           mDialog.create();
           mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
   
           final Window w = mDialog.getWindow();
           w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
           w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
   
           mDialog.show();
       }
       
       private Intent getMediaProjectionIntent(int uid, String packageName)
               throws RemoteException {
           IMediaProjection projection = mService.createProjection(uid, packageName,
                    MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
           Intent intent = new Intent();
           intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
           return intent;
       }
  1. 申请成功后返回结果给到申请的Activity:
    getMediaProjectionIntent函数中, 创建了IMediaProjection并通过Intent返回给了调用的App

    setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
    
    
     IMediaProjection projection = mService.createProjection(uid, packageName,
                  MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
    
     Intent intent = new Intent();
     intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
    
     getMediaProjection(resultCode, data)
    
  2. Activity 调用 getMediaProjection 获取MediaProjection

frameworks/base/media/java/android/media/projection/MediaProjectionManager.java

  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));
      }

总的来说, 这个流程稍微绕了一点路:

App MediaProjectionManager SystemUI MediaProjectionService createScreenCaptureIntent MediaProjectionPermissionActivity createProjection onActivityResult getMediaProjection App MediaProjectionManager SystemUI MediaProjectionService

createProjection的实现

frameworks/base/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java

         @Override // Binder call
         public IMediaProjection createProjection(int uid, String packageName, int type,
                 boolean isPermanentGrant) {
             if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
                         != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to grant "
                         + "projection permission");
             }
             if (packageName == null || packageName.isEmpty()) {
                 throw new IllegalArgumentException("package name must not be empty");
             }
 
             final UserHandle callingUser = Binder.getCallingUserHandle();
             long callingToken = Binder.clearCallingIdentity();
 
             MediaProjection projection;
             try {
                 ApplicationInfo ai;
                 try {
                     ai = mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);
                 } catch (NameNotFoundException e) {
                     throw new IllegalArgumentException("No package matching :" + packageName);
                 }
 
                 projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion,
                         ai.isPrivilegedApp());
                 if (isPermanentGrant) {
                     mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
                             projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingToken);
             }
             return projection;
         }
         

通过反射, 调用MediaProjectionService的createProjection


注意: 此方法需要有系统权限(android.uid.system)

    //android.os.ServiceManager;

    static Object getService(String name){
		try {
			Class ServiceManager = Class.forName("android.os.ServiceManager");
            Method getService = ServiceManager.getDeclaredMethod("getService", String.class);
            return getService.invoke(null, name);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
            e.printStackTrace();
		}
		return null;
    }

	@SuppressLint("SoonBlockedPrivateApi")
	static Object asInterface(Object binder){
		try {
			Class IMediaProjectionManager_Stub = Class.forName("android.media.projection.IMediaProjectionManager$Stub");
            Method asInterface = IMediaProjectionManager_Stub.getDeclaredMethod("asInterface", IBinder.class);
            return asInterface.invoke(null, binder);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
            e.printStackTrace();
		}
		return null;
	}

    //    private IMediaProjectionManager mService;
    //android.media.projection.IMediaProjectionManager
	@SuppressLint("SoonBlockedPrivateApi")
	public static MediaProjection createProjection(){
        //Context.java public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
        //IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
        //        mService = IMediaProjectionManager.Stub.asInterface(b);
        IBinder b = (IBinder) getService("media_projection");
        Object mService = asInterface(b) ;

        //IMediaProjection projection = mService.createProjection(uid, packageName,
        //MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
		//public static final int TYPE_SCREEN_CAPTURE = 0;
		try {
			Logger.i("createProjection", "createProjection");
			Class IMediaProjectionManager = Class.forName("android.media.projection.IMediaProjectionManager");
			// public IMediaProjection createProjection(int uid, String packageName, int type, boolean isPermanentGrant)
			Method createProjection = IMediaProjectionManager.getDeclaredMethod("createProjection", Integer.TYPE, String.class, Integer.TYPE, Boolean.TYPE);
			Object projection = createProjection.invoke(mService, android.os.Process.myUid(), App.getApp().getPackageName(),
					0, false);
			Logger.i("createProjection", "projection created!");

			//android.media.projection.IMediaProjection;
			Class IMediaProjection = IInterface.class;//Class.forName("android.media.projection.IMediaProjection");
			Method asBinder = IMediaProjection.getDeclaredMethod("asBinder");
			Logger.i("createProjection", "asBinder found");

			Intent intent = new Intent();
			//    public static final String EXTRA_MEDIA_PROJECTION =
			//            "android.media.projection.extra.EXTRA_MEDIA_PROJECTION";
			//Bundle extra = new Bundle();
			//extra.putBinder("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)asBinder.invoke(projection));
			//intent.putExtra("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)asBinder.invoke(projection));
			intent.putExtra(Intent.EXTRA_RETURN_RESULT, Activity.RESULT_OK);
			Object projBinder = asBinder.invoke(projection);
			Logger.i("createProjection", "asBinder invoke success.");

			//intent.getExtras().putBinder("android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)projBinder);
			Method putExtra = Intent.class.getDeclaredMethod("putExtra", String.class, IBinder.class);
			putExtra.invoke(intent, "android.media.projection.extra.EXTRA_MEDIA_PROJECTION",  (IBinder)projBinder);
			Logger.i("createProjection", "putExtra with IBinder success.");

			MediaProjectionManager projMgr = App.getApp().getMediaProjectionManager();
			MediaProjection mp = projMgr.getMediaProjection(Activity.RESULT_OK, intent);
			Logger.i("createProjection", "getMediaProjection " + (mp == null ? " Failed" : "Success"));

			//new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));

			//if(mp != null)mp.stop();
			return  mp;

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}

参考

Android截屏录屏MediaProjection分享
Android录屏的三种方案
媒体投影
[Android] 使用MediaProjection截屏
android设备间实现无线投屏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PT8M2102 触控型 8Bit MCU

1. 产品概述 PT8M2102 是一款基于 RISC 内核的 8 位 MTP 单片机&#xff0c;内部集成了电容式触摸感应模块、 TIMER 、 PWM、 LVR 、 LVD 、 WDT 等外设&#xff0c;其主要用作触摸按键开关&#xff0c;广泛适用于触控调光、电子玩具、消 费电子、家用电器等领域&am…

LangGraph 教程:初学者综合指南(2)

工具集成 将工具集成到 LangGraph 聊天机器人中可以显着增强其功能&#xff0c;使其能够按照您喜欢的方式访问和处理信息。 让我们修改上一节中创建的基本聊天机器人&#xff0c;以包含一个可以在网络上搜索信息的工具。我们将使用langchain_中community.tools TavilySearchR…

项目练习:若依管理系统字典功能-Vue前端部分

文章目录 一、情景说明二、若依Vue相关代码及配置1、utils代码2、components组件3、api接口代码4、main.js配置 三、使用方法1、html部分2、js部分 一、情景说明 我们在做web系统的时候&#xff0c;肯定会遇到一些常量选择场景。 比如&#xff0c;性别&#xff1a;男女。 状态…

oracle闪回表

文章目录 闪回表案例1&#xff1a;&#xff08;未清理回收站时的闪回表--成功&#xff09;案例2&#xff08;清理回收站时的闪回表--失败&#xff09;案例3&#xff1a;彻底删除表&#xff08;不经过回收站--失败&#xff09;案例4&#xff1a;闪回表之后重新命名新表总结1、删…

TensorFlow Quantum快速编程(基本篇)

一、TensorFlow Quantum 概述 1.1 简介 TensorFlow Quantum(TFQ)是由 Google 开发的一款具有开创性意义的开源库,它宛如一座桥梁,巧妙地将量子计算与 TensorFlow 强大的机器学习功能紧密融合。在当今科技飞速发展的时代,传统机器学习虽已取得诸多瞩目成就,然而面对日益…

K8s数据存储之详解(Detailed Explanation of K8s Data Storage)

K8s数据存储相关概念详解&#xff08;临时存储&#xff0c;节点存储&#xff0c;网络存储&#xff0c;PV/PVC&#xff09; 本篇文章分享一下存储卷和数据持久化的相关概念&#xff1a; 存储卷概述 临时存储卷&#xff08;Ephemeral Volumes&#xff09; 节点存储卷&#xff…

java求职学习day12

1 泛型机制&#xff08;熟悉&#xff09; 1.1 基本概念 &#xff08;1&#xff09;通常情况下集合中可以存放不同类型的元素&#xff0c;是因为将所有对象都看作Object类型放入&#xff0c;因此从集合中取出元素时&#xff0c;也是Object类型&#xff0c;为了表达该元素真实的…

相加交互效应函数发布—适用于逻辑回归、cox回归、glmm模型、gee模型

在统计分析中交互作用是指某因素的作用随其他因素水平变化而变化&#xff0c;两因素共同作用不等于两因素单独作用之和(相加交互作用)或之积(相乘交互作用)。相互作用的评估是尺度相关的&#xff1a;乘法或加法。乘法尺度上的相互作用意味着两次暴露的综合效应大于&#xff08;…

Spring Boot 2 学习全攻略

Spring Boot 2 学习资料 Spring Boot 2 学习资料 Spring Boot 2 学习资料 在当今快速发展的 Java 后端开发领域&#xff0c;Spring Boot 2 已然成为一股不可忽视的强大力量。它简化了 Spring 应用的初始搭建以及开发过程&#xff0c;让开发者能够更加专注于业务逻辑的实现&am…

【面试题】技术场景 4、负责项目时遇到的棘手问题及解决方法

工作经验一年以上程序员必问问题 面试题概述 问题为在负责项目时遇到的棘手问题及解决方法&#xff0c;主要考察开发经验与技术水平&#xff0c;回答不佳会影响面试印象。提供四个回答方向&#xff0c;准备其中一个方向即可。 1、设计模式应用方向 以登录为例&#xff0c;未…

30分钟内搭建一个全能轻量级springboot 3.4 + 脚手架 <1> 5分钟快速创建一个springboot web项目

快速导航 <1> 5分钟快速创建一个springboot web项目 <2> 5分钟集成好最新版本的开源swagger ui&#xff0c;并使用ui操作调用接口 <3> 5分钟集成好druid并使用druid自带监控工具监控sql请求 <4> 5分钟集成好mybatisplus并使用mybatisplus generator自…

【Rust自学】11.10. 集成测试

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.10.1. 什么是集成测试 在Rust里&#xff0c;集成测试完全位于被测试库的外部。集成测试调用库的方式和其他代码一样&#xff0c;这也…

JAVA实现2048小游戏(附源码)

文章目录 一、设计来源2048小游戏讲解1.1 主界面1.2 4*4难度界面1.3 5*5难度界面1.4 6*6难度界面1.5 挑战失败提示界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载更多优质源码分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/a…

【自动化测试】—— Appium安装配置保姆教程(图文详解)

目录 一. 环境准备 二. JDK安装 1. 下载JDK 2. 安装JDK 3. 配置环境 4. 验证安装 三. Android SDK安装 1. 下载Android SDK 2. 安装Android SDK 3. 安装工具 4. 配置环境 5. 验证安装 四. NodeJS安装 1. 下载NodeJS 2. 安装NodeJS 3. 验证安装 4. 安装淘宝镜像…

vs2022+QT6.7.3打包程序流程

1、新建目录test 2、将项目配置为Release X64&#xff0c;生成XXX.exe 3、将XXX.exe放到test目录 4、管理员方式打开Qt 6.7.3 (MSVC 2022 64-bit)&#xff0c;进入test目录&#xff0c;执行&#xff1a;windeployqt6.exe XXX.exe 5、管理员方式打开x64 Native Tools Command…

RabbitMQ---消息确认和持久化

&#xff08;一&#xff09;消息确认 1.概念 生产者发送消息后&#xff0c;到达消费端会有以下情况&#xff1a; 1.消息处理成功 2.消息处理异常 如果RabbitMQ把消息发送给消费者后就把消息删除&#xff0c;那么就可能会导致&#xff0c;消息处理异常想要再获取这条消息的时…

【C++】反向迭代器

反向迭代器 一.源码及框架分析二.反向迭代器实现代码1.ReverseIterator.h2.Vector.h3.List.h4.Test.cpp 一.源码及框架分析 SGI-STL30版本源代码&#xff0c;反向迭代器实现的核心源码在stl_iterator.h中&#xff0c;反向迭代器是一个适配器&#xff0c;各个容器中再适配出自己…

浅谈云计算02 | 云计算模式的演进

云计算计算模式的演进 一、云计算计算模式的起源追溯1.2 个人计算机与桌面计算 二、云计算计算模式的发展阶段2.1 效用计算的出现2.2 客户机/服务器模式2.3 集群计算2.4 服务计算2.5 分布式计算2.6 网格计算 三、云计算计算模式的成熟与多元化3.1 主流云计算服务模式的确立3.1.…

WEB 攻防-通用漏-XSS 跨站脚本攻击-反射型/存储型/DOMBEEF-XSS

XSS跨站脚本攻击技术&#xff08;一&#xff09; XSS的定义 XSS攻击&#xff0c;全称为跨站脚本攻击&#xff0c;是指攻击者通过在网页中插入恶意脚本代码&#xff0c;当用户浏览该网页时&#xff0c;恶意脚本会被执行&#xff0c;从而达到攻击目的的一种安全漏洞。这些恶意脚…

Vue3组件设计模式:高可复用性组件开发实战

Vue3组件设计模式:高可复用性组件开发实战 一、前言 在Vue3中&#xff0c;组件设计和开发是非常重要的&#xff0c;它直接影响到应用的可维护性和可复用性。本文将介绍如何利用Vue3组件设计模式来开发高可复用性的组件&#xff0c;让你的组件更加灵活和易于维护。 二、单一职责…