Seto
Seto

Reputation: 1686

Integrating Unity+Vuforia to existing iOS project make user interaction not working

Currently I'm following this tutorial to integrate Unity+Vuforia project to my existing iOS project. I manage to be able to show the Unity view inside my ARViewController. The thing is I lost all the user interaction in my view controller: my touch event for back button not fire up.

import Foundation

class ARViewController: UIViewController {

    var unityView: UIView?

    static func instantiateViewController() -> ARViewController {
        let controller = UIStoryboard.main.instantiateViewController(withIdentifier: "ARViewController") as! ARViewController
        return controller
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.currentUnityController = UnityAppController()
            appDelegate.currentUnityController?.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)
            appDelegate.startUnity()
            NotificationCenter.default.addObserver(self, selector: #selector(handleUnityReady), name: NSNotification.Name("UnityReady"), object: nil)
        }

    }

    @IBAction func onBackPressed(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.stopUnity()
        }
    }

    @objc func backPressedTest() {
    }

    @objc func handleUnityReady() {
        showUnitySubView()
    }

    func showUnitySubView() {

        guard let unityView = UnityGetGLView() else { return }

        self.unityView = unityView
        // insert subview at index 0 ensures unity view is behind current UI view
        view?.addSubview(unityView)

        unityView.translatesAutoresizingMaskIntoConstraints = false
        let views = ["view": unityView]
        let w = NSLayoutConstraint.constraints(withVisualFormat: "|-0-[view]-0-|", options: [], metrics: nil, views: views)
        let h = NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[view]-0-|", options: [], metrics: nil, views: views)
        view.addConstraints(w + h)

        let button = UIButton(type: .custom)
        button.setImage(#imageLiteral(resourceName: "ic_back_black").withRenderingMode(.alwaysTemplate), for: .normal)
        button.addTarget(self, action:#selector(backPressed), for: .touchUpInside)
        button.frame = CGRect(x: 0, y: 0, width: 28, height: 60)
        button.widthAnchor.constraint(equalToConstant: button.frame.width).isActive = true
        button.tintColor = UIColor.purpleBrown()
        view?.addSubview(button)

    }
}

I also notice that button from Unity also have any effect when I touch it. The back button inside the green bar is from Unity. And the blue button is from my ARViewController. Both seem don't reach to touch event. enter image description here

Debug elements: enter image description here

Upvotes: 3

Views: 842

Answers (2)

Vlad Korzun
Vlad Korzun

Reputation: 31

I had the same issue but moving Unity configuration to the end of applicationDidFinishLaunchingWithOption method didn't solve it and I still had a UIWindow in front of my screen that steals all user interactions.

My solution is not to create a new window in UnityAppController.mm, but using the current application keyWindow.

Replace:

    _window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];

with:

    _window = [UIApplication sharedApplication].keyWindow;

Upvotes: 2

Seto
Seto

Reputation: 1686

It happens when I put the Unity configuration at the top of application:didFinishLaunchingWithOptions:, above my existing configuration for another services that I use in the project. For someone who encounter this problem in the future, here's my appDelegate.swift:

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

    self.application = application

    // Another existing settings for the project, e.g. fabric

    Fabric.with([Crashlytics.self])

    // Put the Unity configuration at the bottom of the function

    unity_init(CommandLine.argc, CommandLine.unsafeArgv)
    currentUnityController = UnityAppController()
    currentUnityController?.application(application, didFinishLaunchingWithOptions: launchOptions)
    startUnity()
    stopUnity()

    return true
}

For the viewWillAppear(_:) in the view controller:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    setupBackBarButtonItems(back: true, isDark: true)
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.startUnity()
        showUnitySubView()
    }
}

As mentioned by @Prashant in the comment, the UnityReady notification only get called once. So I don't use it.

Then I just call stopUnity() in viewWillDisappear(_:):

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.stopUnity()
    }
}

The current problem is I can't kill the unity process if I leave the screen. It's known bug and I'm still figuring out how to do that, if it's possible.

Upvotes: 4

Related Questions