Låt oss diskutera olika sätt att påskynda din produktutveckling.

Visst, då gör vi det
Betyg 4,9/5 på Clutch

MOP

  • Tjänster

  • Produkter

  • Människor

  • Blogg

  • Låt oss bygga

Mer

  • Fallstudier

  • Utmärkelser

  • Kundutlåtanden

  • Lediga tjänster

  • Teknik

Socialt

  • LinkedIn

  • X

  • Instagram

  • Facebook

  • Dribbble

© 2026 Ministry of Programming

  • Integritetspolicy
Tillbaka till bloggen

Starta ett Unity-spel från en SwiftUI iOS-app

Dino Trnka
2 mars 2021Produktdrift och livslängdLäsningstid: 8 minuter
Starta ett Unity-spel från en SwiftUI iOS-app

Sedan version 2019.3 erbjuder Unity stöd för att ladda in och ta bort ett Unity-spel från en native iOS- eller Android-app via funktionen”Unity As A Library”. Detta är ett effektivt sätt att integrera ett spel i din native mobilapp och separera spelspecifik logik från iOS-appens logik.

Unity erbjuder funktioner som gör att du kan styra när och hur runtime-biblioteket ska laddas, aktiveras eller avlastas i den nativa applikationen. Utöver det förblir byggprocessen för mobilappar i stort sett oförändrad. Med Unity kan du skapa iOS-projekt i Xcode och Android-projekt i Gradle.

Det kan dock vara ganska utmanande att genomföra detta, särskilt om du vill integrera ett Unity-spel i en SwiftUI-app. Men det finns ingen anledning att oroa sig, för det är precis vad vi ska göra i den här artikeln!

Utan vidare dröjsmål – nu kavlar vi upp ärmarna och sätter igång! 😃

Skapa iOS-projektet

Först måste du skapa ett tomt iOS-projekt i en arbetsyta. Ett enkelt sätt att göra detta är att först skapa ett tomt Xcode-projekt och sedan, när du har klickat på ” go ”, väljaArkiv → Spara som arbetsyta. Låt oss döpa både projektet och arbetsytantill SwiftyUnity.

Viktigt:
Se till att du väljer”Storyboard”som gränssnitt och”UIKit App Delegate” somprojektets livscykel. Oroa dig inte, vi kommer att konvertera detta till en SwiftUI-app senare; dessa steg behövs bara för att få Unity-integrationen att fungera.

Eftersom det här kommer att bli ett SwiftUI-projekt, glöm inte att ställa in lägsta iOS-distributionsmål till 13.0.

Skapa Unity-projektet

Därefter måste du skapa ett tomt Unity-projekt. Det spelar ingen roll var det ligger, men det är bäst att placera det i samma mapp som vårt arbetsområde och iOS-projektet. Låt oss kalla Unity-projektet förUnityGame.

Den enda funktionen vi kommer att lägga till i standardscenen i Unity är en enda knapp som stänger spelet och tar dig tillbaka till iOS-appen. Lägg till ett knappobjekt i Unity-scenen och ange ”Avsluta spelet” som knapptext.

Nu ska vi lägga till ett skript,QuitBehavior.cs, till vår knapp. Det är väldigt enkelt, eftersom det enda det behöver göra är att stänga ner Unity-spelet och återgå till vår iOS-app.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class QuitBehavior : MonoBehaviour
{
    public void OnButtonPressed()
    {
    	  Application.Unload();
    }
}

Vi måste koppla lyssnarenOnButtonPressedtill vår knapp. Kom ihåg att du måste markera funktionen medpublici det skript som är kopplat till den för att den ska visas i listan!

Det räcker med den här spel funktionaliteten för tillfället, eftersom vårt huvudsakliga mål är att kunna starta och avsluta spelet från iOS-appen. Nu är det alltså dags att bygga Unity-spelet som ett iOS-projekt.

I Unity-projektet går du tillArkiv → Bygginställningar( go ). Här måste du ändra plattformen från”PC, Mac & Linux Standalone” till”iOS” och sedan klicka på knappen”Byt plattform”. Du måste vänta en stund medan Unity kompilerar om.

Nu är det dags att exportera vårt Unity-projekt som ett iOS-projekt. Du behöver inte ändra några inställningar, utan klickar bara på”Build”. Vi exporterar Unity-projektet till en mapp som heterUnityExport.

Hittills borde vi ha tre projektmappar i vår huvudmapp för arbetsytan:

  • SwiftyUnity, den huvudsakliga iOS-appen.
  • UnityGame, spelprojektet i Unity.
  • UnityExport, som skapas genom att exportera Unity-spelet som ett iOS-projekt.

Om din mappstruktur inte ser ut så här behöver du inte oroa dig. Allt kommer ändå att fungera så länge du kopplar ihop projekten på rätt sätt, vilket vi ska göra i nästa steg.

Anslut Unity till iOS

Nu är det dags att koppla ihop det exporterade Unity-projektet med vår SwiftUI-app. ÖppnaSwiftyUnity.xcworkspace, som för närvarande endast innehåller SwiftyUnity-projektet.

Leta reda på UnityExport-projektet i Finder och dra filen”
Unity-iPhone.xcodeproj”till arbetsytan.

Nu ingår bådeSwiftyUnity.xcodeprojochUnity-iPhone.xcodeproji samma arbetsyta. Om dinUnity-iPhone.xcodeproj visas irött efter att du har dragit den, se till att du ställer in”Plats”på”Relativ till arbetsyta”i projektets högra panel.

Klicka sedan på SwiftyUnity-projektet och välj målet SwiftyUnity. I menyn”Allmänt”bläddrar du ned till avsnittet”Ramverk, bibliotek och inbäddat innehåll”. Klicka på+-knappen för att lägga till ett nytt ramverk.

VäljUnityFramework.frameworki listan och lägg till det i projektet.

Välj sedan mappen”Data” iUnity-iPhone-projektet. I den högra panelen ser duavsnittet ”Target Membership”. Du måste markera rutan bredvid”UnityFramework”.

Öppna sedanInfo.plistoch ta bort posten”Application Scene Manifest”. Detta kommer tillfälligt att göra att appen slutar fungera, men vi åtgärdar det senare i AppDelegate.

Det räcker med inställningarna för tillfället. Nu är det äntligen dags att skriva lite kod!

Och nu… lite kod!

Låt oss först lägga till en ny SwiftUI-vy som heterContentView.swift, som kommer att fungera som vår ingång till SwiftUI. Vi lägger till en enda knapp som startar spelet. Vi lämnar knappens händelsehanterare tom för tillfället och återkommer hit när vi har förberett koden som startar Unity-spelet.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Button(action: {
            // TODO: Add code for launching Unity here
        }) {
            Text("Launch Unity!")
        }
    }
}

Eftersom vi från början skapade en UIKit Storyboard-app (och inte en SwiftUI-app) måste vi nu koppla ihop vår ContentView med den rot-ViewController som har genererats. Nästa steg är alltså att uppdatera koden iViewController.swift:

import UIKit
import SwiftUI

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let vc = UIHostingController(rootView: ContentView())
        addChild(vc)
        vc.view.frame = self.view.frame
        view.addSubview(vc.view)
        vc.didMove(toParent: self)
    }
}

Det viktigaste steget är förstås att implementera kopplingen mellan appen och spelet via UnityFramework, som vi importerade tidigare. Om du vill lära dig mer om ramverket kan du besöka den officiella dokumentationenhär.

Vi ska skapa en singleton-hjälpklass som heterUnity, som vi kan använda för alla våra behov som rör UnityFramework. Skapa en ny klass och fyll den med följande kod:

import Foundation
import UnityFramework

class Unity: UIResponder, UIApplicationDelegate {

    static let shared = Unity()

    private let dataBundleId: String = "com.unity3d.framework"
    private let frameworkPath: String = "/Frameworks/UnityFramework.framework"

    private var ufw : UnityFramework?
    private var hostMainWindow : UIWindow?

    private var isInitialized: Bool {
        ufw?.appController() != nil
    }

    func show() {
        if isInitialized {
            showWindow()
        } else {
            initWindow()
        }
    }

    func setHostMainWindow(_ hostMainWindow: UIWindow?) {
        self.hostMainWindow = hostMainWindow
    }

    private func initWindow() {
        if isInitialized {
            showWindow()
            return
        }

        guard let ufw = loadUnityFramework() else {
            print("ERROR: Was not able to load Unity")
            return unloadWindow()
        }

        self.ufw = ufw
        ufw.setDataBundleId(dataBundleId)
        ufw.register(self)
        ufw.runEmbedded(
            withArgc: CommandLine.argc,
            argv: CommandLine.unsafeArgv,
            appLaunchOpts: nil
        )
    }

    private func showWindow() {
        if isInitialized {
            ufw?.showUnityWindow()
        }
    }

    private func unloadWindow() {
        if isInitialized {
            ufw?.unloadApplication()
        }
    }

    private func loadUnityFramework() -> UnityFramework? {
        let bundlePath: String = Bundle.main.bundlePath + frameworkPath

        let bundle = Bundle(path: bundlePath)
        if bundle?.isLoaded == false {
            bundle?.load()
        }

        let ufw = bundle?.principalClass?.getInstance()
        if ufw?.appController() == nil {
            let machineHeader = UnsafeMutablePointer<MachHeader>.allocate(capacity: 1)
            machineHeader.pointee = _mh_execute_header

            ufw?.setExecuteHeader(machineHeader)
        }
        return ufw
    }
}

extension Unity: UnityFrameworkListener {

    func unityDidUnload(_ notification: Notification!) {
        ufw?.unregisterFrameworkListener(self)
        ufw = nil
        hostMainWindow?.makeKeyAndVisible()
    }
}

Låt oss konfigurera AppDelegate så att vi kan köra appen. ÖppnaAppDelegate.swiftoch ta bort alla scenrelaterade funktioner. Vi måste också skicka referensen till appens huvudfönster till Unity här, eftersom det är det fönstret vi kommer att återvända till när vi stänger Unity-spelet.

Efter dessa ändringar bör din AppDelegate se ut så här:

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        Unity.shared.setHostMainWindow(window)

        return true
    }
}

Till sist återstår bara att starta spelet från vår ContentView.
Vi behöver helt enkelt anropa metodenshow()från vårUnity-klassinuti knappens lyssnare. Så här ser resultatet ut:

import SwiftUI

struct ContentView: View {
    var body: some View {
        Button(action: {
            Unity.shared.show()
        }) {
            Text("Launch Unity!")
        }
    }
}

Så där ja! Nu kör vi appen och provar den!

Viktigt: Se till att du kör appen på en riktig, fysisk iPhone-enhet och inte på en simulator!

Den här GIF-bilden visar hur slutresultatet ska se ut:

Voilà! Det var allt. Vi kan ladda Unity-spelet från vår native SwiftUI-app och återgå till den native delen genom att trycka på knappen ”Quit Game”. Ge dig själv en klapp på axeln – du förtjänar det!

Hur ska ” go ” utvecklas härifrån?

Att ladda och avsluta Unity är en sak. Men ofta vill man överföra data från den inbyggda appen till Unity-spelet, liksom ta emot data tillbaka från spelet. Man kan till exempel behöva överföra viss spelarinformation till spelet innan det startar. Eller skicka spelresultaten tillbaka till den inbyggda iOS-appen, så att den kan formatera dem och skicka dem till en server.

Du kanske till och med vill använda en anpassad styrenhet för ditt spel via Bluetooth, som skulle styras från den native delen och vidarebefordras till Unity! Möjligheterna är oändliga, och det är alltid en bra idé att separera den native logiken från spellogiken där det är möjligt.

UnityFramework erbjuder även denna funktionalitet. Det finns ett sätt att skicka data både till och från Unity genom att använda Unity-ramverket. Om du är intresserad av detta kan du ta en titt påden här artikeln, som visar hur du implementerar kommunikation mellan iOS och Unity! 🚀


Om du gillade den här artikeln, kolla in del 2:

➡️ Kommunicera med ett Unity-spel som är inbäddat i en iOS-app byggd med SwiftUI