2025终极指南:ExoPlayer后台播放Service与通知栏控制完整实现
2025终极指南ExoPlayer后台播放Service与通知栏控制完整实现【免费下载链接】ExoPlayerThis project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media项目地址: https://gitcode.com/gh_mirrors/ex/ExoPlayerExoPlayer是Android平台上最强大的开源媒体播放库为开发者提供了完整的视频和音频播放解决方案。本文将深入探讨如何利用ExoPlayer实现专业的后台播放功能通过Service与通知栏的无缝集成让你的应用在后台运行时依然能够稳定播放音频并支持锁屏控制和通知栏交互。掌握这些技术你的应用将具备与Spotify、YouTube Music等专业音频应用相媲美的后台播放体验。 为什么需要后台播放Service在Android应用中实现后台播放面临三大挑战音频焦点管理、Service生命周期管理和用户交互界面。ExoPlayer通过精心设计的架构解决了这些问题音频焦点管理- 确保应用在播放时能正确处理系统音频焦点Service保活- 避免播放进程被系统回收用户交互- 提供锁屏控制和通知栏操作ExoPlayer直播窗口时间管理示意图 - 展示播放器如何处理直播流的时间轴️ 核心架构设计模块依赖关系ExoPlayer的后台播放功能主要依赖以下核心模块核心播放模块library/core/ - 提供基础的播放器功能UI组件模块library/ui/ - 包含通知管理和UI控件MediaSession扩展extensions/mediasession/ - 系统媒体会话集成技术栈选择dependencies { implementation com.google.android.exoplayer:exoplayer-core:2.19.1 implementation com.google.android.exoplayer:exoplayer-ui:2.19.1 implementation com.google.android.exoplayer:extension-mediasession:2.19.1 } 创建后台播放ServiceService基础实现创建一个继承自Service的播放器服务用于在后台管理ExoPlayer实例的生命周期public class AudioPlaybackService extends Service { private ExoPlayer player; private PlayerNotificationManager notificationManager; private AudioFocusManager audioFocusManager; Override public void onCreate() { super.onCreate(); initializePlayer(); setupAudioFocus(); createNotificationChannel(); setupMediaSession(); } private void initializePlayer() { // 创建ExoPlayer实例 player new ExoPlayer.Builder(this) .setAudioAttributes(AudioAttributes.DEFAULT, true) .setHandleAudioBecomingNoisy(true) .build(); // 设置播放器监听器 player.addListener(new Player.Listener() { Override public void onPlaybackStateChanged(int state) { handlePlaybackStateChange(state); } Override public void onPlayerError(PlaybackException error) { handlePlaybackError(error); } }); } }Service清单配置在AndroidManifest.xml中正确配置Serviceservice android:name.AudioPlaybackService android:foregroundServiceTypemediaPlayback android:exportedfalse android:enabledtrue intent-filter action android:nameandroid.intent.action.MEDIA_PLAYBACK_SERVICE / /intent-filter /service uses-permission android:nameandroid.permission.FOREGROUND_SERVICE / uses-permission android:nameandroid.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK / 通知栏播放器实现PlayerNotificationManager配置ExoPlayer提供了强大的PlayerNotificationManager工具类简化通知栏播放器的实现private void setupNotificationManager() { // 创建通知渠道Android 8.0必需 String channelId audio_playback_channel; String channelName 音频播放; if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { NotificationChannel channel new NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_LOW ); channel.setDescription(音频播放通知); channel.enableLights(false); channel.enableVibration(false); channel.setShowBadge(false); NotificationManager manager getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // 创建媒体描述适配器 MediaDescriptionAdapter descriptionAdapter new DefaultMediaDescriptionAdapter( new MediaDescriptionAdapter() { Override public CharSequence getCurrentContentTitle(Player player) { return getCurrentTitle(); } Override public PendingIntent createCurrentContentIntent(Player player) { Intent intent new Intent(AudioPlaybackService.this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return PendingIntent.getActivity( AudioPlaybackService.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); } // 其他方法实现... } ); // 创建通知管理器 notificationManager new PlayerNotificationManager.Builder( this, NOTIFICATION_ID, channelId ) .setMediaDescriptionAdapter(descriptionAdapter) .setNotificationListener(new NotificationListener() { Override public void onNotificationPosted( int notificationId, Notification notification, boolean ongoing ) { // 启动前台服务 startForeground(notificationId, notification); } Override public void onNotificationCancelled( int notificationId, boolean dismissedByUser ) { // 用户取消通知时停止服务 stopSelf(); } }) .setSmallIconResourceId(R.drawable.ic_music_note) .setNextActionIconResourceId(R.drawable.ic_skip_next) .setPreviousActionIconResourceId(R.drawable.ic_skip_previous) .setPlayActionIconResourceId(R.drawable.ic_play_arrow) .setPauseActionIconResourceId(R.drawable.ic_pause) .setStopActionIconResourceId(R.drawable.ic_stop) .build(); // 绑定播放器 notificationManager.setPlayer(player); }ExoPlayer UI布局自定义对比 - 展示默认布局与自定义覆盖布局的效果差异 MediaSession深度集成MediaSessionConnector配置MediaSessionConnector是ExoPlayer与Android系统MediaSession的桥梁实现锁屏控制、音量键控制等系统级功能private void setupMediaSession() { // 创建MediaSession mediaSession new MediaSessionCompat(this, AudioPlaybackService); mediaSession.setCallback(new MediaSessionCompat.Callback() { Override public void onPlay() { if (player ! null) { player.setPlayWhenReady(true); } } Override public void onPause() { if (player ! null) { player.setPlayWhenReady(false); } } // 其他回调方法... }); mediaSession.setActive(true); // 创建MediaSessionConnector MediaSessionConnector connector new MediaSessionConnector(mediaSession); // 设置播放器 connector.setPlayer(player); // 设置自定义命令处理器 connector.setCustomActionProviders( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_REPEAT, Repeat, R.drawable.ic_repeat ).build() ); // 将MediaSession令牌传递给通知管理器 notificationManager.setMediaSessionToken(mediaSession.getSessionToken()); }播放队列管理对于需要管理播放列表的应用可以扩展QueueNavigatorconnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) { Override public MediaDescriptionCompat getMediaDescription( Player player, int windowIndex ) { MediaItem mediaItem player.getMediaItemAt(windowIndex); return new MediaDescriptionCompat.Builder() .setMediaId(mediaItem.mediaId) .setTitle(mediaItem.mediaMetadata.title) .setSubtitle(mediaItem.mediaMetadata.artist) .setIconUri(mediaItem.mediaMetadata.artworkUri) .build(); } }); 音频焦点管理AudioFocusManager使用ExoPlayer内置了AudioFocusManager简化音频焦点处理private void setupAudioFocus() { audioFocusManager new AudioFocusManager( this, new AudioFocusManager.PlayerCommand() { Override public void execute(int playerCommand) { switch (playerCommand) { case AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY: player.setPlayWhenReady(true); break; case AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY: player.setPlayWhenReady(false); break; } } } ); // 设置音频焦点类型 audioFocusManager.setAudioAttributes( new AudioAttributes.Builder() .setUsage(C.USAGE_MEDIA) .setContentType(C.CONTENT_TYPE_MUSIC) .build(), AudioFocusManager.AUDIOFOCUS_GAIN ); } private boolean requestAudioFocus() { return audioFocusManager.requestAudioFocus(); } private void abandonAudioFocus() { audioFocusManager.abandonAudioFocus(); } 完整的Service实现Service生命周期管理public class AudioPlaybackService extends Service { private static final int NOTIFICATION_ID 1; private static final String ACTION_PLAY ACTION_PLAY; private static final String ACTION_PAUSE ACTION_PAUSE; private static final String ACTION_STOP ACTION_STOP; private ExoPlayer player; private PlayerNotificationManager notificationManager; private MediaSessionCompat mediaSession; private AudioFocusManager audioFocusManager; Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent ! null) { String action intent.getAction(); String mediaUri intent.getStringExtra(MEDIA_URI); if (ACTION_PLAY.equals(action) mediaUri ! null) { playMedia(mediaUri); } else if (ACTION_PAUSE.equals(action)) { pausePlayback(); } else if (ACTION_STOP.equals(action)) { stopPlayback(); } } return START_STICKY; } private void playMedia(String mediaUri) { // 请求音频焦点 if (!requestAudioFocus()) { // 音频焦点请求失败 stopSelf(); return; } // 准备媒体内容 MediaItem mediaItem MediaItem.fromUri(mediaUri); player.setMediaItem(mediaItem); player.prepare(); player.setPlayWhenReady(true); // 更新通知和MediaSession updateNotification(); updateMediaSession(); } Override public void onDestroy() { // 清理资源 if (notificationManager ! null) { notificationManager.setPlayer(null); } if (player ! null) { player.release(); player null; } if (mediaSession ! null) { mediaSession.setActive(false); mediaSession.release(); } abandonAudioFocus(); super.onDestroy(); } // 其他方法... }从Activity控制Servicepublic class MainActivity extends AppCompatActivity { private void startPlaybackService(String mediaUri) { Intent serviceIntent new Intent(this, AudioPlaybackService.class); serviceIntent.setAction(AudioPlaybackService.ACTION_PLAY); serviceIntent.putExtra(MEDIA_URI, mediaUri); if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { ContextCompat.startForegroundService(this, serviceIntent); } else { startService(serviceIntent); } } private void pausePlayback() { Intent serviceIntent new Intent(this, AudioPlaybackService.class); serviceIntent.setAction(AudioPlaybackService.ACTION_PAUSE); startService(serviceIntent); } private void stopPlayback() { Intent serviceIntent new Intent(this, AudioPlaybackService.class); serviceIntent.setAction(AudioPlaybackService.ACTION_STOP); startService(serviceIntent); } } 自定义通知样式自定义通知布局如果需要更复杂的通知样式可以创建自定义通知布局!-- res/layout/custom_notification.xml -- RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_height64dp android:padding8dp ImageView android:idid/album_art android:layout_width48dp android:layout_height48dp android:layout_alignParentStarttrue android:layout_centerVerticaltrue android:scaleTypecenterCrop / LinearLayout android:layout_widthwrap_content android:layout_heightwrap_content android:layout_toEndOfid/album_art android:layout_centerVerticaltrue android:layout_marginStart12dp android:orientationvertical TextView android:idid/title android:layout_widthwrap_content android:layout_heightwrap_content android:textSize14sp android:textColorandroid:color/white android:maxLines1 android:ellipsizeend / TextView android:idid/subtitle android:layout_widthwrap_content android:layout_heightwrap_content android:textSize12sp android:textColorandroid:color/white android:maxLines1 android:ellipsizeend / /LinearLayout !-- 控制按钮等 -- /RelativeLayout自定义MediaDescriptionAdapterpublic class CustomMediaDescriptionAdapter implements MediaDescriptionAdapter { private final Context context; private final Bitmap defaultAlbumArt; public CustomMediaDescriptionAdapter(Context context) { this.context context; this.defaultAlbumArt BitmapFactory.decodeResource( context.getResources(), R.drawable.default_album_art ); } Override public CharSequence getCurrentContentTitle(Player player) { MediaItem currentMediaItem player.getCurrentMediaItem(); if (currentMediaItem ! null currentMediaItem.mediaMetadata.title ! null) { return currentMediaItem.mediaMetadata.title; } return context.getString(R.string.unknown_title); } Override public Bitmap getCurrentLargeIcon( Player player, PlayerNotificationManager.BitmapCallback callback ) { // 异步加载专辑封面 MediaItem currentMediaItem player.getCurrentMediaItem(); if (currentMediaItem ! null currentMediaItem.mediaMetadata.artworkUri ! null) { loadAlbumArtAsync(currentMediaItem.mediaMetadata.artworkUri, callback); return null; // 返回null表示异步加载 } return defaultAlbumArt; } private void loadAlbumArtAsync( Uri artworkUri, PlayerNotificationManager.BitmapCallback callback ) { // 使用Glide或Picasso异步加载图片 // 加载完成后调用callback.onBitmap } }高分辨率媒体资源示例 - 展示ExoPlayer处理高质量图片/视频的能力⚡ 性能优化技巧内存管理及时释放资源在Service的onDestroy中释放所有资源使用适当的缓存策略配置ExoPlayer的缓存大小避免内存泄漏使用弱引用或静态内部类private static class PlayerHolder { private final WeakReferenceAudioPlaybackService serviceRef; PlayerHolder(AudioPlaybackService service) { this.serviceRef new WeakReference(service); } void play(String url) { AudioPlaybackService service serviceRef.get(); if (service ! null service.player ! null) { service.player.setMediaItem(MediaItem.fromUri(url)); service.player.prepare(); service.player.setPlayWhenReady(true); } } }电池优化使用WakeLock在播放时保持设备唤醒优化网络使用使用合适的缓冲策略及时释放WakeLock播放停止后立即释放private PowerManager.WakeLock wakeLock; private void acquireWakeLock() { PowerManager powerManager (PowerManager) getSystemService(POWER_SERVICE); wakeLock powerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, AudioPlaybackService::WakeLock ); wakeLock.acquire(10 * 60 * 1000L /*10分钟*/); } private void releaseWakeLock() { if (wakeLock ! null wakeLock.isHeld()) { wakeLock.release(); wakeLock null; } } 常见问题与解决方案问题1通知栏控制按钮不响应解决方案确保正确设置了MediaSession检查Notification的PendingIntent配置验证MediaSessionConnector是否正确绑定// 确保MediaSession已激活 mediaSession.setActive(true); // 检查PendingIntent的flags PendingIntent contentIntent PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE );问题2后台播放被系统杀死解决方案使用前台Service正确处理Service的START_STICKY实现onTaskRemoved重启逻辑Override public void onTaskRemoved(Intent rootIntent) { // 任务被移除时重新启动Service Intent restartService new Intent(this, AudioPlaybackService.class); restartService.setPackage(getPackageName()); startService(restartService); super.onTaskRemoved(rootIntent); }问题3音频焦点冲突解决方案正确处理音频焦点变化实现音频焦点监听器提供用户可配置选项audioFocusManager.setAudioFocusChangeListener(new AudioManager.OnAudioFocusChangeListener() { Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: // 永久失去焦点停止播放 stopPlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // 暂时失去焦点暂停播放 if (player.isPlaying()) { player.pause(); shouldResumeOnFocusGain true; } break; case AudioManager.AUDIOFOCUS_GAIN: // 重新获得焦点恢复播放 if (shouldResumeOnFocusGain !player.isPlaying()) { player.play(); } shouldResumeOnFocusGain false; break; } } }); 进一步学习资源官方文档和源码ExoPlayer官方文档docs/ - 包含完整的API文档和使用指南核心播放器源码library/core/src/main/java/com/google/android/exoplayer2/ - 深入理解播放器实现UI组件源码library/ui/src/main/java/com/google/android/exoplayer2/ui/ - 学习UI组件实现MediaSession扩展extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/ - MediaSession集成实现示例应用主Demo应用demos/main/ - 完整的播放器示例Cast Demodemos/cast/ - 投屏功能示例Transformer Demodemos/transformer/ - 媒体转换示例最佳实践测试不同场景在后台、锁屏、多任务等场景下测试性能监控使用Android Profiler监控内存和CPU使用用户反馈收集用户反馈持续优化体验 总结通过本文的完整指南你已经掌握了使用ExoPlayer实现专业级后台播放服务的所有关键技术。从基础的Service创建到复杂的通知栏控制从音频焦点管理到MediaSession集成每个环节都经过了精心设计和优化。记住这些关键点使用前台Service确保后台播放稳定性合理管理音频焦点避免冲突充分利用PlayerNotificationManager简化通知实现通过MediaSessionConnector实现系统级集成注重性能优化和电池效率现在你已经具备了构建专业音频播放应用的所有知识。开始实现你的ExoPlayer后台播放功能为用户提供无缝的音频体验吧提示在实际项目中建议参考ExoPlayer的官方示例和测试用例确保实现的最佳实践和兼容性。定期检查项目的RELEASENOTES.md文件了解最新功能和改进。【免费下载链接】ExoPlayerThis project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media项目地址: https://gitcode.com/gh_mirrors/ex/ExoPlayer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

3个终极华硕笔记本控制指南:告别臃肿软件,重获性能自由

3个终极华硕笔记本控制指南:告别臃肿软件,重获性能自由

3个终极华硕笔记本控制指南:告别臃肿软件,重获性能自由 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook,…

2026/10/13 16:26:15 阅读更多 →
终极指南:PoeCharm汉化版快速上手,打造你的《流放之路》最强角色

终极指南:PoeCharm汉化版快速上手,打造你的《流放之路》最强角色

终极指南:PoeCharm汉化版快速上手,打造你的《流放之路》最强角色 【免费下载链接】PoeCharm Path of Building Chinese version 项目地址: https://gitcode.com/gh_mirrors/po/PoeCharm 还在为《流放之路》复杂的角色构建头疼吗?PoeCh…

2026/10/11 20:44:18 阅读更多 →
3分钟搞定QQ空间历史说说备份:GetQzonehistory免费工具终极指南

3分钟搞定QQ空间历史说说备份:GetQzonehistory免费工具终极指南

3分钟搞定QQ空间历史说说备份:GetQzonehistory免费工具终极指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否担心QQ空间里的珍贵回忆会随着时间消失?那…

2026/10/11 20:44:19 阅读更多 →

最新新闻

libIEC61850 1.6.2:开源 IEC 61850 MMS/GOOSE/SV 协议栈的功能全貌、构建流程与集成实践

libIEC61850 1.6.2:开源 IEC 61850 MMS/GOOSE/SV 协议栈的功能全貌、构建流程与集成实践

通信嵌入式工业制造 【免费下载链接】libiec61850 Official repository for libIEC61850, the open-source library for the IEC 61850 protocols 项目地址: https://gitcode.com/gh_mirrors/li/libiec61850 点击查看 免费下载 libIEC61850 是一个以 C99 编写的开源…

2026/10/14 16:55:10 阅读更多 →
ESP32嵌入式应用商店:轻量级OTA固件分发系统设计

ESP32嵌入式应用商店:轻量级OTA固件分发系统设计

1. 这不是在ESP32上“造轮子”,而是在给嵌入式设备装上“操作系统级入口”你有没有试过给家里的智能灯泡升级固件?得先连Wi-Fi,再打开某个App,输入设备密码,等进度条走到一半突然卡住,最后弹出一句“升级失…

2026/10/14 16:55:10 阅读更多 →
CAD Sketcher 交互系统解析:有状态操作、连续绘制、实时吸附与自动约束

CAD Sketcher 交互系统解析:有状态操作、连续绘制、实时吸附与自动约束

桌面应用3D建模 【免费下载链接】CAD_Sketcher Constraint-based geometry sketcher for blender 项目地址: https://gitcode.com/gh_mirrors/ca/CAD_Sketcher 点击查看 免费下载 CAD Sketcher 为 Blender 引入了一个以"有状态操作"为核心的交互框架&…

2026/10/14 16:55:10 阅读更多 →
Windows下用MinGW编译libMesh:从configure到make install全流程

Windows下用MinGW编译libMesh:从configure到make install全流程

简介:这是一份面向Windows开发者、基于Mingw工具链编译libmesh有限元库的资源包,适用于需要在C或Python环境下进行有限元分析、科学计算与工程仿真的中高级用户。资源围绕“libmesh Mingw编译与应用”整理,覆盖Mingw-w64环境搭建、CMake配置、…

2026/10/14 16:55:10 阅读更多 →
实时推荐系统架构拆解:从实时特征到增量训练的完整链路

实时推荐系统架构拆解:从实时特征到增量训练的完整链路

最近组里在折腾推荐链路,把实时推荐这一块的论文和技术方案翻了不少。有一篇论文让我印象很深,讲的是某家头部互联网公司自研的一套实时推荐系统。这套系统的核心不是某个特别复杂的模型,而是把实时链路从行为采集、特征计算、召回、排序到样…

2026/10/14 16:55:10 阅读更多 →
pcie协议学习(3)-枚举

pcie协议学习(3)-枚举

1.链路的训练(硬件上电后,自发行为, 不需要软件参与)当外部 PCIe 设备链路训练成功(LTSSM → L0)后,链路状态进入L0状态,这个是host 能够枚举到pcie 外设的前提。只有进入L0阶段&…

2026/10/14 16:54:09 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →