Legacy iOS support

Games integrating with Skillz are able to still support older versions of iOS, however this is an involved process and should be done carefully. We recommend first building your integration for iOS 8.x and higher, and then making the following changes in order to support older iOS versions.

Important: The Skillz UI will still only be launchable on iOS 8.x and higher.

Step 1: Runtime Framework Linking

You should start by modifying your existing integration to load the Skillz framework at runtime using dlopen(). First modify yourLink Binary With Libraries build phase to load Skillz.framework as Optional. If loading via a Linker Flag, you may use -weak_framework Skillz.

Step 2: Using dlopen()

Prior to calling any Skillz methods, you will need to link to it using dlopen(). First, import dlfcn.h which contains dlopen. Below you’ll find example code which explains how to load Skillz.framework with dlopen(), as well as print out any errors.

Note: This can only be down on iOS 8, notice the NSFoundationVersionNumber check we do prior to linking. All your Skillz calls should be gated by this or similar logic.

#include  //Import to use dlopen()

// Check for iOS8+
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {

    NSLog(@"Skillz class should be null: %@", NSClassFromString(@"Skillz"));
    dlopen("Skillz.framework/Skillz", RTLD_NOW); //Perform linking

    if (!NSClassFromString(@"Skillz")) {
        //Skillz was not loaded properly, dlerror() will contain an explanation.
        NSLog(@"Skillz load error: %s" , dlerror());
    } else {
        //Success :tada:
        NSLog(@"Skillz loaded successfully %@", NSClassFromString(@"Skillz"));
    }
}

 

Step 3: Modify Skillz Usage

Now that you are loading the Skillz framework at runtime, you will no longer be able to use #import statements, and all Skillz class usage will need to be done with either NSInvocation or performSelector varients.

Important: We highly recommend creating a SkillzDelegate singleton with your own class prefix in order to easily organize your method calls.

Examples of performSelector:

If a given method does not return or take primitive types as arguments, and has no more than two arguments, you can replicate your usage via performSelector: and it’s variants. This includes, but is not limited to, launchSkillz,displayTournamentResultsWithScore:withCompletion:, and notifyPlayerAbortWithCompletion.

Launching Skillz:

+ (void)launchSkillz
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];
    [skillzInstance performSelector:@selector(launchSkillz)];
}

Submitting a score:

+ (void)displayTournamentResultsWithScore:(NSNumber *)score withCompletion:(void (^)(void))completion
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];
    [skillzInstance performSelector:@selector(displayTournamentResultsWithScore:withCompletion:)
                         withObject:score
                         withObject:[completion copy]];
}

Reporting an abort:

+ (void)notifyPlayerAbortWithCompletion:(void (^)(void))completion
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];
    [skillzInstance performSelector:@selector(notifyPlayerAbortWithCompletion:)
                         withObject:[completion copy]];
}

Examples of NSInvocation

Once a given method involves primitives or three or more arguments, you must use the more complex NSInvocation. This includes, but is not limited to, initWithGameId:forDelegate:withEnvironment:, tournamentIsInProgress,getRandomNumberWithMin:andMax:, and setGameHasBackgroundMusic.

Important: As NSInvocation is one of the more complicated iOS tools at your disposal, we would suggest referring to the Apple documentation if you have further questions.

Initializing Skillz:

- (void)initializeSkillz
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];

    NSMethodSignature *signature = [skillzInstance methodSignatureForSelector:@selector(initWithGameId:forDelegate:withEnvironment:)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:skillzInstance];
    [invocation setSelector:@selector(initWithGameId:forDelegate:withEnvironment:)];

    NSInteger environment;
#ifdef RELEASE
    environment = 0 /* SkillzProduction */;
#else
    environment = 1 /* SkillzSandbox */;
#endif

    id delegate = [DDSkillzDelegate sharedInstance];
    NSString *gameId = @"myGameId";

    [invocation setArgument:&gameId atIndex:2];
    [invocation setArgument:&delegate atIndex:3];
    [invocation setArgument:&environment atIndex:4];
    [invocation invoke];
}

Checking tournamentIsInProgress:

+ (BOOL)isTournamentInProgress
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];

    NSMethodSignature *signature = [skillzInstance methodSignatureForSelector:@selector(tournamentIsInProgress)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:skillzInstance];
    [invocation setSelector:@selector(tournamentIsInProgress)];
    [invocation invoke];

    BOOL isTournamentInProgress;
    [invocation getReturnValue:&isTournamentInProgress];

    return isTournamentInProgress;
}

Using Skillz Random:

+ (NSInteger)getRandomNumberWithMin:(NSInteger)min andMax:(NSInteger)max
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];

    NSMethodSignature *signature = [Skillz methodSignatureForSelector:@selector(getRandomNumberWithMin:andMax:)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:Skillz];
    [invocation setSelector:@selector(getRandomNumberWithMin:andMax:)];

    [invocation setArgument:&min atIndex:2];
        [invocation setArgument:&max atIndex:3];
    [invocation invoke];

    NSInteger randomNumber;
    [invocation getReturnValue:&randomNumber];

    return randomNumber;
}

Toggling Background Music:

+ (void)setGameHasBackgroundMusic:(BOOL)hasBackgroundMusic
{
    Class Skillz = NSClassFromString(@"Skillz");
    id skillzInstance = [Skillz performSelector:@selector(skillzInstance)];

    NSMethodSignature *signature = [skillzInstance methodSignatureForSelector:@selector(setGameHasBackgroundMusic:)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:skillzInstance];
    [invocation setSelector:@selector(setGameHasBackgroundMusic:)];
    [invocation setArgument:&hasBackgroundMusic atIndex:2];
    [invocation invoke];
}