I am experimenting with mixing objective-C and C++ when building an iOS ue4 application. I created an example of a class which can access iOS functionality utilizing Objective-C++. I am fairly new to objective-c and Unreal and I am having a hard time figuring out how to respond to callback in objective-C layer and propagate to call a function in C++.
In the following example, for simplicity I created a MPMusicPlayerController interface to interact with iOS’s system music player. Here are the classes defined:
IOSMediaPlayerController.h
// C++ class header interfacing with objective-c
#pragma once
#if PLATFORM_IOS
#import "IOSMediaPlayerControllerObj.h"
#endif
class IOSMediaPlayerController
{
public:
IOSMediaPlayerController();
~IOSMediaPlayerController();
void startPlayback();
void stopPlayback();
void callbackFunc();
#if PLATFORM_IOS
IOSMediaPlayerControllerObj *playerObj;
#endif
};
IOSMediaPlayerControllerObj.h
// Objective-C header class containing reference to the MPMusicPlayerController
#if PLATFORM_IOS
#pragma once
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface IOSMediaPlayerControllerObj: NSObject
@property (assign) MPMusicPlayerController *iOSMusicPlayer;
-(void)startPlayback;
-(void)stopPlayback;
-(void)handleNowPlayingItemChanged;
@end
#endif
IOSMediaPlayerControllerObj.mm
// Objective-C++ mixed code and doing most of the interfacing with iOS
#include "IOSMediaPlayerController.h"
#if PLATFORM_IOS
#import "IOSMediaPlayerControllerObj.h"
@implementation IOSMediaPlayerControllerObj
- (instancetype)init
{
self = [super init];
if (self) {
// initiate simple music collection from user's library
NSArray <MPMediaItem *> *items = [[MPMediaQuery songsQuery] items];
MPMediaItemCollection *musicCollection = [MPMediaItemCollection collectionWithItems:items];
_iOSMusicPlayer = [MPMusicPlayerController systemMusicPlayer];
[_iOSMusicPlayer setQueueWithItemCollection:musicCollection];
// Register Media Player Notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleNowPlayingItemChanged:)
name:@"MPMusicPlayerControllerNowPlayingItemDidChangeNotification"
object:_iOSMusicPlayer];
}
return self;
}
- (void)startPlayback
{
[_iOSMusicPlayer play];
}
- (void)stopPlayback
{
[_iOSMusicPlayer stop];
}
- (void)handleNowPlayingItemChanged
{
// what to do here?
// Eventually I want to call up callbackFunc from IOSMediaPlayerController
}
@end
#endif
IOSMediaPlayerController::IOSMediaPlayerController()
{
#if PLATFORM_IOS
playerObj = [[IOSMediaPlayerControllerObj alloc] init];
#endif
}
IOSMediaPlayerController::~IOSMediaPlayerController()
{
}
void IOSMediaPlayerController::startPlayback()
{
#if PLATFORM_IOS
[playerObj startPlayback];
#endif
}
void IOSMediaPlayerController::stopPlayback()
{
#if PLATFORM_IOS
[playerObj stopPlayback];
#endif
}
void IOSMediaPlayerController::callbackFunc()
{
// I want to fire this event, after handleNowPlayingItemChanged was called in obj-c layer
}
Now to use it in Unreal, I can create an object in GameMode class for example
// in the header define a controller and class reference
#include "IOSMediaPlayerController.h"
IOSMediaPlayerController *iOSPlayer;
// in .cpp file, start interfacing with the music player
iOSPlayer = new IOSMediaPlayerController();
iOSPlayer->startPlayback();
Overall, I am not sure if it is the best way to do this, but I haven’t found many examples so it is the method I ended up with. Do you have any suggestions about how I can get the callback from objective-c in the handleNowPlayingItemChanged function eventually call to callbackFunction defined in the parent class or somewhere in GameMode for example? Maybe there is a better way to do this?
Any help would be greatly appreciated!
Thanks!