【问题标题】:Google Chromecast SDK TearDown in backgroundGoogle Chromecast SDK TearDown 在后台
【发布时间】:2014-04-27 18:50:35
【问题描述】:

使用 iOS Sender API 框架,当我的应用程序进入后台时,SDK 会断开所有连接,并且在应用程序重新回到前台之前,我无法启动任何媒体。我的应用程序播放音频并允许在后台运行和流式传输。是否可以选择告诉 Googlecast 框架保持套接字打开?

这是后台日志:

INFO:将主动辞职

信息:现在在后台

FINE: -[GCKCastSocket disconnect] 断开连接

FINE: -[GCKCastSocket doTeardownWithError:] doTeardownWithError

FINE: -[GCKCastSocket doTeardownWithError:] 通知委托套接字已断开

FINE: -[GCKHeartbeatChannel didDisconnect] 已断开连接 - 必要时停止心跳计时器

FINE: -[GCKCastSocket socketDidDisconnect:withError:] socketDidDisconnect:withError: "(null)"

然后当应用程序恢复时: 信息:进入前台

FINE: -[GCKCastSocket doTeardownWithError:] doTeardownWithError

FINE: -[GCKCastSocket doTeardownWithError:] 通知委托套接字已断开

FINE: -[GCKCastSocket connectToHost:port:withTimeout:] 正在连接到端口 8009l 上的“192.168.1.4”...

INFO:已激活

FINE: -[GCKCastSocket socket:didConnectToHost:port:] socketDidConnect:

FINE: -[GCKCastSocket socketDidSecure:] socketDidSecure:

FINE: -[GCKCastSocket socket:didReadData:withTag:] 前缀读取,预期消息长度=1307

FINE: -[GCKDeviceAuthChannel didReceiveBinaryMessage:] 正版 Google 设备 didDeviceAuthenticated=YES

FINE: -[GCKDeviceManager deviceAuthChannelDidAuthenticate:] Authentic device,连接接收通道

FINE: -[GCKCastSocket socket:didReadData:withTag:] 前缀读取,预期消息长度=474

FINE: -[GCKDeviceManager receiverControlChannel:didReceiveStatusForApplication:] 加入申请(CC1AD845)可用

FINE: -[GCKDeviceManager connectAndNotifyDidConnectToApplication:launchedApplication:] 连接到应用程序 默认媒体接收器 (CC1AD845),传输 ID web-11

FINE: -[GCKCastSocket socket:didReadData:withTag:] 前缀读取,预期消息长度=135

FINE: -[GCKMediaControlChannel didReceiveTextMessage:] 收到消息:{"type":"MEDIA_STATUS","status":[],"requestId":6}

【问题讨论】:

  • 您能展示一下您的 appDelegate 的代码吗?特别是您的 ApplicationDidEnterBackground 方法 - 您需要在此方法中安排后台任务。此外,请确保您持有对来自 AppDelegate 的发送者对象的引用,而不是您的视图控制器

标签: ios chromecast


【解决方案1】:

在 iOS Sender API 2.0 版中,GCKCastSocket 在收到 UIApplicationDidEnterBackgroundNotification 时关闭,这不是可以配置的。

这意味着:

  • 当应用在后台时,不能将新媒体从应用推送到 chromecast
  • 无法实现锁屏控制

替代方案(仅限自定义接收器):

  • 将要播放的媒体列表发送给接收器
  • 直接从接收器从云端获取新媒体

有关详细信息,另请参阅 this question 或 this one。

【讨论】:

【解决方案2】:

这是我用于其他需求的解决方案,但我想它也可以在这里应用(尚未测试)

1.创建一个后台任务处理程序作为 dispatch_block_t,比如说

 dispatch_block_t myDummyBackgroundTaskBlock = {
    [[UIApplication sharedApplication] endBackgroundTask:myDummyBackgroundTask];
    myDummyBackgroundTask = UIBackgroundTaskInvalid;
    myDummyBackgroundTask = [app beginBackgroundTaskWithExpirationHandler:myDummyBackgroundTask];
};

2。在某处定义此后台和前台任务处理程序

    // foreground
    -(void)handleTasksForApplicationInForeground {
    if(myDummyBackgroundTask) { // reset that task
       [[UIApplication sharedApplication] endBackgroundTask: myDummyBackgroundTask];
       myDummyBackgroundTask = UIBackgroundTaskInvalid;
     }
    }

     // background
     -(void) handleTasksForApplicationInBackground {
         UIDevice *device = [UIDevice currentDevice];
         BOOL backgroundSupported = NO;
        if ([device respondsToSelector:@selector(isMultitaskingSupported)])
         backgroundSupported = device.multitaskingSupported;
        if(backgroundSupported && backgroundEnabled) { // perform a background task

            myDummyBackgroundTaskBlock = ^{
                [[UIApplication sharedApplication] endBackgroundTask: myDummyBackgroundTaskBlock];
                myDummyBackgroundTaskBlock = UIBackgroundTaskInvalid;
           };

           SEL sel = @selector(doDummyBackgroundTask);
           [self doBackgroundTaskAsync:sel];

           [self performSelector:@selector(doBackgroundTaskAsync:) withObject:nil afterDelay:500.0f]; /// LP: this is the funny part since iOS will kill the task after 500 sec.
             }
           }

3。现在让我们在应用程序中处理委托后台模式(如之前定义的那样,您可以在应用程序 .plist 中使用不同的选项激活后台模式):

    -(void)applicationDidEnterBackground:(UIApplication *)application {
       [self handleTasksForApplicationInBackground];
     }

    -(void)applicationWillEnterForeground:(UIApplication *)application {
       [self handleTasksForApplicationInForeground];
     }

4。让我们看看后台异步任务选择器做了什么

        -(void) doBackgroundTaskAsync:(SEL)selector {

        @try {
             if( [[UIApplication sharedApplication] backgroundTimeRemaining] < 5 ) { 
               return;
             }

           if(!myDummyBackgroundTaskBlock) { // need to create again on-the-fly
                myDummyBackgroundTaskBlock = ^{
                      [[UIApplication sharedApplication] endBackgroundTask:myDummyBackgroundTask];
                     myDummyBackgroundTask = UIBackgroundTaskInvalid;
                };
             }

            myDummyBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:myDummyBackgroundTaskBlock];
          dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

           while ([[UIApplication sharedApplication] backgroundTimeRemaining] > 5.0) {
              int delta = 5.0;
              [self performSelector: selector ];
              sleep(delta);
          }
        });
      }
       @catch (...) {
     }
    }

【讨论】:

    猜你喜欢
    • 2016-03-22
    • 2016-04-02
    • 2016-05-21
    • 2014-05-14
    • 2020-09-01
    • 2015-11-06
    • 2014-03-27
    • 2020-04-04
    • 2014-03-19
    相关资源
    最近更新 更多