Custom Plugin for Apple Game Center in Unity

Introduction

Apple Game Center provides a robust way to integrate leaderboards, achievements, and multiplayer gaming into iOS games. While Unity offers built-in support for Game Center, sometimes it lacks flexibility for advanced use cases. In this blog post, we’ll explore why and how to implement a custom native plugin for Apple Game Center in Unity.

Why Implement a Custom Plugin for Apple Game Center in Unity?

Unity’s built-in Game Center integration may not always support:

  • Advanced leaderboard and achievement customization
  • Multiplayer and real-time event handling
  • Seamless authentication and UI customizations
  • Access to additional Game Center APIs not exposed by Unity
     Creating a custom plugin helps unlock the full potential of Game Center while maintaining control over how features are implemented.

Prerequisites

Before starting, ensure you have:

  • A Mac with Xcode installed
  • Unity (LTS recommended) with iOS Build Support
  • Apple Developer Account
  • Basic knowledge of Swift and Objective-C (for writing native iOS code)
  • Game Center configured in the Apple Developer Console

Steps to Implement a Custom Plugin for Apple Game Center :

Step 1: Enable Game Center in Xcode & Unity

   a. Enable Game Center in Apple Developer Account:

  • Go to Apple Developer AccountCertificates, Identifiers & Profiles.
  • Select your App ID and enable Game Center.
  • Create Leaderboards & Achievements in App Store Connect.

b. Enable Game Center in Unity:

  • Open UnityEditProject SettingsPlayer.
  • Under iOS Settings, enable Game Center.
  • Ensure you set the correct Bundle Identifier (matches the one in your Apple Developer account).

    Step 2: Create Objective-C Plugin for iOS

    Create an Objective-C class (GameCenterManager.m) inside Plugins/iOS/.

    Objective-C Header File (GameCenterManager.h)
#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
 
@interface GameCenterManager : NSObject
+ (GameCenterManager *)sharedInstance;
- (void)authenticatePlayer;
- (void)reportScore:(int64_t)score forLeaderboard:(NSString *)leaderboardID;
- (void)reportAchievement:(NSString *)achievementID percentComplete:(double)percent;
- (void)showLeaderboard:(NSString *)leaderboardID;
- (void)showAchievements;
@end

Objective-C Implementation File (GameCenterManager.m)

#import "GameCenterManager.h"
#import <GameKit/GameKit.h>
 
•	@implementation GameCenterManager

(GameCenterManager *)sharedInstance { 
static GameCenterManager *sharedInstance = nil; 
static dispatch_once_t onceToken; 
dispatch_once(&onceToken, ^{ 
sharedInstance = [[self alloc] init];
 }); 
return sharedInstance; }


(void)authenticatePlayer { 
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error) { if (viewController != nil) { 
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:viewController animated:YES completion:nil]; 
} 
else if (localPlayer.isAuthenticated) 
{ 
NSLog(@"Player authenticated"); } 
else 
{ NSLog(@"Game Center Authentication failed: %@", error.localizedDescription); } }; 
}

(void)reportScore:(int64_t)score forLeaderboard:(NSString *)leaderboardID {
 if ([GKLocalPlayer localPlayer].isAuthenticated)
 { 
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier:leaderboardID]; 
scoreReporter.value = score;
 [GKScore reportScores:@[scoreReporter] withCompletionHandler:^(NSError *error) { if (error) { 
NSLog(@"Error reporting score: %@", error.localizedDescription);
 } }]; 
} }


•	(void)reportAchievement:(NSString *)achievementID percentComplete:(double)percent { 
if ([GKLocalPlayer localPlayer].isAuthenticated) 
{ 
     GKAchievement *achievement = [[GKAchievement alloc]         initWithIdentifier:achievementID]; 
achievement.percentComplete = percent;
 [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) 
{ if (error) { 
NSLog(@"Error reporting achievement: %@", error.localizedDescription); 
} }]; 
} }

(void)showLeaderboard:(NSString *)leaderboardID
 { 
GKGameCenterViewController *gcViewController = 
[[GKGameCenterViewController alloc] init]; gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards; gcViewController.leaderboardIdentifier = leaderboardID; gcViewController.gameCenterDelegate = (id)
[UIApplication sharedApplication].keyWindow.rootViewController; [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:gcViewController animated:YES completion:nil];
 }

(void)showAchievements { 
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init]; 
gcViewController.viewState = GKGameCenterViewControllerStateAchievements; gcViewController.gameCenterDelegate = (id)
[UIApplication sharedApplication].keyWindow.rootViewController; [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:gcViewController animated:YES completion:nil]; 
}
@end

Step 3: Create C# Wrapper in Unity

Create a C# script (GameCenterManager.cs) inside Unity.

using System; using System.Runtime.InteropServices; using UnityEngine;
public class GameCenterManager : MonoBehaviour { [DllImport("__Internal")] private static extern void _AuthenticatePlayer();

[DllImport("__Internal")]
private static extern void _ReportScore(long score, string leaderboardID);

[DllImport("__Internal")]
private static extern void _ReportAchievement(string achievementID, double percentComplete);

[DllImport("__Internal")]
private static extern void _ShowLeaderboard(string leaderboardID);

[DllImport("__Internal")]
private static extern void _ShowAchievements();

public static void AuthenticatePlayer()
{
    if (Application.platform == RuntimePlatform.IPhonePlayer)
    {
        _AuthenticatePlayer();
    }
}

public static void ReportScore(long score, string leaderboardID)
{
    if (Application.platform == RuntimePlatform.IPhonePlayer)
    {
        _ReportScore(score, leaderboardID);
    }
}

public static void ReportAchievement(string achievementID, double percentComplete)
{
    if (Application.platform == RuntimePlatform.IPhonePlayer)
    {
        _ReportAchievement(achievementID, percentComplete);
    }
}

public static void ShowLeaderboard(string leaderboardID)
{
    if (Application.platform == RuntimePlatform.IPhonePlayer)
    {
        _ShowLeaderboard(leaderboardID);
    }
}

public static void ShowAchievements()
{
    if (Application.platform == RuntimePlatform.IPhonePlayer)
    {_ShowAchievements(); } } }

Step 4: Call Plugin from Unity

Inside your Unity script (GameManager.cs), call Game Center functions like this:

void Start() 
{ 
    GameCenterManager.AuthenticatePlayer(); 
}
// Report Score public void SubmitScore(long score) { GameCenterManager.ReportScore(score, "leaderboard_ID_here");
 }
// Report Achievement public void UnlockAchievement(string achievementID) { GameCenterManager.ReportAchievement(achievementID, 100.0); 
}
// Show Leaderboard public void ShowLeaderboard() { GameCenterManager.ShowLeaderboard("leaderboard_ID_here"); 
}
// Show Achievements public void ShowAchievements() { GameCenterManager.ShowAchievements();
 }

Step 5: Build & Test

  • Build for iOS in Unity.
  • Open in Xcode, sign your app, and enable Game Center.
  • Run the app on a real iOS device (Game Center doesn’t work on the simulator).
  • Check if login, leaderboards, and achievements work.

Reference :   Apple GameKit Documentation

Conclusion
By implementing a custom Game Center plugin, we gain more control over authentication, leaderboards, and achievements in Unity. This approach provides better flexibility and customization for iOS games, ensuring a smooth gaming experience.

Leave a Reply

Your email address will not be published. Required fields are marked *