CocosCreator 3.6.1+ 实战:如何优雅地实现游戏截图保存到相册(附iOS/Android适配指南)
CocosCreator 3.6.1 移动端截图保存实战从像素到相册的完整路径最近在做一个社交属性很强的休闲游戏玩家通关后总想分享自己的“战绩”截图。一开始我们团队觉得这功能不就是“咔嚓”一下保存吗结果真上手才发现从CocosCreator的RenderTexture里把画面“抠”出来再稳稳当当地塞进用户手机相册中间要趟的坑可真不少。尤其是iOS和Android两大平台权限处理、API调用、图片方向各有各的脾气。如果你也正在为CocosCreator 3.6.1及以上版本的截图保存功能头疼特别是跨平台适配这块硬骨头那这篇结合了实战踩坑经验的指南或许能帮你省下不少折腾的时间。1. 核心原理从RenderTexture到图像数据的旅程在CocosCreator里实现截图本质上是一个“数据捕获与转换”的过程。我们看到的游戏画面是GPU渲染的结果。截图功能就是要把这一帧GPU渲染出的像素数据从显存里“读”出来转换成CPU能处理的图像数据格式最后编码成标准的图片文件如PNG、JPEG。1.1 RenderTexture你的虚拟画布RenderTexture渲染纹理是这个过程中的核心角色。你可以把它想象成一块虚拟的画布。通常相机Camera组件会将画面直接渲染到屏幕。但当我们把相机的targetTexture设置为一个RenderTexture时相机的渲染输出就会被“重定向”到这块虚拟画布上。// 创建一个与屏幕可视区域等大的RenderTexture const view view.getVisibleSize(); this.rt new RenderTexture(); this.rt.initialize({ width: view.width, height: view.height, }); // 将主相机的渲染目标指向这个RenderTexture const cameraComp this.mainCamera.getComponent(Camera); cameraComp.targetTexture this.rt;关键点RenderTexture的尺寸决定了你截图画面的分辨率。你可以选择全屏截图如上例也可以创建特定尺寸的RenderTexture来捕获UI层或某个特定区域的画面。1.2 readPixels获取原始像素数据画面被渲染到RenderTexture后我们需要通过readPixels方法读取其像素数据。这个方法返回一个Uint8Array即RGBA格式的原始像素数组。// 假设我们想截取屏幕上以(worldX, worldY)为中心宽w高h的区域 // 注意readPixels的坐标原点在左下角 const x Math.round(worldX - w / 2); const y Math.round(worldY - h / 2); const pixelBuffer this.rt.readPixels(x, y, w, h);注意readPixels是一个同步操作且可能比较耗时尤其在高分辨率下。切忌在每帧的更新循环update中调用否则会严重拖慢游戏性能。通常的做法是在一个确定的时机如点击截图按钮后调用并可能伴随一个短暂的画面冻结或加载提示。读取到的pixelBuffer是一个一维数组其长度为width * height * 4每个像素包含R、G、B、A四个通道各占1字节。数据的排列顺序是从左下角开始从左到右从下到上。1.3 像素数据的处理与平台差异拿到原始像素数据只是第一步。一个常见的需求是将这个数据在游戏内实时显示为一个Sprite比如做一个截图预览小窗。这里会遇到第一个平台差异点纹理的Y轴方向。// 将像素数据转换为Texture2D和SpriteFrame let img new ImageAsset(); img.reset({ _data: pixelBuffer, width: w, height: h, format: Texture2D.PixelFormat.RGBA8888, _compressed: false }); let texture new Texture2D(); texture.image img; let spriteFrame new SpriteFrame(); spriteFrame.texture texture; spriteFrame.packable false; // 避免被动态图集合并导致问题 // 关键的平台适配翻转Y轴 spriteFrame.flipUVY true; // 但在iOS/macOS原生平台上通常不需要翻转 if (sys.isNative (sys.os sys.OS.IOS || sys.os sys.OS.OSX)) { spriteFrame.flipUVY false; } // 应用SpriteFrame到预览节点 previewSprite.getComponent(Sprite).spriteFrame spriteFrame;这个flipUVY的差异源于不同图形APIOpenGL ES与Metal在纹理坐标系定义上的不同。记住这个设置它在后续保存图片时也同样重要。2. 引擎的进化jsb.saveImageData的登场与使用在CocosCreator 3.6.1版本之前将像素数据保存为本地图片文件是一件相当麻烦的事开发者往往需要自己编写或寻找原生插件Native Plugin来调用iOS的UIImageWriteToSavedPhotosAlbum或Android的MediaStore.Images.Media.insertImage。从3.6.1版本开始引擎内置了jsb.saveImageData方法这是一个巨大的便利。2.1 方法详解与基础调用jsb.saveImageData是引擎在原生平台iOS/Android上提供的一个全局方法用于将图像数据保存到设备本地。其基本函数签名如下以TypeScript环境下的描述为例/** * 保存图像数据到文件 * param data Uint8Array格式的RGB或RGBA像素数据 * param width 图像宽度 * param height 图像高度 * param filePath 目标文件路径可选 * param callback 保存完成后的回调函数参数为错误信息成功则为null或undefined和文件路径 * param format 图像格式默认为png可选jpg */ declare function saveImageData( data: Uint8Array, width: number, height: number, filePath?: string, callback?: (err: any, path: string) void, format?: string ): void;一个最基础的使用示例// 假设pixelBuffer是从RenderTexture.readPixels获取的RGBA数据 const pixelBuffer this.rt.readPixels(0, 0, width, height); // 定义回调函数 const saveCallback (err, savedPath) { if (err) { console.error(保存图片失败:, err); // 这里可以给用户一个提示 return; } console.log(图片已保存至:, savedPath); // 可以进一步处理如提示用户保存成功 }; // 调用保存不指定filePath则引擎会自动生成一个临时路径 if (sys.isNative jsb.saveImageData) { jsb.saveImageData(pixelBuffer, width, height, null, saveCallback, png); } else { console.warn(当前环境不支持jsb.saveImageData); // 在Web平台需要采用其他方案如使用HTML5的download属性或Canvas.toDataURL }2.2 文件路径策略与格式选择文件路径filePath这个参数是可选的。如果传入null或空字符串引擎会在设备可写目录如Android的/data/data/包名/files/iOS的Documents目录下自动生成一个唯一的文件名如render_to_sprite_image.png。如果你需要自定义文件名和位置可以传入完整路径例如const customPath jsb.fileUtils.getWritablePath() MyGameScreenshot_ Date.now() .png; jsb.saveImageData(pixelBuffer, width, height, customPath, saveCallback);使用jsb.fileUtils.getWritablePath()可以获取到应用有写入权限的沙盒目录。图像格式format支持png和jpg。PNG格式无损支持透明度但文件体积较大JPG格式有损不支持透明度但文件体积小适合分享。如果你的截图包含UI透明背景务必使用PNG格式。2.3 常见问题与性能优化数据格式匹配readPixels默认读取的是RGBA8888格式的数据这与jsb.saveImageData期望的输入是匹配的。如果你对数据进行了其他处理如转成RGB需要确保数组长度是width * height * channels。大图保存卡顿保存高分辨率图片如2K、4K是一个IO密集型操作可能会引起主线程短暂卡顿。建议异步处理jsb.saveImageData本身是异步的不会阻塞JavaScript线程太久但图片编码是同步的。对于超大图可以考虑在用户点击保存后显示一个“保存中”的提示。降低分辨率如果不是必须保存原分辨率可以先将RenderTexture的初始化尺寸设小或者读取像素后在保存前用Canvas 2D API进行缩放Web平台方案原生平台较复杂。内存管理Uint8Array像素数据可能非常大一张1080p的RGBA图约8MB。保存完成后应及时将对这些大数组的引用置为null以便JavaScript垃圾回收器能及时释放内存。const saveCallback (err, path) { // ... 处理完成逻辑 this._largePixelBuffer null; // 释放对大数组的引用 };3. 跨越平台鸿沟iOS与Android的相册保存适配使用jsb.saveImageData能将图片保存到应用的沙盒目录但这还不够。用户期望的是截图能进入系统的相册Photo Library/Gallery方便他们查看和分享。这一步就需要调用各自平台的原生能力并处理令人头疼的权限问题。3.1 Android适配MediaStore与运行时权限Android上向相册保存图片标准做法是使用MediaStoreAPI。你需要一个原生插件来暴露这个Java方法给JavaScript。这里给出一个简化版的插件思路和调用逻辑。原生插件Java部分示例// 假设有一个NativeHelper类 public class NativeHelper { public static void saveImageToGallery(final String imagePath, final String albumName) { // 1. 检查并申请WRITE_EXTERNAL_STORAGE权限针对Android 10以下 // 2. 使用MediaStore.Images.Media.insertImage将文件插入公共目录 // 3. 发送广播通知系统媒体库扫描新文件 // 4. 通过回调通知JS结果 } }TypeScript调用层// 首先用jsb.saveImageData将图片保存到沙盒文件 const tempPath jsb.fileUtils.getWritablePath() temp_screenshot.png; jsb.saveImageData(pixelBuffer, width, height, tempPath, (err, savedPath) { if (err) { /* 处理错误 */ return; } // 然后调用原生插件方法将文件移到相册 if (sys.os sys.OS.ANDROID) { // 假设通过反射或预绑定的方式调用 jsb.reflection.callStaticMethod( com/yourcompany/NativeHelper, saveImageToGallery, (Ljava/lang/String;Ljava/lang/String;)V, savedPath, MyGameScreenshots // 希望保存到的相册文件夹名 ); } });Android权限处理要点Android 版本关键权限存储策略注意事项 Android 10WRITE_EXTERNAL_STORAGE共享存储Shared Storage需要动态申请权限用户可能拒绝。Android 10无需该权限作用域存储媒体存储MediaStore直接使用MediaStoreAPI写入特定媒体目录无需申请WRITE_EXTERNAL_STORAGE。所有版本无应用私有目录jsb.saveImageData默认保存的位置其他应用无法访问。提示从Android 10API 29开始谷歌推行了作用域存储Scoped Storage。对于保存图片到公共相册最佳实践是直接使用MediaStore.Images.Media的insertImage方法或ContentResolver插入一条记录系统会自动处理文件的实际存储位置。这比申请WRITE_EXTERNAL_STORAGE权限并直接操作文件路径更规范、更安全。3.2 iOS适配Photos Framework与隐私描述iOS端使用Photos框架来保存图片到系统相册。同样需要原生插件来提供接口。原生插件Objective-C部分示例// NativeHelper.m #import Photos/Photos.h (void)saveImageToAlbum:(NSString *)imagePath albumName:(NSString *)albumName completion:(void (^)(BOOL success, NSString *msg))completion { NSURL *fileURL [NSURL fileURLWithPath:imagePath]; if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) { completion(NO, File not exist); return; } // 检查相册访问权限 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ if (status ! PHAuthorizationStatusAuthorized) { completion(NO, Photo library permission denied); return; } __block PHObjectPlaceholder *placeholder; [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 创建图片变更请求 PHAssetChangeRequest *creationRequest [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:fileURL]; placeholder creationRequest.placeholderForCreatedAsset; // 如果有指定相册将图片添加到该相册 if (albumName.length 0) { PHAssetCollection *targetAlbum [self getAlbumWithName:albumName]; if (targetAlbum) { PHAssetCollectionChangeRequest *albumChangeRequest [PHAssetCollectionChangeRequest changeRequestForAssetCollection:targetAlbum]; [albumChangeRequest addAssets:[placeholder]]; } } } completionHandler:^(BOOL success, NSError * _Nullable error) { NSString *message success ? Saved successfully : [NSString stringWithFormat:Save failed: %, error.localizedDescription]; completion(success, message); }]; }); }]; } // 辅助方法获取或创建指定名称的相册 (PHAssetCollection *)getAlbumWithName:(NSString *)albumName { /* ... */ }TypeScript调用层// 保存到临时文件后调用iOS原生方法 if (sys.os sys.OS.IOS) { // 假设通过原生绑定调用 jsb.reflection.callStaticMethod( NativeHelper, saveImageToAlbum:albumName:completion:, savedPath, MyGame, // 自定义相册名传空字符串则保存到“相机胶卷” (success: boolean, msg: string) { if (success) { console.log(已保存到iOS相册); } else { console.error(保存到相册失败:, msg); } } ); }iOS适配核心要点隐私描述Info.plist必须在Xcode工程的Info.plist文件中添加相册访问权限的描述否则应用会崩溃。keyNSPhotoLibraryAddUsageDescription/key string我们需要保存游戏截图到您的相册以便您分享精彩时刻。/string如果还需要读取相册则需要NSPhotoLibraryUsageDescription。对于仅保存前者足够。权限请求PHPhotoLibrary.requestAuthorization会向用户弹出授权对话框。务必在用户触发保存操作后再请求权限并妥善处理用户拒绝的情况。自定义相册使用getAlbumWithName这样的辅助方法创建或获取一个以你游戏命名的相册能让用户的截图更有组织性提升体验。3.3 统一的TypeScript封装与错误处理为了在游戏代码中优雅地使用我们可以将上述跨平台逻辑封装成一个工具函数export class ScreenshotUtils { /** * 截图并保存到系统相册 * param camera 用于截图的相机节点 * param width 截图宽度 * param height 截图高度 * param callback 完成回调 (success: boolean, message: string) */ public static captureAndSaveToAlbum(camera: Node, width: number, height: number, callback: (success: boolean, msg: string) void): void { // 1. 创建RenderTexture并截图省略具体代码参考第1章 // ... 获取 pixelBuffer ... // 2. 先保存到临时文件 const tempFileName screenshot_${Date.now()}.png; const tempPath jsb.fileUtils.getWritablePath() tempFileName; if (!sys.isNative || !jsb.saveImageData) { callback(false, 当前平台不支持截图保存); return; } jsb.saveImageData(pixelBuffer, width, height, tempPath, (fileErr, savedPath) { if (fileErr) { callback(false, 保存临时文件失败: ${fileErr}); return; } // 3. 根据平台调用原生相册保存 if (sys.os sys.OS.ANDROID) { this._saveToAndroidGallery(savedPath, callback); } else if (sys.os sys.OS.IOS) { this._saveToIOSAlbum(savedPath, MyGameAlbum, callback); } else { callback(false, 不支持的操作系统: ${sys.os}); } }); } private static _saveToAndroidGallery(path: string, callback: Function): void { // 调用Android原生插件 // ... 实现细节 ... } private static _saveToIOSAlbum(path: string, albumName: string, callback: Function): void { // 调用iOS原生插件 // ... 实现细节 ... } }错误处理策略用户拒绝权限在回调中明确告知用户“保存失败因为未获得相册访问权限”并可以引导用户去系统设置中开启。磁盘空间不足原生代码应捕获此类异常并通过回调返回友好提示。文件不存在在调用原生方法前先用jsb.fileUtils.isFileExist检查临时文件是否成功生成。4. 进阶技巧与性能优化实战掌握了基础保存功能后我们来看看如何做得更好、更高效。4.1 截图内容的精确控制你未必总是需要全屏截图。有时只需要截取游戏画面排除UI有时又只需要截取某个UI界面。分离渲染层使用多个相机。例如设置一个GameCamera只渲染3D场景和游戏角色另一个UICamera只渲染UI。截图时只将GameCamera的目标设为RenderTexture即可得到纯净的游戏画面截图。// 假设 gameCamera 和 uiCamera 是两个不同的相机节点 gameCamera.getComponent(Camera).targetTexture renderTexture; uiCamera.getComponent(Camera).targetTexture null; // UI相机依然渲染到屏幕 // ... 执行截图 ... gameCamera.getComponent(Camera).targetTexture null; // 恢复区域截图通过调整readPixels的参数和RenderTexture的视口viewport可以只读取屏幕的某一部分。这对于制作“头像裁剪”、“分享卡片”等功能非常有用。4.2 性能优化避免卡顿与内存峰值截图尤其是高频率或高分辨率的截图是性能敏感操作。对象池化RenderTexture频繁创建和销毁RenderTexture开销很大。可以创建一个RenderTexture对象池在需要时取出用完后重置并放回。export class RenderTexturePool { private static _pool: RenderTexture[] []; private static _defaultSize: Size new Size(1024, 1024); static get(width: number this._defaultSize.width, height: number this._defaultSize.height): RenderTexture { let rt this._pool.pop(); if (!rt) { rt new RenderTexture(); rt.initialize({ width, height }); } else if (rt.width ! width || rt.height ! height) { rt.resize(width, height); } return rt; } static put(rt: RenderTexture): void { if (rt this._pool.length 5) { // 控制池大小 this._pool.push(rt); } } }延迟与分帧操作不要在用户点击的同一帧内执行readPixels和saveImageData。使用scheduleOnce或setTimeout延迟到下一帧执行给渲染线程喘息之机。this.scheduleOnce(() { const pixelBuffer this._rt.readPixels(...); // ... 后续保存操作 }, 0); // 延迟一帧降低截图分辨率对于分享到社交平台的图片通常不需要屏幕原生分辨率。可以在创建RenderTexture时使用较小的尺寸或者读取像素后在保存前进行缩放Web端用Canvas 2D原生端可能需要借助原生库或引擎的Image处理。4.3 扩展应用Base64编码与网络传输除了保存到本地截图数据还有更多用途比如生成Base64字符串用于网页显示或即时通讯分享或者直接上传到游戏服务器。从本地文件或像素数据生成Base64/** * 将Uint8Array像素数据转换为Base64字符串 (RGBA格式) * 注意这是一个纯JS实现适用于小图。大图性能较差原生平台建议用原生方法。 */ static pixelBufferToBase64(data: Uint8Array, width: number, height: number): string { // 创建一个离屏CanvasWeb环境或使用Buffer处理 // 这里提供一个简化思路实际在Cocos Native环境中可能需要借助cc.assetManager或原生能力 // 更实用的方法是先通过jsb.saveImageData保存为临时文件再读取文件为base64 const tempPath jsb.fileUtils.getWritablePath() temp_base64.png; return new Promise((resolve, reject) { jsb.saveImageData(data, width, height, tempPath, (err) { if (err) reject(err); const fullData jsb.fileUtils.getDataFromFile(tempPath); if (fullData) { // 将ArrayBuffer转为Base64 const base64 btoa(String.fromCharCode(...new Uint8Array(fullData))); resolve(data:image/png;base64,${base64}); } else { reject(new Error(Read file data failed)); } }); }); } // 使用示例生成Base64并可能用于显示一个网络图片组件 const base64Str await ScreenshotUtils.pixelBufferToBase64(pixelBuffer, width, height); someWebViewComponent.url base64Str; // 假设有组件能显示Data URL直接上传二进制数据 如果你需要将截图直接上传到服务器完全不需要经过Base64转换Base64会增大约33%的体积。你可以直接读取保存的临时文件或者将pixelBuffer转换为BlobWeb或FormData通过原生网络请求进行上传。// 伪代码上传临时图片文件 const xhr new XMLHttpRequest(); const formData new FormData(); formData.append(screenshot, jsb.fileUtils.getDataFromFile(tempPath), screenshot.png); xhr.open(POST, https://your.server.com/upload); xhr.send(formData);实现一个稳定、高效、用户体验良好的截图保存功能确实是CocosCreator移动端开发中的一个经典挑战。从理解RenderTexture和readPixels的原理到熟练运用jsb.saveImageData再到深入处理iOS和Android平台迥异的相册权限与API每一步都需要仔细打磨。我在项目中最终采用的方案是将所有平台相关代码封装在一个统一的NativeBridge类里通过事件中心来通知前端保存状态这样业务逻辑就清爽多了。记住在真机上充分测试权限弹窗、存储空间不足、横竖屏切换等边界情况这些才是保证功能健壮性的关键。

相关新闻

如何永久保存QQ空间回忆?GetQzonehistory零门槛备份方案全解析

如何永久保存QQ空间回忆?GetQzonehistory零门槛备份方案全解析

如何永久保存QQ空间回忆?GetQzonehistory零门槛备份方案全解析 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 在数字记忆日益珍贵的今天,社交平台数据安全危机却…

2026/7/5 0:14:02 阅读更多 →
Qwen3-0.6B-FP8镜像免配置优势:预置CUDA Graphs优化,降低首token延迟37%

Qwen3-0.6B-FP8镜像免配置优势:预置CUDA Graphs优化,降低首token延迟37%

Qwen3-0.6B-FP8镜像免配置优势:预置CUDA Graphs优化,降低首token延迟37% 如果你正在寻找一个能在自己电脑上快速跑起来的AI对话工具,并且对“下载即用”、“开箱即聊”有执念,那么这篇文章就是为你准备的。今天要聊的&#xff0c…

2026/7/4 6:08:16 阅读更多 →
实战应用:基于快马平台与min(公益版)开发动态图片画廊管理界面

实战应用:基于快马平台与min(公益版)开发动态图片画廊管理界面

最近在做一个社区公益项目,需要一个简单、轻量级的图片展示和管理界面。考虑到项目性质,我希望前端部分足够精简,不引入庞大的框架。于是,我尝试了 min(公益版)这个轻量级JavaScript库,并借助 I…

2026/5/17 7:48:36 阅读更多 →

最新新闻

网络安全渗透测试入门:从DVWA到在线靶场的实战训练指南

网络安全渗透测试入门:从DVWA到在线靶场的实战训练指南

1. 靶场入门:为什么说它是渗透测试的“新手村”与“演武场”如果你刚接触网络安全,对“渗透测试”这个词既感到兴奋又有些迷茫,不知道从哪里开始动手,那么“靶场”就是你绕不开的第一个关键节点。你可以把它理解为一个完全合法、安…

2026/7/5 0:56:03 阅读更多 →
【大白话说Java面试题 第154题】【06_Spring篇】第14题:Spring 支持的 Bean 作用域

【大白话说Java面试题 第154题】【06_Spring篇】第14题:Spring 支持的 Bean 作用域

📌 PDF:大白话说Java面试题 — 06_Spring篇 第14题:Spring 支持的 Bean 作用域 📚 回答: 核心考点: Spring Bean 作用域是 Spring IoC 容器的核心设计之一,大厂面试不会只问"有哪几种&qu…

2026/7/5 0:56:03 阅读更多 →
跨线程大数据的免拷贝黑科技:拆解 Qt 内存管理与“非 const 性能刺客”

跨线程大数据的免拷贝黑科技:拆解 Qt 内存管理与“非 const 性能刺客”

在构建高性能系统(如局域网分布式总线、实时语音转文字终端、或本地 AI 模型中转网关)时,我们经常需要在不同的线程之间频繁流转海量的原始字节数据(如 QByteArray)。 许多初学者、甚至有经验的 C 开发者在刚接触 Qt 多…

2026/7/5 0:54:02 阅读更多 →
FModel:Unreal Engine游戏档案浏览器完整指南

FModel:Unreal Engine游戏档案浏览器完整指南

FModel:Unreal Engine游戏档案浏览器完整指南 【免费下载链接】FModel Unreal Engine Archives Explorer 项目地址: https://gitcode.com/gh_mirrors/fm/FModel FModel是一款基于C#开发的Unreal Engine档案浏览器,专为游戏开发者和逆向工程师设计…

2026/7/5 0:54:02 阅读更多 →
DockDoor终极指南:重新定义macOS窗口管理与效率革命

DockDoor终极指南:重新定义macOS窗口管理与效率革命

DockDoor终极指南:重新定义macOS窗口管理与效率革命 【免费下载链接】DockDoor Window peeking, alt-tab and other enhancements for macOS 项目地址: https://gitcode.com/gh_mirrors/do/DockDoor 你是否曾经在macOS上同时打开多个窗口,却为频繁…

2026/7/5 0:52:02 阅读更多 →
Elsevier Tracker:科研投稿状态监控的终极解决方案

Elsevier Tracker:科研投稿状态监控的终极解决方案

Elsevier Tracker:科研投稿状态监控的终极解决方案 【免费下载链接】Elsevier-Tracker 项目地址: https://gitcode.com/gh_mirrors/el/Elsevier-Tracker 还在为每天反复登录Elsevier系统查看论文审稿状态而烦恼吗?想象一下,当你提交了…

2026/7/5 0:52:02 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻