Using Hockey.app to distribute macOS cinder based apps

I have a macOS app that uses cinder. To distribute it with Hockey app, I need to add a call to the method -applicationDidFinishLaunching. However the method is defined in AppImplMac.mm is part of Cinder. There is virtual void privateSetup__(); Perhaps I could override that. Is there a good solution for supporting this type of distribution support ?

Hey. I’m using Crashlytics and I did something like this. I reimplemented AppDelegateImpl, something like this

@interface CBAppDelegateImpl : AppDelegateImpl

@end

@implementation CBAppDelegateImpl

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
	mApp = cinder::app::AppCocoaTouch::get();
	mAppImpl = mApp->privateGetImpl();
	
	[UIApplication sharedApplication].statusBarHidden = mAppImpl->mStatusBarShouldHide;
	
	for( auto &windowImpl : mAppImpl->mWindows )
		[windowImpl finishLoad];
	
	mApp->privateSetup__();
	mAppImpl->mSetupHasFired = YES;
	
	[mAppImpl startAnimation];
	
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDirectory = [paths objectAtIndex:0];
	NSString *presetsPath = [documentsDirectory stringByAppendingPathComponent:@"presets"];

	if(![[NSFileManager defaultManager] fileExistsAtPath:presetsPath]) {
		NSError *error = nil;
		[[NSFileManager defaultManager] createDirectoryAtPath:presetsPath
								  withIntermediateDirectories:YES
												   attributes:nil error:&error];
	}

	[Fabric with:@[[Answers class], [Crashlytics class]]];
	
	return YES;
}

@end

and then in my main Cinder app class I did something like this to make sure the correct AppDelegate class was getting called.

void CircularBellsApp::launch() {
	const auto &args = getCommandLineArgs();
	int argc = (int)args.size();
	
	char* argv[argc];
	for( int i = 0; i < argc; i++ )
		argv[i] = const_cast<char *>( args[i].c_str() );
	
	::UIApplicationMain( argc, argv, nil, ::NSStringFromClass( [CBAppDelegateImpl class] ) );
}

Not sure if any of these lines can be dropped/done differently, but this works like a charm for me.

That is an excellent way of doing it for a Cinder based iOS app.
A macOS app is not a cocoaTouch app and as far as I can tell, there is no separate object for the app delegate as it is in iOS.

//! We use a separate object for the app delegate, so that AppImplCocoaTouch can be
//! completely initialized before UIApplicationMain is called.
@interface AppDelegateImpl : NSObject &lt;UIApplicationDelegate&gt; {
@public
cinder::app::AppCocoaTouch* mApp;
AppImplCocoaTouch* mAppImpl;
}
@end // AppDelegateImpl

One similar approach to yours maybe:

  1. using AppImplMac to derive from and implement applicationDidFinishLaunching to call HockeyManager stuff.
  2. Since AppMac creates the private implementation object in it construction.
    A. Add MyAppMac class that uses the modified AppImplMac object
    B. Use that to launch the app as App.h.

I will be trying that out but also wanted to

  1. Check to see if there is a better solution
  2. Request a similar design to AppDelegateImpl in cocoaTouch to make your pretty clean approach work for macOS apps as well.

I’m not familiar with Hockey.app, but is there any particular reason the call has to come from within applicationDidFinishLaunching? Cinder calls out to your app’s setup() override from there, so is it possible you can just do any hockey related initialization there?

*edit

Looking at hockey’s documentation, it doesn’t seem to me to specifically need to be in the delegate method. If you rename your main app’s cpp file you be YourAppName.mm it will be compiled as objective-c++, and you can just dump the hockey initialization code in your setup.

void YourApp::setup ( )
{
    [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"APP_IDENTIFIER"];
    [[BITHockeyManager sharedHockeyManager] startManager];
}

You are correct. There is no reason for the call to come from within applicationDidFinishLaunching. I put the setup call in a c++ class constructor with the implementation in a .mm file. In my app’s setup() override, it gets instantiated. It works. I did not put in my app’s file as you suggested for clarity and not mixing HockeyApp framework includes with all else. Thank you !!