当前位置: 首页 > news >正文

网站充值链接怎么做三亚做网站推广

网站充值链接怎么做,三亚做网站推广,西安有几个区,佛山高端网站开发公司大致流程为:客户端通过MediaProjectionManager进行屏幕共享,获取屏幕的截图,然后通过WebSocket发送到服务端,然后通过浏览器访问服务端查看传输的截图。 客户端代码分为3部分: ScreenShotShareActivity:作…

大致流程为:客户端通过MediaProjectionManager进行屏幕共享,获取屏幕的截图,然后通过WebSocket发送到服务端,然后通过浏览器访问服务端查看传输的截图。

客户端代码分为3部分:

  1. ScreenShotShareActivity:作用用户的交互界面,有2个按钮,一个是开启屏幕共享,另一个是结束屏幕共享,开启后会启动一个前台服务(这个是系统要求的,屏幕共享的逻辑必须在Service进行)
  2. ScreenShotEncoder:用于实现屏幕共享的图片截图处理,并设置结果回调,相当于一个工具类,会在Service中调用。
  3. ScreenCaptureService:前台服务,启动后会监听ScreenShotEncoder的结果,然后通过WebSocket将结果同步给远端服务器。

服务端代码分为2部分:
服务端通过Node js来实现,需要安装socket.io,2个代码文件:

  1. server.js:作为服务响应
  2. index.html:前端页面,用来展示客户端截图结果

客户端实现

清单文件配置

ScreenShotShareActivity + ScreenCaptureService 声明

<activity android:name=".demo.sharescreen.ScreenShotShareActivity" /><serviceandroid:name=".demo.sharescreen.ScreenCaptureService"android:exported="false"android:foregroundServiceType="mediaProjection" />

权限声明

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />

ScreenShotShareActivity

class ScreenShotShareActivity : AppCompatActivity() {private var isBound = falseprivate var binder: ScreenCaptureService.LocalBinder? = nullprivate var imageView: ImageView? = nullprivate val screenCaptureLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK && result.data != null) {startScreenEncoding(result.resultCode, result.data!!)} else {Toast.makeText(this, "屏幕录制权限被拒绝", Toast.LENGTH_SHORT).show()}}private val connection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {binder = service as? ScreenCaptureService.LocalBinderbinder?.setImageCallback(object : ScreenShotCaptureCallback {override fun onJpegImageReady(jpegData: String) {// 采集端本地测试val decodedBytes = Base64.decode(jpegData, Base64.NO_WRAP)val bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)runOnUiThread {imageView?.setImageBitmap(bitmap)}}})isBound = true}override fun onServiceDisconnected(name: ComponentName?) {isBound = false}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)imageView = ImageView(this).apply {scaleType = ImageView.ScaleType.FIT_CENTER}setContentView(LinearLayout(this).apply {orientation = LinearLayout.VERTICALaddView(Button(this@ScreenShotShareActivity).apply {text = "开始屏幕录制"click {requestScreenCapture()}})addView(Button(this@ScreenShotShareActivity).apply {text = "停止屏幕录制"click {stopScreenCapture()}})addView(imageView, LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT))})}private fun stopScreenCapture() {if (isBound) unbindService(connection)val intent = Intent(this@ScreenShotShareActivity, ScreenCaptureService::class.java)stopService(intent)}/*** 请求屏幕共享权限*/private fun requestScreenCapture() {val projectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManagerval intent = projectionManager.createScreenCaptureIntent()screenCaptureLauncher.launch(intent)}/*** 开始屏幕共享,启动前台服务 ScreenCaptureService*/private fun startScreenEncoding(resultCode: Int, data: Intent) {val serviceIntent = Intent(this, ScreenCaptureService::class.java).apply {putExtra("resultCode", resultCode)putExtra("data", data)}ContextCompat.startForegroundService(this, serviceIntent)bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)}
}

ScreenCaptureService


/*** 前台服务,需要添加权限:*   <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />*   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />*/
class ScreenCaptureService : Service() {private var screenShotEncoder:ScreenShotEncoder? = nullprivate var screenShotCallback: ScreenShotCaptureCallback? = nullprivate val socket by lazy {val opts = IO.Options().apply {transports = arrayOf("websocket") // ⭐ 避免 xhr-poll 错误reconnection = truereconnectionAttempts = 5timeout = 5000}IO.socket("http://192.168.28.101:3000",opts)}private fun startForeground(notification: Notification) {if (VERSION.SDK_INT >= Build.VERSION_CODES.Q) {startForeground(1,notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)} else {startForeground(1, notification)}}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {startForeground(createNotification())val resultCode = intent?.getIntExtra("resultCode", Activity.RESULT_CANCELED) ?: return START_NOT_STICKYval data = intent.getParcelableExtra<Intent>("data") ?: return START_NOT_STICKYinitSocketIO()screenShotEncoder = ScreenShotEncoder(this, resultCode, data)screenShotEncoder?.startCapturing { base64Jpeg ->// 回调给外部activity,可以用做测试或者打印logscreenShotCallback?.onJpegImageReady(base64Jpeg)// 发送给远端服务器socket.emit("frame", base64Jpeg)}return START_STICKY}private fun initSocketIO() {try {// 连接状态监听socket.on(Socket.EVENT_CONNECT) {Log.d("ScreenCaptureService", "✅ Socket 已连接到服务器")}socket.on(Socket.EVENT_CONNECT_ERROR) { args ->Log.e("ScreenCaptureService", "❌ Socket 连接失败: ${args.getOrNull(0)}")}socket.on(Socket.EVENT_DISCONNECT) {Log.w("ScreenCaptureService", "⚠️ Socket 已断开连接")}socket.connect()} catch (e: URISyntaxException) {Log.e("ScreenCaptureService", "❌ Socket URI 格式错误", e)}}private fun createNotification(): Notification {val channelId = "screen_capture"val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManagerif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {val channel = NotificationChannel(channelId, "屏幕共享", NotificationManager.IMPORTANCE_LOW)manager.createNotificationChannel(channel)}return NotificationCompat.Builder(this, channelId).setContentTitle("屏幕共享中").setContentText("正在采集屏幕内容").setSmallIcon(android.R.drawable.ic_menu_camera).build()}override fun onBind(intent: Intent?): IBinder? {return LocalBinder()}override fun onDestroy() {super.onDestroy()screenEncoder?.stopEncoding()screenShotEncoder?.stopCapturing()socket.disconnect()Log.d("ScreenCaptureService","服务销毁")}inner class LocalBinder : Binder() {fun stopCapture() {stopSelf()}fun setImageCallback(callback: ScreenShotCaptureCallback) {screenShotCallback  = callback}}
}interface ScreenShotCaptureCallback {fun onJpegImageReady(jpegData: String)
}

ScreenShotEncoder


class ScreenShotEncoder(private val context: Context,private val resultCode: Int,private val data: Intent,private val width: Int = 720,private val height: Int = 1280,private val dpi: Int = 320
) {private lateinit var mediaProjection: MediaProjectionprivate var imageReader: ImageReader? = nullprivate var handlerThread: HandlerThread? = nullprivate var handler: Handler? = nullprivate var isCapturing = falsefun startCapturing(onFrameReady: (String) -> Unit) {setupMediaProjection()setupImageReader(onFrameReady)isCapturing = true}fun stopCapturing() {isCapturing = falseimageReader?.close()mediaProjection.stop()handlerThread?.quitSafely()}private fun setupMediaProjection() {val projectionManager = context.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManagermediaProjection = projectionManager.getMediaProjection(resultCode, data)}private fun setupImageReader(onFrameReady: (String) -> Unit) {imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2)handlerThread = HandlerThread("ScreenShotThread").also { it.start() }handler = Handler(handlerThread!!.looper)mediaProjection.createVirtualDisplay("ScreenShotCapture",width,height,dpi,0,imageReader!!.surface,null,handler)handler?.post(object : Runnable {override fun run() {if (!isCapturing) returnval image = imageReader?.acquireLatestImage()if (image != null) {val planes = image.planesval buffer = planes[0].bufferval pixelStride = planes[0].pixelStrideval rowStride = planes[0].rowStrideval rowPadding = rowStride - pixelStride * widthval bitmap = createBitmap(width + rowPadding / pixelStride, height)bitmap.copyPixelsFromBuffer(buffer)image.close()val outputStream = ByteArrayOutputStream()bitmap.compress(Bitmap.CompressFormat.JPEG, 70, outputStream)val byteArray = outputStream.toByteArray()val base64Image = Base64.encodeToString(byteArray, Base64.NO_WRAP)onFrameReady(base64Image)bitmap.recycle()}handler?.postDelayed(this, 100) // 每 100ms 截图一帧(约10帧/s)}})}
}

启动App后,看到界面如下:
在这里插入图片描述

点击开始录制,会弹一个权限弹窗
在这里插入图片描述
同意后,进入录制
在这里插入图片描述

服务端实现

第一步:准备环境

安装 Node.js
如果你尚未安装,请去 https://nodejs.org/ 下载并安装 LTS 版本。
安装完成后,打开终端输入:

node -v
npm -v

确认安装成功。

第二步:创建项目文件夹

mkdir webrtc-server
cd webrtc-server
npm init -y
npm install express socket.io

第三步:创建信令服务器 server.js

在webrtc-server文件夹下创建server.js文件,代码如下:

// server.js
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);  // v2.4.1 不需要 CORS 配置app.use(express.static(__dirname + '/public'));io.on('connection', socket => {console.log('🟢 Client connected:', socket.id);socket.on('frame', (data) => {console.log(`📥 接收到 frame,长度=${data.length}`);socket.broadcast.emit('frame', data);});socket.on('offer', (data) => {socket.broadcast.emit('offer', data);});socket.on('answer', (data) => {socket.broadcast.emit('answer', data);});socket.on('ice-candidate', (data) => {socket.broadcast.emit('ice-candidate', data);});socket.on('disconnect', () => {console.log('🔴 Client disconnected:', socket.id);});
});const PORT = 3000;
http.listen(PORT, '0.0.0.0', () => {console.log(`🚀 Server running at http://0.0.0.0:${PORT}`);
});

第四步:创建接收端前端页面

在 webrtc-server 目录下创建一个 public/index.html 文件:

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>屏幕共享画面</title><style>#log {background: #f4f4f4;border: 1px solid #ccc;padding: 10px;margin-top: 10px;height: 100px;overflow-y: auto;font-family: monospace;font-size: 14px;}</style>
</head>
<body>
<h2>接收到的屏幕共享图像</h2>
<img id="screenImg"style="max-width: 100%; max-height: 600px; border: 1px solid #ccc; object-fit: contain;" /><div id="log"></div><script src="/socket.io/socket.io.js"></script>
<script>const socket = io();const img = document.getElementById("screenImg");const logEl = document.getElementById("log");function log(message) {const time = new Date().toLocaleTimeString();const entry = `[${time}] ${message}`;console.log(entry);logEl.innerText += entry + "\n";logEl.scrollTop = logEl.scrollHeight;}socket.on("connect", () => {log("✅ 已连接到服务器");});socket.on("disconnect", () => {log("❌ 与服务器断开连接");});socket.on("frame", (base64) => {log("🖼️ 收到一帧图像");img.src = "data:image/jpeg;base64," + base64;});socket.on("connect_error", (err) => {log("⚠️ 连接错误: " + err.message);});
</script>
</body>
</html>

第五步:运行服务器

node server.js

你会看到:
在这里插入图片描述
说明服务端运行成功了,并且有一个客户端加入了,这个就是我们的客户端发起的屏幕共享加入的。

验证效果

打开浏览器输入地址:http://192.168.28.101:3000/index.html
注意:这里的地址是局域网地址,我本机电脑的地址,和我手机是在同一个局域网内。

成功的话,可以看到客户端的共享内容:
在这里插入图片描述

http://www.dtcms.com/a/552967.html

相关文章:

  • 在Azure webapp中搭建 基于chroma的 RAG agent
  • 【春秋云境】CVE-2024-38856 Apache OFbiz从未授权到RCE
  • 货拉拉用户画像基于 Apache Doris 的数据模型设计与实践
  • JAR 包中替换依赖jar的正确姿势(Windows 环境)
  • linux驱动开发之pr_warn和pr_warning
  • Keil(MDK-ARM)和 STM32CubeIDE对比
  • Linux上使用Docker安装MinIO指南
  • Maven 依赖冲突:解决 jar 包版本不一致的 3 种方法
  • android集成react native组件踩坑笔记(Activity局部展示RN的组件)
  • 多语言网站思路十大h5页面制作工具
  • 汽车之家网站系统是什么做的防爆玻璃门网站建设
  • k8s——services资源+pod详解1
  • 基于深度学习的医疗器械分类编码映射系统:实现篇
  • [人工智能-大模型-122]:模型层 - RNN是通过神经元还是通过张量时间记录状态信息?时间状态信息是如何被更新的?
  • React 18.x 学习计划 - 第六天:React路由和导航
  • 逻辑回归正则化参数选择实验报告:贝叶斯优化与网格搜索的效率对比
  • 建设景区网站推文网站中了木马了怎么办
  • 【JAVA 进阶】重生之我要学会 JUC 并发编程
  • POST 数据提交注入测试sqlilabs less 11
  • 微服务高并发设计考虑要点
  • 解码LVGL Linux 系统(Ubuntu/WSL + 开发板)移植
  • 长春网站制作昆明君创网络科技有限公司
  • 把 CLI 搬上 Web:在内网打造“可二开”的 AI IDE,为什么这条路更现实?
  • iOS 上架应用市场全流程指南,App Store 审核机制、证书管理与跨平台免 Mac 上传发布方案(含开心上架实战)
  • 酒厂网站源码now9999网站提示建设中
  • iOS 中的引用计数
  • C++多线程运行整理
  • 【渲染引擎基础】圣杯架构——固定逻辑时长+插值渲染
  • iOS 崩溃日志分析工具全指南,多工具协同构建稳定性分析体系
  • 做网站推广的难点、襄阳地区网站做的好的