From a711be4c4d9c3a484993ea6063a7c4d65e5672a2 Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Thu, 26 Feb 2026 21:47:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=A8=E8=BF=9B=E7=A8=8B=20=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E7=94=A8ai=20=20=E5=9C=A8=E4=B8=BB=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E9=87=8C=E4=B9=9F=E8=A6=81=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 6 +- .../KeyboardViewController+Chat.m | 19 +++++++ Shared/KBConfig.h | 6 ++ .../Class/AiTalk/V/Chat/KBPersonaChatCell.h | 3 + .../Class/AiTalk/V/Chat/KBPersonaChatCell.m | 15 ++++- keyBoard/Class/AiTalk/VC/KBAIHomeVC.m | 57 +++++++++++++++++++ 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 30acc2e..1765a18 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,11 @@ "permissions": { "allow": [ "WebSearch", - "Bash(git checkout:*)" + "Bash(git checkout:*)", + "Bash(xcodebuild:*)", + "Bash(plutil:*)", + "Bash(find:*)", + "Bash(ls:*)" ] } } diff --git a/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Chat.m b/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Chat.m index c0a52ed..4cec103 100644 --- a/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Chat.m +++ b/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Chat.m @@ -371,6 +371,9 @@ static const NSUInteger kKBChatMessageLimit = 6; audioId:response.data.audioId]; NSLog(@"[KB] AI 消息添加完成"); + // 通知主 App 刷新对应 persona 的聊天记录 + [self kb_notifyMainAppChatUpdatedWithCompanionId:companionId]; + // 如果有 audioId,开始预加载音频 if (response.data.audioId.length > 0) { [self kb_preloadAudioWithAudioId: @@ -671,6 +674,22 @@ static const NSUInteger kKBChatMessageLimit = 6; NSLog(@"[Keyboard] 开始播放音频,时长: %.2f秒", player.duration); } +#pragma mark - Notify Main App + +/// 通知主 App 刷新对应 persona 的聊天记录 +- (void)kb_notifyMainAppChatUpdatedWithCompanionId:(NSInteger)companionId { + NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup]; + [ud setInteger:companionId forKey:AppGroup_ChatUpdatedCompanionId]; + [ud synchronize]; + + CFNotificationCenterPostNotification( + CFNotificationCenterGetDarwinNotifyCenter(), + (__bridge CFStringRef)kKBDarwinChatUpdated, + NULL, NULL, true); + + NSLog(@"[KB] 已通知主 App 刷新 companionId=%ld 的聊天记录", (long)companionId); +} + #pragma mark - KBChatLimitPopViewDelegate - (void)chatLimitPopViewDidTapCancel:(KBChatLimitPopView *)view { diff --git a/Shared/KBConfig.h b/Shared/KBConfig.h index 12f34e3..962d4a6 100644 --- a/Shared/KBConfig.h +++ b/Shared/KBConfig.h @@ -30,6 +30,12 @@ /// 用户头像 URL(主 App 写入,键盘扩展读取) #define AppGroup_UserAvatarURL @"AppGroup_UserAvatarURL" +/// 键盘扩展聊天更新的 companionId(键盘写入,主 App 读取后刷新对应聊天记录) +#define AppGroup_ChatUpdatedCompanionId @"AppGroup_ChatUpdatedCompanionId" + +/// Darwin 跨进程通知:键盘扩展发送聊天消息后通知主 App 刷新 +#define kKBDarwinChatUpdated @"com.loveKey.nyx.chat.updated" + /// 皮肤图标加载模式: /// 0 = 使用本地 Assets 图片名(key_icons 的 value 写成图片名,例如 "kb_q_melon") /// 1 = 使用远程 Zip 皮肤包(skinJSON 中提供 zip_url;key_icons 的 value 写成 Zip 内图标文件名,例如 "key_a") diff --git a/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.h b/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.h index fc5c9b9..fb2e94f 100644 --- a/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.h +++ b/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.h @@ -69,6 +69,9 @@ NS_ASSUME_NONNULL_BEGIN /// 当前 Cell 不再是屏幕主显示页 - (void)onResignedCurrentPersonaCell; +/// 刷新聊天记录(重置分页状态,从第一页重新加载) +- (void)refreshChatHistory; + @end NS_ASSUME_NONNULL_END diff --git a/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.m b/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.m index b5ccf75..9f346a4 100644 --- a/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.m +++ b/keyBoard/Class/AiTalk/V/Chat/KBPersonaChatCell.m @@ -256,7 +256,20 @@ static NSString * const KBChatSessionDidResetNotification = @"KBChatSessionDidRe if (self.hasLoadedData || self.isLoading) { return; } - + + [self loadChatHistory]; +} + +- (void)refreshChatHistory { + // 重置分页状态 + self.currentPage = 1; + self.hasMoreHistory = YES; + self.hasLoadedData = NO; + self.isLoading = NO; + + // 清空当前消息并重新加载 + [self.messages removeAllObjects]; + [self.chatView clearMessages]; [self loadChatHistory]; } diff --git a/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m b/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m index b685fbd..68ea210 100644 --- a/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m +++ b/keyBoard/Class/AiTalk/VC/KBAIHomeVC.m @@ -108,6 +108,19 @@ static NSString * const KBAISelectedPersonaIdKey = @"KBAISelectedPersonaId"; +#pragma mark - Darwin Notification Callback (键盘扩展聊天更新) + +static void KBChatUpdatedDarwinCallback(CFNotificationCenterRef center, + void *observer, + CFStringRef name, + const void *object, + CFDictionaryRef userInfo) { + KBAIHomeVC *self = (__bridge KBAIHomeVC *)observer; + dispatch_async(dispatch_get_main_queue(), ^{ + [self kb_handleChatUpdatedFromExtension]; + }); +} + #pragma mark - Keyboard Gate /// 查找当前 view 树里的 firstResponder @@ -163,6 +176,15 @@ static NSString * const KBAISelectedPersonaIdKey = @"KBAISelectedPersonaId"; [self setupKeyboardNotifications]; [self setupKeyboardDismissGesture]; [self loadPersonas]; + + // 监听键盘扩展聊天更新的 Darwin 跨进程通知 + CFNotificationCenterAddObserver( + CFNotificationCenterGetDarwinNotifyCenter(), + (__bridge const void *)(self), + KBChatUpdatedDarwinCallback, + (__bridge CFStringRef)kKBDarwinChatUpdated, + NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); } - (void)viewDidAppear:(BOOL)animated { @@ -763,6 +785,36 @@ static NSString * const KBAISelectedPersonaIdKey = @"KBAISelectedPersonaId"; return nil; } +#pragma mark - 键盘扩展聊天更新处理 + +/// 收到键盘扩展的聊天更新通知后,刷新对应 persona 的聊天记录 +- (void)kb_handleChatUpdatedFromExtension { + NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup]; + NSInteger companionId = [ud integerForKey:AppGroup_ChatUpdatedCompanionId]; + if (companionId <= 0) { + return; + } + + NSLog(@"[KBAIHomeVC] 收到键盘扩展聊天更新通知,companionId=%ld", (long)companionId); + + // 查找对应 persona 的索引 + NSInteger index = [self indexOfPersonaId:companionId]; + if (index == NSNotFound) { + NSLog(@"[KBAIHomeVC] 未找到 companionId=%ld 对应的 persona", (long)companionId); + return; + } + + // 获取对应的 cell 并刷新聊天记录 + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0]; + KBPersonaChatCell *cell = (KBPersonaChatCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; + if (cell) { + [cell refreshChatHistory]; + NSLog(@"[KBAIHomeVC] 已触发 companionId=%ld 的聊天记录刷新", (long)companionId); + } else { + NSLog(@"[KBAIHomeVC] companionId=%ld 的 cell 不可见,下次显示时会自动加载", (long)companionId); + } +} + - (NSInteger)indexOfPersonaId:(NSInteger)personaId { if (personaId <= 0) { return NSNotFound; @@ -1360,6 +1412,11 @@ static NSString * const KBAISelectedPersonaIdKey = @"KBAISelectedPersonaId"; - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; + CFNotificationCenterRemoveObserver( + CFNotificationCenterGetDarwinNotifyCenter(), + (__bridge const void *)(self), + (__bridge CFStringRef)kKBDarwinChatUpdated, + NULL); } @end