5

I initialize Google Cast SDK in my application: didFinishLaunching like that:

let criteria = GCKDiscoveryCriteria(applicationID: kGCKDefaultMediaReceiverApplicationID)
let options = GCKCastOptions(discoveryCriteria: criteria)
GCKCastContext.setSharedInstanceWith(options)

I've tried to stream video content to Default Media Receiver and it works.

But I need to be able to change kGCKDefaultMediaReceiverApplicationID to a custom receiver application id to send different content to a custom receiver application I've registered via Google Cast SDK Developer Console. I can't relaunch the app to specify a different application id.

Is there any way to do it dynamically at some point in the app after GCKCastContext.setSharedInstanceWith(options) has already been called?

The call of this method works only once and I cannot update GCKDiscoveryCriteria: GCKCastContext.setSharedInstanceWith(options)

I use 'google-cast-sdk-no-bluetooth', version: 4.5.3

In Android SDK there is a method which can change the receiver app id on the fly: https://developers.google.com/android/reference/com/google/android/gms/cast/framework/CastContext#public-void-setreceiverapplicationid-string-applicationid

Unfortunately, I don't see anything like that in the iOS SDK :(

The only thing I found is this (inside GCKSessionManager):

/**
 * Sets the default session options for the given device category.The session options are passed to
 * the GCKDeviceProvider::createSessionForDevice:sessionID:sessionOptions: method when the user
 * selects a device from the Cast dialog.  For Cast sessions, the session options can specify which
 * receiver application to launch.
 *
 * @param sessionOptions The session options. May be <code>nil</code> to remove any previously set
 * options.
 * @param category The device category.
 *
 * @since 4.0
 */
- (void)setDefaultSessionOptions:(nullable GCKSessionOptions *)sessionOptions
               forDeviceCategory:(NSString *)category;

But there is no documentation on which sessionOptions and category to pass (category is probably kGCKCastDeviceCategory). It's not understandable which params exist and how to construct them.

Aleksandr Honcharov
  • 2,343
  • 17
  • 30
  • did you end up solving this? – natus Dec 22 '20 at 01:05
  • @natus no, I haven't solved it yet ( – Aleksandr Honcharov Dec 22 '20 at 08:01
  • Think it's not possible because there are no methods to manage Google Cast SDK's internal singleton instance and once it's initialized with `setSharedInstanceWith` you can't change its options. – iUrii Dec 22 '20 at 10:22
  • @iUrii Well, I asked this question specifically to find the answer. I believe it's possible, maybe in a hacky way or as a workaround. Maybe specifying needed params in `setDefaultSessionOptions`. And I wrote to Google developer support, created issues on Github and their IssueTracker. Haven't received any answer so far, but this use case is important. https://issuetracker.google.com/issues/175803965 – Aleksandr Honcharov Dec 22 '20 at 10:28

2 Answers2

2

I found a solution after some time of reverse engineering. It requires 2 steps which are necessary:

Step 1: Initializing GCKDiscoveryCriteria using a private Objective-C call:

let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
let initWithIds = Selector(("initWithApplicationIDs:"))
if criteria.responds(to: initWithIds) {
    criteria.perform(initWithIds, with: NSOrderedSet(array: [kGCKDefaultMediaReceiverApplicationID, kReceiverAppID]))
}
    
let options = GCKCastOptions(discoveryCriteria: criteria)
GCKCastContext.setSharedInstanceWith(options)

Here you need to provide an instance of NSOrderedSet with application ids you want to use. In my case one of them is default media receiver app id, and the second is custom.

Step 2: Dynamically setting what app id to use for the newly created sessions. You can call it many times during your app lifecycle:

let sessionManager = GCKCastContext.sharedInstance().sessionManager
sessionManager.setDefaultSessionOptions(["gck_applicationID": NSString("YOUR_RECEIVER_APP_ID")],
                                                                                forDeviceCategory: kGCKCastDeviceCategory)
    

Here we use a string gck_applicationID as a key. I've spent several days trying to find it and finally managed to do it!!! You can use kGCKDefaultMediaReceiverApplicationID as a value, or your custom receiver app id.

Thanks to @iUrii and his direction to go reverse engineering. https://stackoverflow.com/a/65408060/5147552

P.S.: I used a private method to accomplish what I wanted. It works in google-cast-sdk-no-bluetooth, version 4.5.3. But potentially it's a subject to change. Be careful when using it, since the new versions of SDK might break it.

Aleksandr Honcharov
  • 2,343
  • 17
  • 30
1

You can delete a Cast's singleton instance by calling private objc unsetSharedInstance selector and then set it again:

let unset = Selector("unsetSharedInstance")
if GCKCastContext.responds(to: unset) {
    GCKCastContext.perform(unset)
}
GCKCastContext.setSharedInstanceWith(GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: "APP_ID")))

You can use it as a temporary solution because it can be changed in new versions of the library.

iUrii
  • 11,742
  • 1
  • 33
  • 48
  • Thanks for the answer. I tried it. The code does get executed, but it doesn't change the applicationId. It launches the one which was set in the `application: didFinishLaunching`. :( By the way, how did you find this approach? – Aleksandr Honcharov Dec 22 '20 at 11:55
  • @AleksandrHoncharov I've found new approach please try it out – iUrii Dec 22 '20 at 12:12
  • It sets the new instance, but it unfortunately crashes. `Thread 1: "+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'GCKDBDeviceInfo'"`. The first variant with changing the session options changed the value in the context. So, it worked, but didn't achieve needed result. Probably it's important to restart session manager or something after doing it. – Aleksandr Honcharov Dec 22 '20 at 12:30
  • I think you should stop and reinit all after removing the instance. – iUrii Dec 22 '20 at 12:33
  • yes, I tried to do it. But it seems not to work, since it was doing some things under the hood which I can't control. – Aleksandr Honcharov Dec 22 '20 at 12:35
  • To view all private objc properties and methods of objc object you can use next NSObject selectors: _ivarDescription, _shortMethodDescription, _methodDescription – iUrii Dec 22 '20 at 12:35
  • Thanks, I will investigate this path. – Aleksandr Honcharov Dec 22 '20 at 12:39
  • I awarded you a bounty, thanks!!! But answered the question myself for folks who face this problem in the future. – Aleksandr Honcharov Dec 22 '20 at 14:21