進(jìn)程間通信-CFNotificationCenterGetDarwinNotifyCenter

文章寫得不多、盡量只寫干貨

簡要

CFNotificationCenterGetDarwinNotifyCenter,是CoreFundation中的一個(gè)類,可以實(shí)現(xiàn)進(jìn)程間的通知,將通知從擴(kuò)展App發(fā)送到主App中。

而之前文章說的屏幕共享,使用了Broadcast Upload Extension,而這就是擴(kuò)展App,其負(fù)責(zé)采集和傳輸數(shù)據(jù),本章將講述數(shù)據(jù)傳輸?shù)暮唵螌?shí)現(xiàn)。

SampleHandler

SampleHandler中有諸多方法都是獲取各種信息的、我們需要把信息傳給主App:

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
    [self sendNotificationWithIdentifier:@"broadcastStartedWithSetupInfo" userInfo:setupInfo];
}

- (void)broadcastPaused {
    // User has requested to pause the broadcast. Samples will stop being delivered.
    [self sendNotificationWithIdentifier:@"broadcastPaused" userInfo:nil];
}

- (void)broadcastResumed {
    // User has requested to resume the broadcast. Samples delivery will resume.
    [self sendNotificationWithIdentifier:@"broadcastResumed" userInfo:nil];
}

- (void)broadcastFinished {
    // User has requested to finish the broadcast.
    [self sendNotificationWithIdentifier:@"broadcastFinished" userInfo:nil];
}

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:{
            // Handle video sample buffer
            //如果有網(wǎng)速不好的情況、請酌情丟棄數(shù)據(jù)、不要阻塞線程導(dǎo)致程序崩潰
            NSDictionary * info = [[NSDictionary alloc] initWithObjectsAndKeys:[self dataWithSampBuffer:sampleBuffer],@"buffer", nil];
            [self sendNotificationWithIdentifier:@"processSampleBuffer" userInfo:info];
        }
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}

identifier為通知標(biāo)識,為區(qū)分哪個(gè)方法發(fā)出的通知。

傳輸數(shù)據(jù)流

CMSampleBufferRef不能直接傳輸,那么我們把它轉(zhuǎn)換成NSData:

- (NSData *)dataWithSampBuffer:(CMSampleBufferRef)sampBuffer { CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    void *src_buff = CVPixelBufferGetBaseAddress(imageBuffer);
    NSData *data = [NSData dataWithBytes:src_buff length:bytesPerRow * height];
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    return data;
}

發(fā)送通知

- (void)sendNotificationWithIdentifier:(nullable NSString *)identifier userInfo:(NSDictionary *)info {
    CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
    CFDictionaryRef userInfo = (__bridge CFDictionaryRef)info;
    BOOL const deliverImmediately = YES;
    CFStringRef identifierRef = (__bridge CFStringRef)identifier;
    CFNotificationCenterPostNotification(center, identifierRef, NULL, userInfo, deliverImmediately);
}

主App

接收通知~首先需要:

注冊通知

identifier需要與發(fā)送端保持一致喲~~

- (void)addNotifications {
    [self registerNotificationsWithIdentifier:@"broadcastStartedWithSetupInfo"];
    [self registerNotificationsWithIdentifier:@"broadcastPaused"];
    [self registerNotificationsWithIdentifier:@"broadcastResumed"];
    [self registerNotificationsWithIdentifier:@"broadcastFinished"];
    [self registerNotificationsWithIdentifier:@"processSampleBuffer"];
    //這里同時(shí)注冊了分發(fā)消息的通知,在宿主App中使用
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(NotificationAction:) name:NotificationName object:nil];
}
- (void)registerNotificationsWithIdentifier:(nullable NSString *)identifier{
    CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
    CFStringRef str = (__bridge CFStringRef)identifier;
   
    CFNotificationCenterAddObserver(center,
                                    (__bridge const void *)(self),
                                    NotificationCallback,
                                    str,
                                    NULL,
                                    CFNotificationSuspensionBehaviorDeliverImmediately);
}

其中NotificationCallback為接到通知后使用此方法取值。

void NotificationCallback(CFNotificationCenterRef center,
                                   void * observer,
                                   CFStringRef name,
                                   void const * object,
                                   CFDictionaryRef userInfo) {
    NSString *identifier = (__bridge NSString *)name;
    NSObject *sender = (__bridge NSObject *)observer;
    //NSDictionary *info = (__bridge NSDictionary *)userInfo;
//    NSDictionary *info = CFBridgingRelease(userInfo);
    NSDictionary *notiUserInfo = @{@"identifier":identifier};
    [[NSNotificationCenter defaultCenter] postNotificationName:NotificationName
                                                        object:sender
                                                      userInfo:notiUserInfo];
}
結(jié)果輸出
- (void)NotificationAction:(NSNotification *)noti {
    NSDictionary *userInfo = noti.userInfo;
    NSString *identifier = userInfo[@"identifier"];
    
    if ([identifier isEqualToString:@"broadcastStartedWithSetupInfo"]) {
        NSLog(@"broadcastStartedWithSetupInfo");
    }
    if ([identifier isEqualToString:@"broadcastPaused"]) {
        NSLog(@"broadcastPaused");
    }
    if ([identifier isEqualToString:@"broadcastResumed"]) {
        NSLog(@"broadcastResumed");
    }
    if ([identifier isEqualToString:@"broadcastFinished"]) {
        NSLog(@"broadcastFinished");
    }
    if ([identifier isEqualToString:@"processSampleBuffer"]) {
        NSLog(@"processSampleBuffer");
    }
}

測試

這時(shí)你會發(fā)現(xiàn)你接到了擴(kuò)展中發(fā)出的通知,通過輸出測試突然發(fā)現(xiàn):傳的數(shù)據(jù)流哪去了?為什么沒有輸出?好奇怪,是不是擴(kuò)展沒有傳過來?

調(diào)試

運(yùn)行擴(kuò)展進(jìn)行斷點(diǎn)輸出:


斷點(diǎn)輸出

呃、事實(shí)證明我們確實(shí)傳輸了數(shù)據(jù)、那么數(shù)據(jù)究竟哪去了?

調(diào)研

懷著官網(wǎng)肯定不會騙我的心態(tài)開始了官網(wǎng)的"掃描"
CFNotificationCenterPostNotification

難過

CFNotificationCenterAddObserver
并沒有userInfo的接收參數(shù)

\color{red}{可以更改上邊的sendNotificationWithIdentifier方法不必傳輸userInfo了??}

所以:進(jìn)程級通知不允許傳輸數(shù)據(jù)??。。。ㄔ垡膊淮_定、只能在此請求大佬給予指點(diǎn)??)

App Groups:數(shù)據(jù)共享

App Groups詳情
此處直接使用代碼完成了,詳情請看上行鏈接

SampleHandler.m
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:{
            // Handle video sample buffer
            //如果有網(wǎng)速不好的情況、請酌情丟棄數(shù)據(jù)、不要阻塞線程導(dǎo)致程序崩潰
            [self saveNSDataWithFileManager:[self dataWithSampBuffer:sampleBuffer]];
            
        }
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}
- (void)saveNSDataWithFileManager:(NSData*)data{
    NSError *err = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.tongxun_xiaolang"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/data"];
    NSString *dataString = [[NSString alloc] initWithData:data encoding:kCFStringEncodingUTF8];
    BOOL result = [dataString writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err];
    if (result) {
        //已經(jīng)修改完sendNotificationWithIdentifier方法(不傳userInfo)
        [self sendNotificationWithIdentifier:@"processSampleBuffer"];
    }
}
主App
-(void)getDataWithFileManager{
    NSError *err = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.tongxun_xiaolang"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/data"];
    NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&err];
    NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];

    if (err != nil) {
        NSLog(@"xxxx %@",err);
        return;
    }
    NSLog(@"----%@",data);
}

且NotificationAction方法中:

if ([identifier isEqualToString:@"processSampleBuffer"]) {
        [self getDataWithFileManager];
    }
測試

主App已經(jīng)能拿到NSData(非SampleBuffer)明天添加轉(zhuǎn)化
但運(yùn)行一下之后擴(kuò)展突然崩潰了、原因:內(nèi)存不足、擴(kuò)展中不能大于50M數(shù)據(jù)、需要進(jìn)行編解碼處理~ 明天繼續(xù)

ps:沒那么簡單、、、在多種操作合并時(shí)卡住了??、修復(fù)中、、、

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容