删除录音相关文件

This commit is contained in:
2026-01-15 19:00:25 +08:00
parent d479d1903b
commit 8f4deaac4e
6 changed files with 1 additions and 404 deletions

View File

@@ -1,26 +0,0 @@
//
// KBVoiceBridgeNotification.h
// 通用的语音录制桥接常量App 与键盘扩展共享)
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// 扩展 -> 主 App请求开始录音
extern NSString * const KBDarwinVoiceStartRequest; // "com.loveKey.nyx.voice.start"
/// 扩展 -> 主 App请求停止录音
extern NSString * const KBDarwinVoiceStopRequest; // "com.loveKey.nyx.voice.stop"
/// 主 App -> 扩展:录音文件已就绪
extern NSString * const KBDarwinVoiceReady; // "com.loveKey.nyx.voice.ready"
/// 主 App -> 扩展:录音失败
extern NSString * const KBDarwinVoiceFailed; // "com.loveKey.nyx.voice.failed"
/// App Group: 录音文件路径NSString
extern NSString * const KBVoiceBridgeFilePathKey;
/// App Group: 录音错误信息NSString
extern NSString * const KBVoiceBridgeErrorKey;
/// App Group: 录音时间戳NSNumber
extern NSString * const KBVoiceBridgeTimestampKey;
NS_ASSUME_NONNULL_END

View File

@@ -1,14 +0,0 @@
//
// KBVoiceBridgeNotification.m
//
#import "KBVoiceBridgeNotification.h"
NSString * const KBDarwinVoiceStartRequest = @"com.loveKey.nyx.voice.start";
NSString * const KBDarwinVoiceStopRequest = @"com.loveKey.nyx.voice.stop";
NSString * const KBDarwinVoiceReady = @"com.loveKey.nyx.voice.ready";
NSString * const KBDarwinVoiceFailed = @"com.loveKey.nyx.voice.failed";
NSString * const KBVoiceBridgeFilePathKey = @"kb_voice_file_path";
NSString * const KBVoiceBridgeErrorKey = @"kb_voice_error";
NSString * const KBVoiceBridgeTimestampKey = @"kb_voice_ts";

View File

@@ -1,21 +0,0 @@
//
// KBVoiceRecordManager.h
// 主 App 录音管理(用于键盘桥接)
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBVoiceRecordManager : NSObject
+ (instancetype)shared;
- (void)startRecording;
- (void)stopRecording;
@property (nonatomic, assign, readonly, getter=isRecording) BOOL recording;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,312 +0,0 @@
//
// KBVoiceRecordManager.m
//
#import "KBVoiceRecordManager.h"
#import "KBConfig.h"
#import "KBVoiceBridgeNotification.h"
#import "KBHUD.h"
#import <AVFoundation/AVFoundation.h>
static void KBVoiceBridgeDarwinCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo);
@interface KBVoiceRecordManager () <AVAudioRecorderDelegate>
@property (nonatomic, strong) AVAudioRecorder *recorder;
@property (nonatomic, strong) NSURL *recordURL;
@property (nonatomic, assign, readwrite, getter=isRecording) BOOL recording;
@property (nonatomic, assign) BOOL pendingStart;
@end
@implementation KBVoiceRecordManager
+ (instancetype)shared {
static KBVoiceRecordManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBVoiceRecordManager new]; });
return m;
}
- (instancetype)init {
if (self = [super init]) {
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
KBVoiceBridgeDarwinCallback,
(__bridge CFStringRef)KBDarwinVoiceStartRequest,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
KBVoiceBridgeDarwinCallback,
(__bridge CFStringRef)KBDarwinVoiceStopRequest,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
}
return self;
}
- (void)dealloc {
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
(__bridge CFStringRef)KBDarwinVoiceStartRequest,
NULL);
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
(__bridge CFStringRef)KBDarwinVoiceStopRequest,
NULL);
}
static void KBVoiceBridgeDarwinCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
KBVoiceRecordManager *self = (__bridge KBVoiceRecordManager *)observer;
if (!self) { return; }
NSString *n = (__bridge NSString *)name;
NSLog(@"[KBVoiceBridge][App] Darwin received: %@", n);
dispatch_async(dispatch_get_main_queue(), ^{
if ([n isEqualToString:KBDarwinVoiceStartRequest]) {
[self startRecording];
} else if ([n isEqualToString:KBDarwinVoiceStopRequest]) {
[self stopRecording];
}
});
}
#pragma mark - Public
- (void)startRecording {
if (self.isRecording) {
NSLog(@"[KBVoiceBridge][App] startRecording already recording, stop then restart");
[self stopRecording];
// return;
}
NSLog(@"[KBVoiceBridge][App] startRecording begin");
[self kb_clearSharedState];
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionRecordPermission permission = session.recordPermission;
if (permission == AVAudioSessionRecordPermissionDenied) {
NSLog(@"[KBVoiceBridge][App] recordPermission denied");
[self kb_postFailed:KBLocalized(@"麦克风权限未开启")];
return;
}
if (permission == AVAudioSessionRecordPermissionUndetermined) {
NSLog(@"[KBVoiceBridge][App] recordPermission undetermined, requesting");
self.pendingStart = YES;
__weak typeof(self) weakSelf = self;
[session requestRecordPermission:^(BOOL granted) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) self = weakSelf;
if (!self) { return; }
if (!self.pendingStart) { return; }
self.pendingStart = NO;
if (!granted) {
NSLog(@"[KBVoiceBridge][App] recordPermission request denied");
[self kb_postFailed:KBLocalized(@"麦克风权限未开启")];
return;
}
NSLog(@"[KBVoiceBridge][App] recordPermission request granted");
[self startRecording];
});
}];
return;
}
NSError *error = nil;
if (@available(iOS 10.0, *)) {
[session setCategory:AVAudioSessionCategoryPlayAndRecord
mode:AVAudioSessionModeDefault
options:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
} else {
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
}
if (error) {
NSLog(@"[KBVoiceBridge][App] setCategory error: %@", error.localizedDescription);
[self kb_postFailed:KBLocalized(@"麦克风初始化失败")];
return;
}
[session setActive:YES error:&error];
if (error) {
NSLog(@"[KBVoiceBridge][App] setActive error: %@", error.localizedDescription);
[self kb_postFailed:error.localizedDescription ?: KBLocalized(@"麦克风启动失败")];
return;
}
if (!session.isInputAvailable) {
NSLog(@"[KBVoiceBridge][App] input not available");
[self kb_postFailed:KBLocalized(@"麦克风不可用")];
return;
}
NSURL *aacURL = [self kb_voiceFileURLWithExtension:@"m4a"];
if (!aacURL) {
NSLog(@"[KBVoiceBridge][App] app group not configured");
[self kb_postFailed:KBLocalized(@"App Group 未配置,无法共享录音")];
return;
}
NSDictionary *aacSettings = [self kb_voiceRecordSettingsAAC];
if ([self kb_tryStartRecorderWithSettings:aacSettings fileURL:aacURL error:&error]) {
NSLog(@"[KBVoiceBridge][App] recorder started (aac) url=%@", aacURL);
self.recordURL = aacURL;
self.recording = YES;
return;
}
NSURL *pcmURL = [self kb_voiceFileURLWithExtension:@"caf"];
if (!pcmURL) {
NSLog(@"[KBVoiceBridge][App] app group not configured");
[self kb_postFailed:KBLocalized(@"App Group 未配置,无法共享录音")];
return;
}
NSDictionary *pcmSettings = [self kb_voiceRecordSettingsPCM];
error = nil;
if ([self kb_tryStartRecorderWithSettings:pcmSettings fileURL:pcmURL error:&error]) {
NSLog(@"[KBVoiceBridge][App] recorder started (pcm) url=%@", pcmURL);
self.recordURL = pcmURL;
self.recording = YES;
return;
}
NSLog(@"[KBVoiceBridge][App] recorder start failed: %@", error.localizedDescription);
NSString *tip = error.localizedDescription ?: KBLocalized(@"录音启动失败,可能是系统限制或宿主 App 不允许录音");
[self kb_postFailed:tip];
}
- (void)stopRecording {
self.pendingStart = NO;
NSLog(@"[KBVoiceBridge][App] stopRecording");
if (self.recorder.isRecording) {
[self.recorder stop];
}
}
#pragma mark - AVAudioRecorderDelegate
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
[[AVAudioSession sharedInstance] setActive:NO error:nil];
NSLog(@"[KBVoiceBridge][App] finishRecording flag=%d url=%@", flag, recorder.url);
NSURL *fileURL = recorder.url ?: self.recordURL;
self.recorder = nil;
self.recordURL = nil;
self.recording = NO;
if (!flag || !fileURL) {
[self kb_postFailed:KBLocalized(@"录音失败")];
return;
}
[self kb_saveSharedFileURL:fileURL];
[self kb_postDarwin:KBDarwinVoiceReady];
}
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error {
[[AVAudioSession sharedInstance] setActive:NO error:nil];
NSLog(@"[KBVoiceBridge][App] encodeError: %@", error.localizedDescription);
self.recorder = nil;
self.recordURL = nil;
self.recording = NO;
[self kb_postFailed:error.localizedDescription ?: KBLocalized(@"录音失败")];
}
#pragma mark - Helpers
- (NSDictionary *)kb_voiceRecordSettingsAAC {
return @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVSampleRateKey: @(16000),
AVNumberOfChannelsKey: @(1),
AVEncoderAudioQualityKey: @(AVAudioQualityMedium)};
}
- (NSDictionary *)kb_voiceRecordSettingsPCM {
return @{AVFormatIDKey: @(kAudioFormatLinearPCM),
AVSampleRateKey: @(16000),
AVNumberOfChannelsKey: @(1),
AVLinearPCMBitDepthKey: @(16),
AVLinearPCMIsFloatKey: @(NO),
AVLinearPCMIsBigEndianKey: @(NO)};
}
- (NSURL *)kb_voiceFileURLWithExtension:(NSString *)ext {
NSURL *dirURL = [self kb_voiceDirectoryURL];
if (!dirURL) {
return nil;
}
NSTimeInterval ts = [[NSDate date] timeIntervalSince1970] * 1000;
NSString *safeExt = (ext.length > 0) ? ext : @"m4a";
NSString *fileName = [NSString stringWithFormat:@"kb_voice_%lld.%@", (long long)ts, safeExt];
return [dirURL URLByAppendingPathComponent:fileName];
}
- (NSURL *)kb_voiceDirectoryURL {
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:AppGroup];
if (!containerURL) {
return nil;
}
NSURL *dirURL = [containerURL URLByAppendingPathComponent:@"voice" isDirectory:YES];
if (dirURL && ![[NSFileManager defaultManager] fileExistsAtPath:dirURL.path]) {
[[NSFileManager defaultManager] createDirectoryAtURL:dirURL withIntermediateDirectories:YES attributes:nil error:nil];
}
return dirURL;
}
- (BOOL)kb_tryStartRecorderWithSettings:(NSDictionary *)settings fileURL:(NSURL *)fileURL error:(NSError **)error {
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:error];
if (*error || !recorder) {
NSLog(@"[KBVoiceBridge][App] create recorder failed: %@", (*error).localizedDescription);
return NO;
}
recorder.delegate = self;
recorder.meteringEnabled = YES;
if (![recorder prepareToRecord]) {
NSLog(@"[KBVoiceBridge][App] prepareToRecord failed");
return NO;
}
if (![recorder record]) {
NSLog(@"[KBVoiceBridge][App] record returned NO");
return NO;
}
self.recorder = recorder;
return YES;
}
- (NSUserDefaults *)kb_voiceUserDefaults {
return [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
}
- (void)kb_clearSharedState {
NSUserDefaults *ud = [self kb_voiceUserDefaults];
[ud removeObjectForKey:KBVoiceBridgeFilePathKey];
[ud removeObjectForKey:KBVoiceBridgeErrorKey];
[ud removeObjectForKey:KBVoiceBridgeTimestampKey];
[ud synchronize];
}
- (void)kb_saveSharedFileURL:(NSURL *)fileURL {
if (!fileURL) { return; }
NSUserDefaults *ud = [self kb_voiceUserDefaults];
[ud setObject:fileURL.path ?: @"" forKey:KBVoiceBridgeFilePathKey];
[ud setObject:@([[NSDate date] timeIntervalSince1970]) forKey:KBVoiceBridgeTimestampKey];
[ud removeObjectForKey:KBVoiceBridgeErrorKey];
[ud synchronize];
}
- (void)kb_saveSharedError:(NSString *)message {
NSUserDefaults *ud = [self kb_voiceUserDefaults];
[ud setObject:message ?: @"" forKey:KBVoiceBridgeErrorKey];
[ud setObject:@([[NSDate date] timeIntervalSince1970]) forKey:KBVoiceBridgeTimestampKey];
[ud removeObjectForKey:KBVoiceBridgeFilePathKey];
[ud synchronize];
}
- (void)kb_postFailed:(NSString *)message {
[self kb_saveSharedError:message];
[self kb_postDarwin:KBDarwinVoiceFailed];
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
NSString *tip = message.length > 0 ? message : KBLocalized(@"录音失败");
[KBHUD showInfo:tip];
}
}
- (void)kb_postDarwin:(NSString *)name {
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge CFStringRef)name,
NULL, NULL, true);
}
@end

View File

@@ -221,9 +221,6 @@
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
A1B2C4202EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; };
A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; };
A1B2C5052F31001000000001 /* KBVoiceBridgeNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C5022F31001000000001 /* KBVoiceBridgeNotification.m */; };
A1B2C5062F31001000000001 /* KBVoiceBridgeNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C5022F31001000000001 /* KBVoiceBridgeNotification.m */; };
A1B2C5072F31001000000001 /* KBVoiceRecordManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C5042F31001000000001 /* KBVoiceRecordManager.m */; };
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9022FBD000100000001 /* KBBackspaceLongPressHandler.m */; };
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */; };
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9082FBD000200000004 /* KBInputBufferManager.m */; };
@@ -638,10 +635,6 @@
A1B2C4002EB4A0A100000002 /* KBAuthManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAuthManager.m; sourceTree = "<group>"; };
A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardPermissionManager.m; sourceTree = "<group>"; };
A1B2C4232EB4B7A100000001 /* KBKeyboardPermissionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardPermissionManager.h; sourceTree = "<group>"; };
A1B2C5012F31001000000001 /* KBVoiceBridgeNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVoiceBridgeNotification.h; sourceTree = "<group>"; };
A1B2C5022F31001000000001 /* KBVoiceBridgeNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVoiceBridgeNotification.m; sourceTree = "<group>"; };
A1B2C5032F31001000000001 /* KBVoiceRecordManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVoiceRecordManager.h; sourceTree = "<group>"; };
A1B2C5042F31001000000001 /* KBVoiceRecordManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVoiceRecordManager.m; sourceTree = "<group>"; };
A1B2C9012FBD000100000001 /* KBBackspaceLongPressHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBackspaceLongPressHandler.h; sourceTree = "<group>"; };
A1B2C9022FBD000100000001 /* KBBackspaceLongPressHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBBackspaceLongPressHandler.m; sourceTree = "<group>"; };
A1B2C9032FBD000200000001 /* KBBackspaceUndoManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBackspaceUndoManager.h; sourceTree = "<group>"; };
@@ -1671,10 +1664,6 @@
0459D1B62EBA287900F2D189 /* KBSkinManager.m */,
049FB23D2EC4B6EF00FAB05D /* KBULBridgeNotification.h */,
049FB23E2EC4B6EF00FAB05D /* KBULBridgeNotification.m */,
A1B2C5012F31001000000001 /* KBVoiceBridgeNotification.h */,
A1B2C5022F31001000000001 /* KBVoiceBridgeNotification.m */,
A1B2C5032F31001000000001 /* KBVoiceRecordManager.h */,
A1B2C5042F31001000000001 /* KBVoiceRecordManager.m */,
04D1F6B02EDFF10A00B12345 /* KBSkinInstallBridge.h */,
04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */,
04791F8C2ED469C0004E8522 /* KBHostAppLauncher.h */,
@@ -1983,7 +1972,6 @@
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */,
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */,
049FB23F2EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
A1B2C5052F31001000000001 /* KBVoiceBridgeNotification.m in Sources */,
04791F992ED49CE7004E8522 /* KBFont.m in Sources */,
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */,
04FC95672EB0546C007BD342 /* KBKey.m in Sources */,
@@ -2075,8 +2063,6 @@
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */,
04122F7E2EC5FC5500EF7AB3 /* KBJfPayCell.m in Sources */,
049FB2402EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
A1B2C5062F31001000000001 /* KBVoiceBridgeNotification.m in Sources */,
A1B2C5072F31001000000001 /* KBVoiceRecordManager.m in Sources */,
04FC95C92EB1E4C9007BD342 /* BaseNavigationController.m in Sources */,
048908DD2EBF67EB00FABA60 /* KBSearchResultVC.m in Sources */,
05A1B2D12F5B1A2B3C4D5E60 /* KBSearchVM.m in Sources */,

View File

@@ -25,7 +25,6 @@
#import "KBUserSessionManager.h"
#import "KBLoginVC.h"
#import "KBConfig.h"
#import "KBVoiceRecordManager.h"
static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
@@ -62,8 +61,6 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
// 访
[KBNetworkManager shared].enabled = YES;
// Darwin
[KBVoiceRecordManager shared];
///
[self getNetJudge];
///
@@ -193,20 +190,7 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
} else if ([host isEqualToString:@"settings"]) { // kbkeyboard://settings
[self kb_openAppSettings];
return YES;
} else if ([host isEqualToString:@"voice"]) { // kbkeyboard://voice?action=start|stop
NSDictionary<NSString *, NSString *> *params = [self kb_queryParametersFromURL:url];
NSString *action = params[@"action"].lowercaseString;
NSLog(@"[KBVoiceBridge][App] openURL voice action=%@", action);
if ([action isEqualToString:@"start"]) {
[[KBVoiceRecordManager shared] startRecording];
return YES;
}
if ([action isEqualToString:@"stop"]) {
[[KBVoiceRecordManager shared] stopRecording];
return YES;
}
return YES;
}else if ([host isEqualToString:@"recharge"]) { // kbkeyboard://recharge
} else if ([host isEqualToString:@"recharge"]) { // kbkeyboard://recharge
NSDictionary<NSString *, NSString *> *params = [self kb_queryParametersFromURL:url];
NSString *productId = params[@"productId"];
BOOL autoPay = NO;