Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Integration Unity as a library in native iOS app

Discussion in '2019.3 Beta' started by PavelLU, May 27, 2019.

  1. Lulliflo

    Lulliflo

    Joined:
    Sep 17, 2017
    Posts:
    4
    Hi :) that would be super cool since I'm struggling with that too, I cannot get the touch to work with the subview, do you know if/when you'll be able to share your solution with us?
    Thanks!
     
  2. sengyong1999

    sengyong1999

    Joined:
    Nov 21, 2019
    Posts:
    3
    May I know how you able to achieve this?
     
  3. sengyong1999

    sengyong1999

    Joined:
    Nov 21, 2019
    Posts:
    3
  4. sengyong1999

    sengyong1999

    Joined:
    Nov 21, 2019
    Posts:
    3
    Hi all,

    I've found the solution for using Unity player as a view in native IOS app

    basically I just added this
    Code (CSharp):
    1. ufw?.appController()?.window?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue - CGFloat(globalUILevel))
    in the initUnityWindow()

    It works for now but may not be the practical way to do it, if anyone have a cleaner way to do it please share with us

    Thanks

    Reference:
    https://stackoverflow.com/questions/59428747/embed-unity-inside-ios-in-own-viewcontroller
    https://pub.dev/packages/flutter_unity_widget

    Code (CSharp):
    1. import Foundation
    2. import UnityFramework
    3.  
    4. class UnityEmbeddedSwift: UIResponder, UIApplicationDelegate, UnityFrameworkListener {
    5.  
    6.     private struct UnityMessage {
    7.         let objectName : String?
    8.         let methodName : String?
    9.         let messageBody : String?
    10.     }
    11.  
    12.     private static var instance : UnityEmbeddedSwift!
    13.     private var ufw : UnityFramework!
    14.     private static var hostMainWindow : UIWindow! // Window to return to when exiting Unity window
    15.     private static var launchOpts : [UIApplication.LaunchOptionsKey: Any]?
    16.  
    17.     private static var cachedMessages = [UnityMessage]()
    18.  
    19.     // MARK: - Static functions (that can be called from other scripts)
    20.  
    21.     static func getUnityRootViewController() -> UIViewController! {
    22.         return instance.ufw.appController()?.rootViewController
    23.     }
    24.  
    25.     static func getUnityView() -> UIView! {
    26.         return instance.ufw.appController()?.rootViewController?.view
    27.     }
    28.  
    29.     static func setHostMainWindow(_ hostMainWindow : UIWindow?) {
    30.         UnityEmbeddedSwift.hostMainWindow = hostMainWindow
    31.         let value = UIInterfaceOrientation.landscapeLeft.rawValue
    32.         UIDevice.current.setValue(value, forKey: "orientation")
    33.     }
    34.  
    35.     static func setLaunchinOptions(_ launchingOptions :  [UIApplication.LaunchOptionsKey: Any]?) {
    36.         UnityEmbeddedSwift.launchOpts = launchingOptions
    37.     }
    38.  
    39.     static func showUnity() {
    40.         if(UnityEmbeddedSwift.instance == nil || UnityEmbeddedSwift.instance.unityIsInitialized() == false) {
    41.             UnityEmbeddedSwift().initUnityWindow()
    42.         }
    43.         else {
    44.             UnityEmbeddedSwift.instance.showUnityWindow()
    45.         }
    46.     }
    47.  
    48.     static func hideUnity() {
    49.         UnityEmbeddedSwift.instance?.hideUnityWindow()
    50.     }
    51.  
    52.     static func pauseUnity() {
    53.         UnityEmbeddedSwift.instance?.pauseUnityWindow()
    54.     }
    55.  
    56.     static func unpauseUnity() {
    57.         UnityEmbeddedSwift.instance?.unpauseUnityWindow()
    58.     }
    59.  
    60.     static func unloadUnity() {
    61.         UnityEmbeddedSwift.instance?.unloadUnityWindow()
    62.     }
    63.  
    64.     static func sendUnityMessage(_ objectName : String, methodName : String, message : String) {
    65.         let msg : UnityMessage = UnityMessage(objectName: objectName, methodName: methodName, messageBody: message)
    66.  
    67.         // Send the message right away if Unity is initialized, else cache it
    68.         if(UnityEmbeddedSwift.instance != nil && UnityEmbeddedSwift.instance.unityIsInitialized()) {
    69.             UnityEmbeddedSwift.instance.ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
    70.         }
    71.         else {
    72.             UnityEmbeddedSwift.cachedMessages.append(msg)
    73.         }
    74.     }
    75.  
    76.     // MARK - Callback from UnityFrameworkListener
    77.  
    78.     func unityDidUnload(_ notification: Notification!) {
    79.         ufw.unregisterFrameworkListener(self)
    80.         ufw = nil
    81.         UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
    82.     }
    83.  
    84.     // MARK: - Private functions (called within the class)
    85.  
    86.     private func unityIsInitialized() -> Bool {
    87.         return ufw != nil && (ufw.appController() != nil)
    88.     }
    89.  
    90.     private func initUnityWindow() {
    91.         if unityIsInitialized() {
    92.             showUnityWindow()
    93.             return
    94.         }
    95.  
    96.         ufw = UnityFrameworkLoad()!
    97.         ufw.setDataBundleId("com.unity3d.framework")
    98.         ufw.register(self)
    99. //        NSClassFromString("FrameworkLibAPI")?.registerAPIforNativeCalls(self)
    100.  
    101.         ufw.runEmbedded(withArgc: CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: UnityEmbeddedSwift.launchOpts)
    102.  
    103. // Added this line for touch events in Unity player to work
    104. ufw?.appController()?.window?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue - CGFloat(globalUILevel))
    105.  
    106.         sendUnityMessageToGameObject()
    107.  
    108.         UnityEmbeddedSwift.instance = self
    109.     }
    110.  
    111.     private func showUnityWindow() {
    112.         if unityIsInitialized() {
    113.             ufw.showUnityWindow()
    114.             sendUnityMessageToGameObject()
    115.         }
    116.     }
    117.  
    118.     private func hideUnityWindow() {
    119.         if(UnityEmbeddedSwift.hostMainWindow == nil) {
    120.             print("WARNING: hostMainWindow is nil! Cannot switch from Unity window to previous window")
    121.         }
    122.         else {
    123.             UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
    124.         }
    125.     }
    126.  
    127.     private func pauseUnityWindow() {
    128.         ufw.pause(true)
    129.     }
    130.  
    131.     private func unpauseUnityWindow() {
    132.         ufw.pause(false)
    133.     }
    134.  
    135.     private func unloadUnityWindow() {
    136.         if unityIsInitialized() {
    137.             UnityEmbeddedSwift.cachedMessages.removeAll()
    138.             ufw.unloadApplication()
    139.         }
    140.     }
    141.  
    142.     private func sendUnityMessageToGameObject() {
    143.         if (UnityEmbeddedSwift.cachedMessages.count >= 0 && unityIsInitialized())
    144.         {
    145.             for msg in UnityEmbeddedSwift.cachedMessages {
    146.                 ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
    147.             }
    148.  
    149.             UnityEmbeddedSwift.cachedMessages.removeAll()
    150.         }
    151.     }
    152.  
    153.     private func UnityFrameworkLoad() -> UnityFramework? {
    154.         let bundlePath: String = Bundle.main.bundlePath + "/Frameworks/UnityFramework.framework"
    155.  
    156.         let bundle = Bundle(path: bundlePath )
    157.         if bundle?.isLoaded == false {
    158.             bundle?.load()
    159.         }
    160.  
    161.         let ufw = bundle?.principalClass?.getInstance()
    162.         if ufw?.appController() == nil {
    163.             // unity is not initialized
    164.             //            ufw?.executeHeader = &mh_execute_header
    165.  
    166.             let machineHeader = UnsafeMutablePointer<MachHeader>.allocate(capacity: 1)
    167.             machineHeader.pointee = _mh_execute_header
    168.  
    169.             ufw!.setExecuteHeader(machineHeader)
    170.         }
    171.         return ufw
    172.     }
    173. }
    174.  
    Code (CSharp):
    1. import UIKit
    2.  
    3. class UnityGameViewController: UIViewController {
    4.  
    5.     @IBOutlet weak var unityView: UIView!
    6.  
    7.     override func viewDidLoad() {
    8.         super.viewDidLoad()
    9.      
    10.         UnityEmbeddedSwift.showUnity()
    11.              
    12.         let uView = UnityEmbeddedSwift.getUnityView()
    13.      
    14.         DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
    15.             self.unityView.addSubview(uView!)
    16.          
    17.             DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
    18. //                self.view.sendSubviewToBack(uView!)
    19.             })
    20.         })
    21.      
    22.         // Do any additional setup after loading the view.
    23.     }
    24.  
    25.     /*
    26.     // MARK: - Navigation
    27.  
    28.     // In a storyboard-based application, you will often want to do a little preparation before navigation
    29.     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    30.         // Get the new view controller using segue.destination.
    31.         // Pass the selected object to the new view controller.
    32.     }
    33.     */
     
    Last edited: Jun 14, 2022
    ROBYER1 likes this.
  5. KonstantinMTS

    KonstantinMTS

    Joined:
    Nov 18, 2021
    Posts:
    1

    Can you give that fork? XcodeApi rep has 404 on opening?
     
  6. NSWell

    NSWell

    Joined:
    Jul 30, 2017
    Posts:
    89
    Integration Unity as a Lib with iOS16.0.1(20A371,iPhone14Pro Max) failed.

    - OS:iOS16.0.1-20A371
    - Device:iPhone14Pro Max
    - Unity: Unity 2021.3.10f1 and 2022.1.16f1


    upload_2022-9-19_15-10-31.png
     
  7. Pathawut_P

    Pathawut_P

    Joined:
    Oct 16, 2015
    Posts:
    3
    I got this error too but on iPhone13 Pro Max and Unity 2021.3.9f1
    Any Solution?
     
  8. NSWell

    NSWell

    Joined:
    Jul 30, 2017
    Posts:
    89
    Hi,
    Unlinking from XCode, re- launch the app works fine. But you can not debug with xcode.
     
  9. SKArctop

    SKArctop

    Joined:
    Feb 12, 2018
    Posts:
    38
    Hi All.
    I've recently integrated IOS into a new SwiftUI project.
    This is with Unity 2019.4 and XCode 14.

    I've used @DavidPeicho solution from here:

    https://davidpeicho.github.io/blog/unity-swiftui-integration-revisited/

    Which works great, however, I didn't like changing the Swift UI app and adding the UIKit lifecycle.

    After doing some research I found this:

    https://www.fivestars.blog/articles/app-delegate-scene-delegate-swiftui/

    Which led me to just change my app to this:


    import SwiftUI

    @main
    struct NeuosApp: App {
    @UIApplicationDelegateAdaptor var delegate: AppDelegate

    var body: some Scene {
    WindowGroup {
    ContentView()
    }
    }
    }


    Everything else stayed the same.

    Thought I'd share this with the community.
     
    stacconi, NSWell and ROBYER1 like this.
  10. stacconi

    stacconi

    Joined:
    Jul 26, 2019
    Posts:
    4
  11. SKArctop

    SKArctop

    Joined:
    Feb 12, 2018
    Posts:
    38
  12. unity_8EFB321EA1C418B40C65

    unity_8EFB321EA1C418B40C65

    Joined:
    Feb 25, 2021
    Posts:
    3
    Here is a fork of @DavidPeicho original solution with improvements that achieve the following:
    • The Unity player is rendered in a SwiftUI view that can be resized, repositioned, and used like any normal SwiftUI element
    • The player can be removed or re-added to the UI any time
    • Touch interactions work as you would expect
    • The bug that could prevent unity from appearing is fixed
    • Tested on 2020.2.1f1and 2021.3.18f1
    See the pull request for more detailed explanation.
     
    tteneder and ManjitSBedi like this.