Android截屏录屏MediaProjection分享

【Android】录屏功能实现——MediaProjection Android录屏功能实现—MediaProjection 不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵! 参考博客:Android实现录屏MediaProjection以及相关异常解决 参考GitHub:github中最容易理解的Android录屏的版本 概述 Android录屏功能实现有很多种方式,这里记录最常见的一种,用Android自带的apk来实现,即使用MediaProjection来实现。 工具类 实现Android的录屏功能,需要用到一些工具类:MediaP 阅读详情
AI摘要

本文详细介绍如何使用Android的MediaProjection API实现截屏与录屏功能,包括实现步骤、注意事项及示例代码。

Android截图方案使用MediaProjection截图

1.简介

MediaProjection 是google官方的屏幕截屏/录屏方式,
通过MediaProjectionManager管理有具体类型的MediaProjection建立屏幕捕获对话来实现截屏或者录屏。也就是说其实是靠MediaProjection来实现截屏或录屏的。

所有代码都在Github-Tinder


/**
 * Manages the retrieval of certain types of {@link MediaProjection} tokens.
 *
 * <p><ol>An example flow of starting a media projection will be:
 *     <li>Declare a foreground service with the type {@code mediaProjection} in
 *     the {@code AndroidManifest.xml}.
 *     </li>
 *     <li>Create an intent by calling {@link MediaProjectionManager#createScreenCaptureIntent()}
 *         and pass this intent to {@link Activity#startActivityForResult(Intent, int)}.
 *     </li>
 *     <li>On getting {@link Activity#onActivityResult(int, int, Intent)},
 *         start the foreground service with the type
 *         {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
 *     </li>
 *     <li>Retrieve the media projection token by calling
 *         {@link MediaProjectionManager#getMediaProjection(int, Intent)} with the result code and
 *         intent from the {@link Activity#onActivityResult(int, int, Intent)} above.
 *     </li>
 *     <li>Start the screen capture session for media projection by calling
 *         {@link MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface,
 *         android.hardware.display.VirtualDisplay.Callback, Handler)}.
 *     </li>
 * </ol>
 */


类注解就说的很明白,使用MediaProjectionManager实现截屏仅需5步:

  • 声明一个foregroundServiceType包含mediaProjection类型的service
  • 通过 MediaProjectionManager.createScreenCaptureIntent() 获取intent,然后调用Activity.tartActivityForResult(Intent, int)
  • 在收到Activity.onActivityResult(int, int, Intent)回调后,启动Service,并传递foregroundServiceType为ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
  • 在Activity.onActivityResult(int, int, Intent)中调用MediaProjectionManager.getMediaProjection(int, Intent)获取MediaProjection
  • 调用MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface,android.hardware.display.VirtualDisplay.Callback, Handler)开始捕获屏幕

2.具体使用

接下来,正式按照上述步骤介绍如何实现截屏

2.1 声明Service

Service代码


class TinderService : Service() {
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        Log.i(TAG, "onCreate: ")
        //前台化通知
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "001"
            val channelName = "screenshot"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
            channel.lightColor = Color.BLUE
            channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
            val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
            if (manager != null) {
                val activityIntent: Intent = Intent(
                    this,
                    MainActivity::class.java
                )
                activityIntent.setAction("stop")
                val contentIntent = PendingIntent.getActivity(
                    this,
                    0,
                    activityIntent,
                    PendingIntent.FLAG_MUTABLE
                )

                manager.createNotificationChannel(channel)
                val notification: Notification =
                    Notification.Builder(getApplicationContext(), channelId)
                        .setOngoing(true)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setCategory(Notification.CATEGORY_SERVICE)
                        .setContentTitle("screenshot")
                        .setContentIntent(contentIntent)
                        .build()
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    //录屏要这个类型ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
                    startForeground(
                        1,
                        notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
                    )
                } else {
                    startForeground(1, notification)
                }
            }
        } else {
            startForeground(1, Notification())
        }
    }

    companion object {
        private const val TAG = "TinderService"
    }
}


不必多说,服务前台化是必要的;

Manifest声明:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 前台服务-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <!-- 文件权限-->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 截屏如果不想变成系统应用,增加这个权限-->
    <uses-permission
        android:name="android.permission.READ_FRAME_BUFFER"
        tools:ignore="ProtectedPermissions" />
 	<application>
        <service
            android:name=".TinderService"
            android:foregroundServiceType="mediaPlayback|mediaProjection"
            tools:ignore="ForegroundServicePermission" />
 	</application>
</manifest>

切记:记得增加必要的权限;service要增加mediaProjection类型

2.2 发起屏幕捕获申请



  private val mProjectionManager: MediaProjectionManager =
        context.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
  val captureIntent = mProjectionManager.createScreenCaptureIntent()
  s
  startActivityForResult(cpatureIntent,0)

调用这个方法后,系统会弹窗询问是否允许捕获屏幕提问,不论同意还是拒绝,都会回调onActivityResult

2.3 在onActivityResult中处理结果


    private val mOnActivityResult: IOnActivityResult by lazy {
        object : IOnActivityResult {
            override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
                Log.i(TAG, "onActivityResult:requestCode:$requestCode ,resultCode:$resultCode")
                 mMediaProjection =
                        mProjectionManager.getMediaProjection(resultCode, data)
                data?.let {
                    Handler().post({
                        //要先启动service,否则/java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
                        getScreenshot(resultCode, data)

                    })
                }
            }
        }
    }


2.4 提前启动Service

这里注意,在调用MediaProjectionManager.getMediaProjection(int, Intent)获取MediaProjection之前,一定要先启动service,并保证service已经被前台化了,否则,就会包SecuretyException;

关于Service的启动,有以下3中方案:

方案一:

可以把这个intent传递到service中,在Service.onStartCommand中在继续后续任务;

startActivity(Intent(this,TinderService::class.java).putPercelableExtra(data))

然后在Service.onStartCommand在继续后续的工作

我个人猜想,这种方案才是符合官方方案的一种方式,因为捕获屏幕是一个后台性的任务,很适合放到service中去做。

方案二:

Handler(Looper.getMainLooper()).postDelayed({startActivity(Intent(this,TinderService::class.java)},1_000L)

这种方案我并不太喜欢,使用延时以达到任务同步无论何时都不是高明有效的方案;

方案三:

前两种方案我更推崇方案一,安全,但是我并不喜欢把一个独立的功能拆分放到不同的模块中。所以我在截屏模块启动之前,就提前启动service(比如模块初始化时),
这样就能保证安全性,功能完整性;

Service启动后,一定要将服务前台化,在前面已经贴过Service的完整代码,但一定要记得这行:

startForeground(1,notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)

foregroundServiceType要传递ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION,否则会报错

2.4 开始捕获屏幕


   private fun getScreenshot(resultCode: Int, data: Intent) {
        Log.i(TAG, "getScreenshot: ")

        mMediaProjection?.let {
            val imageReader =
                ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3)
            imageReader.setOnImageAvailableListener({
                Log.i(TAG, "onImageAvailable: ")
//                val image: Image? = imageReader.acquireNextImage()
                val image: Image? = imageReader.acquireLatestImage()
                image?.let {
                    val width = image.width
                    val height = image.height
                    val planes = image.planes
                    val buffer = planes[0].buffer
                    val pixelStride = planes[0].pixelStride
                    val rowStride = planes[0].rowStride
                    val rowPadding = rowStride - pixelStride * width
                    val bitmap = Bitmap.createBitmap(
                        width + rowPadding / pixelStride,
                        height,
                        Bitmap.Config.ARGB_8888
                    )
                    bitmap.copyPixelsFromBuffer(buffer)
                    val filePath =
                        Environment.getExternalStorageDirectory().path + File.separator + Calendar.getInstance().timeInMillis + ".jpg"
                    //bitmap保存为图片
                    saveBitmap(bitmap, filePath)
                    mOnScreenshotListener?.onScreenshot(bitmap)

                    //--释放资源
                    mVirtualDisplay?.release()
                    release()
                    image.close()
                    //使用完一定要回收
	//              bitmap.recycle()

                    cancelNotification();
                }
            }, null)
            mVirtualDisplay = it.createVirtualDisplay(
                "screenCapture",
                width,
                height,
                dpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                imageReader.surface,
                null,
                null
            )

        }
    }

 private fun saveBitmap(bitmap: Bitmap, path: String) {
        try {
            val fop = FileOutputStream(path)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fop)
            fop.flush()
            fop.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
}

注意:

  • 如果弹窗申请捕获屏幕拒绝,mProjectionManager.getMediaProjection(resultCode, data)获取到的mediaprojection就为null;
    同时,如果Service还未启动或前台化,这里也会报错;

3.注意事项

网上说,如果不想服务前台化,或申请相关的权限,那么就把应用变成系统应用即manifes里面添加android:sharedUserId="android.uid.system",但是这对于正常开发不适用,所以我并未尝试。

3.附:录屏


class MediaProjectionScreenshotImpl(val context: Context) {


    private val mProjectionManager: MediaProjectionManager =
        context.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager

    //录屏
    private val mMediaRecorder: MediaRecorder by lazy {
        initRecorder()
    }
    private var mMediaProjection: MediaProjection? = null

    private fun initRecorder(): MediaRecorder {

        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            MediaRecorder(context)
        } else {
            MediaRecorder()
        }.apply {
            //音频源
            setAudioSource(MediaRecorder.AudioSource.MIC)
            //视频源
            setVideoSource(MediaRecorder.VideoSource.SURFACE)
            //视频输出格式
            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            //存储路径
            val path =
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).path + File.separator + "Video" + System.currentTimeMillis() + ".mp4"
            setOutputFile(path)
            setVideoSize(width, height)
            //视频格式
            setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            //音频格式
            setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
            //帧率
            setVideoFrameRate(24)
            //视频清晰度
            setVideoEncodingBitRate(5242880)
            prepare()
        }
    }

    private fun startRecorder() {
        mMediaProjection?.let {
            it.createVirtualDisplay(
                "tinder_screen_recorder",
                width,
                height,
                dpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.surface,
                null,
                null
            )
            mMediaRecorder.start()
        }
    }

    override fun stopRecord() {
        Log.i(TAG, "stopRecord: ")
        try {
            mMediaRecorder.stop()
            mMediaRecorder.reset()

        } catch (e: Exception) {
            e.printStackTrace()
        }
        release()
    }

}

和截图一样,同样需要服务前台化,在onActivityResult后进行操作

Android MediaProjection MediaProjection是Android提供的一个API,它允许应用程序捕获和录制设备屏幕上的内容。通过使用MediaProjection API,应用程序可以捕获屏幕上的视频和音频,并将其保存为视频文件或流式传输到网络。MediaProjection API还可以用于创建屏幕截图和屏幕录制应用程序。使用MediaProjection API需要以下步骤:获取MediaProjectionManager实例。 阅读详情

相关推荐

Andriod 录屏:AudioRecord、MediaProjection、MediaCodec、MediaMuxer

Android 为开发者提供了MediaRecorder的类,可以帮助录屏。但是重要的缺陷: MediaRecorder控制粒度很粗,无法完成更多的自定义功能,如对音频数据处理 MediaRecorder录制的效果很差,特别是音频效果。 为了更好的效果,最终决定利用AudioRecord、MediaProjection、MediaCodec、MediaMuxer几个重要的组件进行录屏。 这几个组件都涉及到很多的音视频的知识,建议先看之前的音视频相关的文章介绍。

三木仔 3983

Android之MediaProjection的简介

Android之MediaProjection的简介 本文链接: 知识点: 1、MediaProjection简介; 2、MediaProjection方法简介; 3、新名词记录{ VirtualDisplay: MediaProjectionManager:MediaProjection的管理类 } MediaProjection是一个5.0之后给开发者

姚镜堂 1万+

Android截屏录屏监听实战:兼容性方案与安全边界解析

在移动应用开发中,监听用户屏幕操作行为是一个涉及安全与体验的核心技术点。其原理通常基于系统提供的媒体库监听、投影服务回调等机制,通过感知系统层事件来响应截屏、录屏等动作。这项技术的价值在于,它能够帮助应用在金融交易、版权内容保护等场景下,及时做出安全响应或提供智能交互,例如自动隐藏敏感信息或添加分享水印。从工程实践角度,开发者需要综合考量兼容性、实时性与系统权限限制,尤其在Android不同版本和厂商定制系统下,方案选型差异显著。本文聚焦Android平台,深入探讨了基于ContentObserver的截屏

weixin_33728708的博客 397

Android APP 音视频(02)MediaProjection录屏与MediaCodec编码

这里主要是使用MediaProjection获取屏幕数据,将数据通过mediacodec编码输出到存储卡上。这里主要介绍 MediaProjection的基本原理和流程、 MediaCodec编码的简单说明,便于对代码有所理解。

wangdsh的博客 4688

Android MediaProjection实战:从权限适配到异常处理,构建Android Q+的稳定截屏录屏功能

本文深入探讨Android Q+中MediaProjection API的实战应用,涵盖权限适配、异常处理及性能优化等关键环节。通过详细代码示例和厂商设备兼容性分析,帮助开发者构建稳定的截屏录屏功能,特别针对Android 12+的前台服务要求和各ROM特性提供了解决方案。

weixin_27076351的博客 206

Android 5.0及以上版本的录屏与截屏功能实现与分析

本文还有配套的精品资源,点击获取 简介:Android系统中的录屏和截屏功能是进行应用测试、分享游戏过程或教学演示时常用的功能。自Android 5.0版本起,Google官方引入了内置的屏幕录制功能,简化了屏幕活动记录过程。本文将详细介绍从Android 5.0开始的录屏和截屏机制,包括系统截图与编程实现截屏的方法,系统录屏命令的使用,权限控制,参数设置,以及开发应用实现...

weixin_36047538的博客 1541

android实现录屏小功能录制画板屏幕共享

Android屏幕共享与直播-red5流媒体服务器搭建 https://blog.youkuaiyun.com/u011368551/article/details/93141240Android 11 拍照+录制视频保存到外部共享区域 https://blog.youkuaiyun.com/xiaobaaidaba123/article/details/121585680?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~f

chezabo6116的博客 296

Android基于MediaProjection的截屏录屏全攻略:从原理到Android 15适配

在Android开发中,屏幕捕获是高频刚需,涉及战绩分享、远程协助、操作教学等场景。实现屏幕捕获绕不开MediaProjection API,它无需root即可获取整个屏幕内容,配合VirtualDisplay能将屏幕画面映射到ImageReader或编码器Surface,从而同时支持静态截屏与视频录制。然而实际落地时,开发者常遭遇黑屏、权限失效、文件存储失败、Android 14前台服务类型未声明等兼容性问题。本文系统梳理了从权限申请到VirtualDisplay创建、ImageReader取帧、Medi

weixin_29184371的博客 123

提升应用体验:Android MediaProjection 截屏与录屏解决方案

提升应用体验:Android MediaProjection 截屏与录屏解决方案 【下载地址】AndroidMediaProjection截屏录屏-完美适配至AndroidQ及以上版本 本仓库提供了实现Android设备截屏与录屏功能的解决方案,特别针对Android Q(API级别29)引入的安全限制进行了优化。在An...

gitblog_09787的博客 951

MediaProjection 录屏截屏全适配指南:从授权到落盘避坑实战

屏幕捕捉是移动应用开发中常见且敏感的能力,系统通过 MediaProjection 统一管理授权与画面分发,确保用户知情并防止隐私泄露。其核心机制是创建 VirtualDisplay 将屏幕内容复制到指定 Surface,由消费方决定输出为静态截图还是动态视频流。理解这一设计逻辑后,开发者还需处理从 Android 5.0 到 Android 14 的版本差异、ROM 兼容性以及生命周期管理。在实际工程中,录屏与截屏涉及权限申请、前台服务类型、MediaStore 存储、音频源选择、性能参数调优等环节,任何

weixin_31102231的博客 299

Android截屏功能实现完整代码与技术解析

你以为拿到Bitmap就万事大吉了?接下来才是真正考验工程能力的地方:如何把这张图安全、合规、高效地保存下来?回顾这场截屏技术的演进,你会发现:代表了简单粗暴但局限明显的第一代方案;则是功能强大但引入复杂性的第二代解法;而真正的高手,懂得在两者之间找到平衡点——根据场景动态切换,构建弹性架构。这不仅是截屏的问题,也是整个Android开发的缩影。技术没有绝对的好坏,只有是否适合当前场景。最好的代码,不是最炫的,而是最稳的。

weixin_36382073的博客 1310

android录屏弹窗,android视频截屏&手机录屏实现代码

本文介绍了android视频截屏&手机录屏实现代码,分享给大家,希望对大家有帮助问题在android中有时候我们需要对屏幕进行截屏操作,单一的截屏操作好解决可以通过activity的顶层view DecorView获取一个bitmap,得到就是当前activity上面的全部视图。View view = activity.getWindow().getDecorView();view.set...

weixin_33054847的博客 744

Android截屏录屏避坑指南:MediaProjection从入门到Android 14适配

屏幕捕获是移动应用开发中的常见需求,从社交分享到客服反馈,从在线教育到系统工具,都离不开对屏幕画面的实时获取。在Android平台,官方提供的MediaProjection API自Android 5.0起便成为实现截屏与录屏的核心方案,其原理是通过用户授权后创建VirtualDisplay,将屏幕内容镜像渲染到指定的Surface上,从而支持生成静态图片、视频编码或实时推流。理解这套机制的技术价值在于:无需root权限即可获得完整画面,且具备跨版本兼容性。实际应用中,开发者需关注ImageReader取帧

weixin_29174385的博客 343

Android应用如何监听截屏、录屏与投屏操作:原理、实现与实战

在移动应用开发中,用户行为监听是保障应用安全与内容保护的关键技术。其核心原理在于通过系统提供的机制感知用户操作,例如利用ContentObserver监听媒体库文件变化来检测截屏,借助MediaProjectionManager回调追踪录屏和投屏会话。这项技术的价值在于让应用从被动响应升级为主动感知,能够在敏感操作发生时及时介入,有效防范内容泄露、作弊风险与数据盗用。典型的应用场景包括在线教育平台的版权内容保护、金融类App的交易安全防护以及在线考试系统的防作弊机制。本文将以Android平台为例,深入解析

weixin_33910759的博客 297

Android平台截屏功能实现完整代码实战

经过这一番深挖,我们可以总结出一个成熟截屏系统的五大支柱:维度关键点完整性使用捕获全视图树,包含状态栏、导航栏准确性根据创建匹配分辨率的Bitmap,避免模糊安全性Android 10+使用MediaStore,遵守Scoped Storage规范稳定性异步执行、OOM防护、弱引用防泄漏扩展性支持GIF录制、多图层合成、SurfaceView低延迟捕捉🎯 最终目标不是“能截图”,而是“

weixin_28872035的博客 1127

基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框.zip

基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起用户授权对话框 基于MediaProjection进行屏幕录制、截屏,每次开始时都会唤起

如何在1v1一对一视频直播交友APP中实现防录屏防截屏功能?

交友APP防录屏技术方案解析:随着1v1视频社交需求增长,防录屏功能成为开发重点。原生APP中,Android可通过MediaProjection API检测录屏,iOS使用UIScreen.isCaptured属性监测。防护措施包括模糊画面、暂停播放或弹出警告。技术实现示例展示了Swift代码如何监听录屏状态并隐藏敏感内容。需注意iOS无法完全阻止录屏,建议结合动态水印和DRM加密等增强防护。本文为开发者提供了跨平台防录屏的技术思路和实现方法。

m0_62969882的博客 1417

超声波 vs 红外 vs 激光雷达:扫地机器人避障传感器选型指南(实测对比)

本文深入对比了扫地机器人三种主流避障传感器——超声波、红外与激光雷达的核心原理与实测表现。文章基于成本、精度、环境适应性等关键指标,提供了清晰的选型决策树和典型场景配置方案,旨在帮助开发者与爱好者根据项目需求与预算,构建高效可靠的机器人避障系统。

h0i1j2k3l的博客 690

android 录屏自动运行,Android录屏+视频转Gif实现

jerry-wang-1154193-unsplash.jpg录屏转动图最近看见一个视频转GIF的开源项目:ffmpeg-commands-executor-library,有时会有手机录屏转成GIF动图的需求,都是下载一个录屏软件录屏,再下一个转换软件,一般是电脑上的软件或者在线转换,效果也不怎么好,就想借这个东西来做一个录屏转GIF合一的APPAndroid录屏Android 5.0+ 可以利...

weixin_35815640的博客 456

Discrete Optimization (Coursera) 学习笔记 Week 1 introduction (开个帖子)

Week 1 Introduction 这位教授Pascal Van Hentenryck 真的算是优化领域神级别的人物了吧?截一张Google scholar的图大家感受一下… 居然在Coursera上看到了他开的课:Discrete Optimization。试听了几节后,发现讲得很有激情,而且深入浅出。遂决定花暑假跟完这一门课。 这门课每周花两三个小时介绍基础概念,然后得花十几个小时写作业(coding)… 一开始以为Coursera上的课的作业应该不会太难,然后第一次作业(knapsack)我就被

ZJ_11701的博客 656

【实战指南】OpenClaw Telegram 群聊不响应完整解决方案:从获取群 ID 到关闭隐私模式全流程

将整个从“获取群组 ID → 配置 OpenClaw Telegram 通道 → 关闭隐私模式 → 测试”的全流程都整合进去。

hampeter的博客 3489
上一篇: Gradle系列(3)——Gradle extension(gradle扩展),如何自定义gradle扩展,AppPlugin,AppExtension原理
下一篇: Android OCR && 谷歌OCR TextRecognition用法介绍
cry kid
博客等级 码龄10年 144粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值