{"id":20325952,"url":"https://github.com/e-sites/unityxcodebridge","last_synced_at":"2025-04-11T20:06:12.227Z","repository":{"id":150337409,"uuid":"90954528","full_name":"e-sites/UnityXcodeBridge","owner":"e-sites","description":"A step-by-step tutorial on how to make a bridge between Unity's C# and Xcode's Objective-C","archived":false,"fork":false,"pushed_at":"2017-05-11T08:43:49.000Z","size":1405,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-11T20:06:04.393Z","etag":null,"topics":["c","c-sharp","ios","objective-c","unity3d","xcode"],"latest_commit_sha":null,"homepage":"https://www.e-sites.nl","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/e-sites.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-11T08:12:09.000Z","updated_at":"2025-02-24T12:54:39.000Z","dependencies_parsed_at":"2023-04-06T09:55:35.399Z","dependency_job_id":null,"html_url":"https://github.com/e-sites/UnityXcodeBridge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-sites%2FUnityXcodeBridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-sites%2FUnityXcodeBridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-sites%2FUnityXcodeBridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/e-sites%2FUnityXcodeBridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/e-sites","download_url":"https://codeload.github.com/e-sites/UnityXcodeBridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248473127,"owners_count":21109628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c-sharp","ios","objective-c","unity3d","xcode"],"created_at":"2024-11-14T19:42:22.237Z","updated_at":"2025-04-11T20:06:12.217Z","avatar_url":"https://github.com/e-sites.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unity C# \u003c\u003e Xcode Objective-C Bridge\n\nA \"simple\" step-by-step tutorial on how to make a bridge between Unity's C# and Xcode's Objective-C. Either way.\n\n## Unity Scene set up\n- First set up a new scene in Unity and add a plane with a simple sphere above it. So we can interact with it later.\n- Make sure the purple `Sphere` has a `RigidBody` and `Use Gravity` is enabled. \n\n\u003e 💡 You can add some materials to it, so it stands out. And maybe move the `Sphere` a bit up (on the y-axis).\n\n![](Assets/Unity-scene1.png)\n\nIf you run the scene the purple sphere would drop on the white plane.\n\n## Unity GUI\nNext up we're going to add a GUI button to send information to Objective-c\n- Add a `UI -\u003e Button`\n- It should be aligned to the left-bottom\n- Rename the button's text to your liking.\n\n![](Assets/Unity-scene2.png)\n\n## Unity Script\n- Next stop, create a new C# Script, name it `BehaviourScript` or anything to your liking\n\nOpen the script and use this code:\n\n```cs\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.UI;\nusing System.Runtime.InteropServices;\n\npublic class BehaviourScript : MonoBehaviour {\n    public GameObject ball;\n    public Button button;\n\n    [DllImport (\"__Internal\")]\n    private static extern void calledFromUnity();\n\n    void Start () {\n        button.onClick.AddListener (Tap);\n    }\n\n    void Tap()  {\n        calledFromUnity();\n    }\n\n    void Bounce(string direction) {\n        ball.GetComponent\u003cRigidbody\u003e().AddForce(transform.up * 300);\n    }\n}\n```\n\nCode blocks explained:\n\n```cs\nusing System.Runtime.InteropServices;\n```\n\nUsed for external communication.\n\n```cs\n[DllImport (\"__Internal\")]\nprivate static extern void calledFromUnity();\n```\nThis creates a reference to the c function `calledFromUnity()`, which will be implemented in your Xcode project later on.\n\n```cs\nvoid Start () {\n    button.onClick.AddListener (Tap);\n}\n\nvoid Tap()  {\n    calledFromUnity();\n}\n```\nWould listen for a click event on the `button`. When a click occurs the c-function `calledFromUnity()` will be called and invoked in (Obj-)C.\n\n```cs\nvoid Bounce(string direction) {\n    ball.GetComponent\u003cRigidbody\u003e().AddForce(transform.up * 300);\n}\n```\t\nThis would make the ball bounce. `Bounce(string)` will be called from Obj-c / Xcode. \n\nNow go back into Unity and add the `BehaviourScript` to your plane and connect `Button` and `GameObject`.\n\n\n![](Assets/Script-connect.png)\n\nAt this stage you would have a button which would do nothing (yet) and have a function which isn't called (yet).\n\n## iOS Plugin\n- Create a new folder called `Plugin` in your project\n- Create a new folder called `iOS` in `Plugin`\n- Create a new file called `plugin.mm` in that `iOS` folder\n\n\u003e ⚠️ It's important to add these files to this specific folder. Adding them from Xcode would overwrite the `plugin.mm` once you (re)build the Unity project.\n\n![](Assets/Unity-ios-plugin.png)\n\n`plugin.mm` should contain the following code:\n\n```c\nextern \"C\" {\n    void calledFromUnity() {        \n        [[NSNotificationCenter defaultCenter] postNotificationName:@\"UnityNotification\" object:nil];\n    }\n}\n\n```\n\nThis is where the `calledFromUnity()` function we declared earlier would return. We make the default `NSNotificationCenter` post a notification with the name `\"UnityNotification\"`, this way we can intercept it in our own `UIViewController` later on.\n\n\u003e 💡 There are a few options regarding dispatching methods from C to Objective-C's main view, but for now we'll stick to this.\n\n## Build the project\n- Open `Build Settings`: `File -\u003e Build Settings` or press `⇧⌘B`.\n- Use the following settings:\n ![](Assets/Build-Settings.png)\n- Press `Build`\n- Wait ...\n- After a while your Xcode project should be created\n- Open `Unity-iPhone.xcodeproj`\n\n## A UIViewController on top of Unity\n- Create a new Objective-C class in the `Classes` folder name `AppController`.\n\n![](Assets/XcodeCreateAppController.png)\n\n![](Assets/Xcode-AppController.png)\n\n\u003e 💡 Make sure you have a `.mm` extension for the implementation file and it's linked to the `Unity-iPhone` target.\n\n\n- Make sure `AppController` extends `UnityAppController`\n\nThe two files will look like this:\n\n```objc\n// .mm\n\n#import \"AppController.h\"\n\n@implementation AppController {\n    UIButton *btn;\n}\n    \n- (void)startUnity:(UIApplication *)application {\n    [super startUnity:application];\n    \n    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationFired:) name:@\"UnityNotification\" object:nil];\n    \n    UIViewController *vc = [UIViewController new];\n    [vc.view setFrame:self.window.bounds];\n    [vc.view addSubview:self.rootViewController.view];    \n    [vc addChildViewController:self.rootViewController];\n    [self.window setRootViewController:vc];\n    \n    btn = [UIButton buttonWithType:UIButtonTypeSystem];\n    [btn setTitle:@\"To Unity\" forState:UIControlStateNormal];\n    [btn setBackgroundColor:[UIColor whiteColor]];\n    [btn setTintColor:[UIColor orangeColor]];\n    [btn setFrame:CGRectMake(10, 10, 100, 50)];\n    [btn addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];   \n    [vc.view addSubview:btn];\n}\n\n- (void)tapButton:(UIButton *)sender {\n    UnitySendMessage(\"Plane\", \"Bounce\", \"Up\");\n}\n    \n- (void)notificationFired:(NSNotification *)notification {\n    NSString *originalTitle = [btn titleForState: UIControlStateNormal];\n    [btn setTitle:@\"😎\" forState:UIControlStateNormal];\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n        [btn setTitle:originalTitle forState:UIControlStateNormal];\n    });\n}\n@end\n\n```\n\nLets have a look at each code blocks:\n\n```objc\n@implementation AppController {\n    UIButton *btn;\n}\n```\nA `btn` is declared so we can use it among the whole class instance.\n\n```objc\n- (void)startUnity:(UIApplication *)application {\n    [super startUnity:application];\n```\n\nSince `AppController` extends `UnityAppController` and `startUnity:` is called when the Unity view is loaded, this method will be invoked once the Unity controller is started.\n\n```objc\n[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationFired:) name:@\"UnityNotification\" object:nil];\n```\n\n```objc\n- (void)notificationFired:(NSNotification *)notification {\n    NSString *originalTitle = [btn titleForState: UIControlStateNormal];\n    [btn setTitle:@\"😎\" forState:UIControlStateNormal];\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n        [btn setTitle:originalTitle forState:UIControlStateNormal];\n    });\n}\n```\nListen for the `\"UnityNotification\"` notification to be fired and call the `notificationFired:` method.\n`notificationFired:` will change the title of the button and after 1 second set it back to the original one.\n\n```objc\nUIViewController *vc = [UIViewController new];\n[vc.view setFrame:self.window.bounds];\n[vc.view addSubview:self.rootViewController.view];    \n[vc addChildViewController:self.rootViewController];\n[self.window setRootViewController:vc];\n```\nThis would create a new `UIViewController` and places the original unity viewcontroller in it. This way we can add our own UI on top of Unity.\n\n```objc\nbtn = [UIButton buttonWithType:UIButtonTypeSystem];\n[btn setTitle:@\"To Unity\" forState:UIControlStateNormal];\n[btn setBackgroundColor:[UIColor whiteColor]];\n[btn setTintColor:[UIColor orangeColor]];\n[btn setFrame:CGRectMake(10, 10, 100, 50)];\n[btn addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];   \n[vc.view addSubview:btn];\n```\n\nCreates the actual button and places it on the newly created `UIViewController`\n\n```objc\n- (void)tapButton:(UIButton *)sender {\n    UnitySendMessage(\"Plane\", \"Bounce\", \"Up\");\n}\n```\n\nThe button tap will invoke `tapButton:` and will fire `UnitySendMessage` with 3 parameters:\n\n- `\"Plane\"`: The name of the `GameObject` in Unity\n- `\"Bounce\"`: The name of the function in the `BehaviourScript.cs` Unity C# Script.\n- `\"Up\"`: The parameter to be used in the `Bounce(string)` function. (For now this hasn't any effect, you can place any string in it)\n\n\n## main.mm\n- Open `main.mm` (also in the Classes folder) and change this line:\n\n```c\nconst char* AppControllerClassName = \"UnityAppController\";\n```\n\nto\n\n```c\nconst char* AppControllerClassName = \"AppController\";\n```\nThis way it will load the `AppController` class instead of the `UnityAppController` class.\n\n## Results\n\n![](Assets/Result.gif?001)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fe-sites%2Funityxcodebridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fe-sites%2Funityxcodebridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fe-sites%2Funityxcodebridge/lists"}