Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. 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:
    37
    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.
     
    NSWell and ROBYER1 like this.
  10. stacconi

    stacconi

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

    SKArctop

    Joined:
    Feb 12, 2018
    Posts:
    37
  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.