Migrate your existing Unity iOS project from the Objective-C project type to the new Swift project type.
Consider the following before migrating to a Swift Xcode project type:
Use the following steps to create a Swift Xcode project type:
If you have post-process scripts that modify Xcode project files, you must update them to support changes to the project structure.
The Xcode project file now uses a sanitized version of your Unity project’s name, rather than the static name Unity-iPhone.xcodeproj. To return the correct project path, use the PBXProject.GetPBXProjectPath method.
For example, update your code as follows:
// Before (Objective-C only):
string projPath = Path.Combine(pathToBuiltProject, "Unity-iPhone.xcodeproj/project.pbxproj");
// After (works for both Objective-C and Swift project types):
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
Review your existing modifications to the .xcodeproj file to ensure they’re still required. For more information, refer to Structure of a Unity Xcode Swift project type.
To identify project types in your post-process scripts, use the UnityEditor.PlayerSettings.xcodeProjectType property. For example:
if (UnityEditor.PlayerSettings.xcodeProjectType == UnityEditor.XcodeProjectType.Swift) {
// Swift project type specific modifications
} else {
// Objective-C project type specific modifications
}
With the introduction of the Swift project type, you must adapt your native plug-ins to work with the new UnityFramework and the updated Xcode project structure. This migration involves updating API calls, handling lifecycle events differently, and ensuring your plug-ins are correctly configured in the Unity Editor.
Ensure your plug-in is set to be included in the correct Xcode project type. By default, plug-ins are included in both the Objective-C and Swift project types. In the Unity Editor, open the Plugin Inspector for your native plug-in and review its platform settings to confirm the correct compatibility. For more information, refer to Configure a plug-in for iOS with the Inspector window.
The contents of UnityFramework are different when using a Swift Xcode project type. Review your plug-in’s dependencies and update any code that relies on functions or classes that are no longer available.
The UnityPlayer class now provides most of the functionality previously available through UnityAppController.
Note: UnityPlayer isn’t a direct substitute, so it’s recommended to review the Swift project type API reference for details on its specific methods and properties.
// Before:
UnityAppController* appController = GetAppController();
// After (Swift):
let player = UnityPlayer.shared
// After (Objective-C):
UnityPlayer *player = [UnityPlayer shared];
To access the main rendering view and root view controller, use the properties on the UnityPlayer instance.
// Before:
UIView* unityView = GetAppController().unityView;
UIView* unityView = UnityGetUnityView();
UIViewController* rootVC = GetAppController().rootViewController;
UIViewController* rootVC = UnityGetGLViewController();
// After (Swift):
let unityView = UnityPlayer.shared.renderingView
let rootVC = UnityPlayer.shared.rootViewController
// After (Objective-C):
UIView *unityView = [[UnityPlayer shared] renderingView];
UIViewController *rootVC = [[UnityPlayer shared] rootViewController];
Pausing and resuming the application is now handled through methods on the UnityPlayer instance. For example:
// Before:
if (!UnityIsPaused()) {
UnityPause(1); // pause
}
UnityPause(0); // resume
// After (Swift):
if (!UnityPlayer.shared.isPaused()) {
UnityPlayer.shared.pause()
}
UnityPlayer.shared.resume()
// After (Objective-C):
if (![[UnityPlayer shared] isPaused]) {
[[UnityPlayer shared] pause];
}
[[UnityPlayer shared] resume];
If your plug-in previously depended on LifeCycleListener.h or AppDelegateListener, you must migrate to using NotificationCenter to handle lifecycle events. The event definitions are now located in UnityAPI/UnityPluginInterface/UnityNotifications.swift.
// Before (using LifeCycleListener protocol):
@interface MyPlugin : NSObject<AppDelegateListener>
@end
- (void)applicationWillFinishLaunchingWithOptions:(NSNotification*)notification { ... }
// After (Swift):
NotificationCenter.default.addObserver(
forName: UnityNotifications.applicationWillFinishLaunching,
object: nil, queue: nil
) { _ in /* handle */ }
// After (Objective-C):
[[NSNotificationCenter defaultCenter]
addObserverForName:UnityNotifications.applicationWillFinishLaunching
object:nil queue:nil usingBlock:^(NSNotification *note) { /* handle */ }];
Available notifications include:
applicationWillFinishLaunchingapplicationDidRegisterForRemoteNotificationsapplicationDidFailToRegisterForRemoteNotificationsapplicationDidReceiveRemoteNotificationunityDidQuitunityDidUnloadapplicationHandleEventsForBackgroundURLSessionsceneOpenURLContextsUIApplication.didBecomeActiveNotificationUIApplication.didFinishLaunchingNotificationNote: To prevent duplicate notifications, Unity filters out certain lifecycle and app delegate events that iOS already provides, such as didFinishLaunchingNotification.
For the Swift project type, the recommended way to call into C# script is by using the UnityPlayer.sendMessage() method. The UnitySendMessage() C function is still available but now requires you to import UnityPluginInterface.h.
// Before (C/C++/Objective-C):
UnitySendMessage("GameObjectName", "MethodName", "argument");
// After (Swift):
UnityPlayer.shared.sendMessage(toGameObject: "GameObjectName", method: "MethodName", argument: "argument")
UnitySendMessage("GameObjectName", "MethodName", "argument")
// After (Objective-C):
#import "UnityPluginInterface.h"
#import <UnityFramework/UnityFramework-Swift.h>
[[UnityPlayer shared] sendMessageToGameObject:@"GameObjectName" method:@"MethodName" argument:@"argument"];
UnitySendMessage("GameObjectName", "MethodName", "argument");
// C/C++ still works (requires #import "UnityPluginInterface.h"):
UnitySendMessage("GameObjectName", "MethodName", "argument");
If you need to support both Xcode project types within the same plug-in source file, use the UNITY_XCODE_PROJECT_TYPE_SWIFT preprocessor macro to create different code paths.
#ifdef UNITY_XCODE_PROJECT_TYPE_SWIFT
UnityPlayer *player = [UnityPlayer shared];
#else
UnityAppController* appController = GetAppController();
#endif
The low-level native plug-in API remains the same, but the location of the header files has changed. The headers are now located in the UnityAPI/UnityPluginInterface/ directory.
However, you can continue to import them in your code using the same syntax as before.