iOS录屏直播(四)主App和宿主App数据共享,通信功能实现
文章目錄
- CFNotificationCenterGetDarwinNotifyCenter
- 發送通知
- 接收通知
- 注意事項
- 遺留問題
- 補充
Morris_
2019.06.17
上一篇總結了一下AppGroup相關的基礎知識,通過AppGroup組即可實現App之間共享同一塊存儲區,以達到數據共享的目的。
在錄屏直播中,我們采用AppGroup這種方式可以實現宿主App和Extention的數據傳遞。在App中寫入數據,然后在Extention中讀取數據,反之也可以。
這里主要總結一下跨進程在兩個App中事件傳遞,從Extention發送通知到宿主App。
CFNotificationCenterGetDarwinNotifyCenter
平時開發中發送通知我們使用NSNotificationCenter這個單例類,這個類僅限在一個App內部發送通知,如果跨進程發通知的話就不能使用它了。
CFNotificationCenterGetDarwinNotifyCenter,是CoreFundation中的一個類,它可以實現跨進程發送通知,將通知從Extention App發送到宿主App中。
如果我們的App要實現錄屏直播功能,需要添加Broadcast Upload Extension,這子App是負責采集、傳輸數據的,創建后會自動生成一個類SampleHandler。系統將采集到的錄屏數據,通過SampleHandler中的Api輸出,同時有一些其他Api:
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {[self sendNotificationForMessageWithIdentifier:@"broadcastStartedWithSetupInfo" userInfo:setupInfo]; }- (void)broadcastPaused {[self sendNotificationForMessageWithIdentifier:@"broadcastPaused" userInfo:nil]; }- (void)broadcastResumed {[self sendNotificationForMessageWithIdentifier:@"broadcastResumed" userInfo:nil]; }- (void)broadcastFinished {[self sendNotificationForMessageWithIdentifier:@"broadcastFinished" userInfo:nil]; }- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {}打開手機桌面,然后長按錄屏,選擇錄屏的App為我們自己的App,這時候就開始錄制了。以上的接口就會被執行。開始錄屏執行broadcastStartedWithSetupInfo,暫停錄制執行broadcastPaused…
如果我們要將開始、暫停、結束這些事件以消息的形式發送到宿主App中,需要使用CFNotificationCenterGetDarwinNotifyCenter。
發送通知
寫一個發送通知的方法:
- (void)sendNotificationForMessageWithIdentifier:(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); }這里的identifier是發送此條通知的標識,每個通知定義一個唯一的標識,以便接收端辨認是哪一條通知。
接收通知
在Extension中發送通知后,在宿主App中接收消息。
需要接收通知,首先需要注冊該條通知,這里寫了注冊和移除注冊通知的方法。這里的identifier需要和發送端保持一致。
- (void)registerForNotificationsWithIdentifier:(nullable NSString *)identifier {[self unregisterForNotificationsWithIdentifier:identifier];CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();CFStringRef str = (__bridge CFStringRef)identifier;CFNotificationCenterAddObserver(center,(__bridge const void *)(self),MyHoleNotificationCallback,str,NULL,CFNotificationSuspensionBehaviorDeliverImmediately); } - (void)unregisterForNotificationsWithIdentifier:(nullable NSString *)identifier {CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();CFStringRef str = (__bridge CFStringRef)identifier;CFNotificationCenterRemoveObserver(center,(__bridge const void *)(self),str,NULL); }這里我們需要接收多個通知消息,需要一一注冊才能收到消息:
注冊對應事件的通知
- (void)addUploaderEventMonitor {NSLog(@"addUploaderEventMonitor");[self registerForNotificationsWithIdentifier:@"broadcastStartedWithSetupInfo"];[self registerForNotificationsWithIdentifier:@"broadcastPaused"];[self registerForNotificationsWithIdentifier:@"broadcastResumed"];[self registerForNotificationsWithIdentifier:@"broadcastFinished"];[self registerForNotificationsWithIdentifier:@"processSampleBuffer"];//這里同時注冊了紛發消息的通知,在宿主App中使用[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(broadcastInfo:) name:ScreenHoleNotificationName object:nil]; }移除注冊的通知
- (void)removeUploaderEventMonitor {NSLog(@"removeUploaderEventMonitor");[self unregisterForNotificationsWithIdentifier:@"broadcastStartedWithSetupInfo"];[self unregisterForNotificationsWithIdentifier:@"broadcastPaused"];[self unregisterForNotificationsWithIdentifier:@"broadcastResumed"];[self unregisterForNotificationsWithIdentifier:@"broadcastFinished"];[self unregisterForNotificationsWithIdentifier:@"processSampleBuffer"];[[NSNotificationCenter defaultCenter] removeObserver:self name:ScreenHoleNotificationName object:nil]; }MyHoleNotificationCallback是一個回調block,當收到通知時,就會回調這個block。它的實現如下:
static NSString * const ScreenHoleNotificationName = @"ScreenHoleNotificationName";void MyHoleNotificationCallback(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);NSLog(@"userInfo %@ %@",userInfo,info);NSDictionary *notiUserInfo = @{@"identifier":identifier};[[NSNotificationCenter defaultCenter] postNotificationName:ScreenHoleNotificationNameobject:senderuserInfo:notiUserInfo]; }這里收到通知后,做了一步轉發,將消息轉發出去,在在宿主App中發送通知。
在宿主App中收到MyHoleNotificationCallback這個回調后,我們將此條通知通過NSNotificationCenter紛發出去,App中其他地方如果需要監聽這些事件就可以注冊ScreenHoleNotificationName接收消息了。
如果其他地方不需要接收通知消息,則收到MyHoleNotificationCallback后直接處理就行,也不必再轉發了。
這樣事件傳遞,實現了宿主App和主App之間的事件通信。
- (void)broadcastInfo:(NSNotification *)noti {NSDictionary *userInfo = noti.userInfo;NSString *identifier = userInfo[@"identifier"];if ([identifier isEqualToString:@"broadcastStartedWithSetupInfo"]) {}if ([identifier isEqualToString:@"broadcastPaused"]) {}if ([identifier isEqualToString:@"broadcastResumed"]) {}if ([identifier isEqualToString:@"broadcastFinished"]) {}if ([identifier isEqualToString:@"processSampleBuffer"]) {} }這塊只是在錄屏直播中是否有用,得根據具體的業務需求來看,有時候不需要將事件傳遞給宿主App,也就不用發送通知了。
注意事項
不要在- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType這個方法里發通知,這幾方法是采集到數據就會回調,錄屏過程中一直被執行,如果一直發送通知的話,會造成主線程卡頓,因為通知是同步進行的。
遺留問題
在發送通知的時候,可以傳遞一個參數userInfo,即CFNotificationCenterPostNotification(center, identifierRef, NULL, userInfo, deliverImmediately);
這個userInfo的傳值問題我沒有解決,應該是可以轉值的,可能是轉化問題,不知道怎么弄,有知道的可以一起探討一下,或者直接在品論了告知,謝謝先。
補充
這里是之后補充的內容
以下是別人的處理思路,出處
App 與 Extension 的代碼共用iOS 10 新增了很多種 Extension,包括本文提到的兩種 Broadcast Extension。主 App 與 Extension 屬于不同的兩個進程,代碼邏輯也是分離的,而實際情況中,主 App 與 Extension 往往會包含相同的邏輯,需要共用代碼。
主 App 與 Extension 屬于兩個不同的 target,共用代碼,有以下幾種方式:
一份代碼創建兩個副本,分別加到 App 和 Extension 兩個 target 中。這種方法簡單粗暴而有效,只是,如果需要改動邏輯,則需要改兩份代碼,想象一下,假如這種改動很頻繁,世界上又有幾個程序員能受得了?
抽離公共代碼,放到獨立的 framework,然后兩個 target 都依賴該 framework,這是標準而方便的做法。
使用 CocoaPods,只需要在 Podfile 中分別寫兩個 target 所依賴的 pod 即可,最簡潔。
我覺得 使用 CocoaPods,只需要在 Podfile 中分別寫兩個 target 所依賴的 pod 即可,最簡潔。 這個也是一個可考慮的思路。
總結
以上是生活随笔為你收集整理的iOS录屏直播(四)主App和宿主App数据共享,通信功能实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端设计 最详细的div介绍+效果图+代
- 下一篇: [转帖]Photoshop将照片制作成素