How do I access the model component of Reality Composer in RealityKit? - swift

I'm trying to change the model component of a text entity created in Reality Composer in my code, but this as! casting the gui-created entity to a reference to an entity with a model component failed.
self.entityReference = scene.realityComposerEntity as! HasModel
textEntity.model!.mesh = MeshResource.generateText("New Text")
The text entity in RealityKit should have a model property as it has a visual appearance in the ARView, but I don't know how to access it. Does anyone have any idea how?
Are there any other easy ways to dynamically display different text in the same spot using RealityKit/Reality Composer?

To access Reality Composer's ModelComponent in RealityKit try the following approach:
import RealityKit
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
arView.environment.background = .color(.darkGray)
let textAnchor = try! SomeText.loadTextScene() // SomeText is enum
let textEntity: Entity = textAnchor.realityComp!.children[0]
textEntity.scale = [5,5,5]
var textModelComp: ModelComponent = textEntity.children[0].components[ModelComponent]!
var material = SimpleMaterial()
material.baseColor = .color(.systemTeal)
textModelComp.materials[0] = material
textAnchor.realityComp!.children[0].children[0].components.set(textModelComp)
arView.scene.anchors.append(textAnchor)
}
}

Related

RealityKit for VR

Trying to use my RealityKit project as the foundation for an on screen app (VR) instead of projecting onto the real-world (AR) out the back camera.
Anyone know how to load a RealityKit project asynchronously with the .nonAR camera option, so it project in an app instead of leveraging the rear facing camera?
Do I create position information in the Swift code or the Reality Composer project?
Here's how you can asynchronously load .usdz VR-model with a help of RealityKit's .loadModelAsync() instance method and Combine's AnyCancellable type.
import UIKit
import RealityKit
import Combine
class VRViewController: UIViewController {
#IBOutlet var arView: ARView!
var anyCancellable: AnyCancellable? = nil
let anchorEntity = AnchorEntity(world: [0, 0,-2])
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
arView.backgroundColor = .black
arView.cameraMode = .nonAR
anyCancellable = ModelEntity.loadModelAsync(named: "horse").sink(
receiveCompletion: { _ in
self.anyCancellable?.cancel()
},
receiveValue: { [self] (object: Entity) in
if let model = object as? ModelEntity {
self.anchorEntity.addChild(model)
self.arView.scene.anchors.append(self.anchorEntity)
} else {
print("Can't load a model due to some issues")
}
}
)
}
}
However, if you wanna move inside 3D environment, instead of using .nonAR camera mode use:
arView.environment.background = .color(.black)

How to play a video in a macOS application with swift?

I'm trying to get a video I have in my project to play in my macOS application using swift. Here is my code:
import Cocoa
import AVKit
import AVFoundation
class ViewController: NSViewController {
var player : AVPlayer!
var avPlayerLayer : AVPlayerLayer!
#IBOutlet weak var videoPlayer: AVPlayerView!
override func viewDidLoad() {
super.viewDidLoad()
guard let path = Bundle.main.path(forResource: "Background", ofType:"mp4") else {
debugPrint("Not found")
return
}
let playerURL = AVPlayer(url: URL(fileURLWithPath: path))
let playerView = AVPlayerView()
playerView.player = playerURL
playerView.player?.play()
}
}
I also have an AVPlayerView in my storyboard that I have connected to my viewcontroller.
It builds and runs fine but when I run it nothing shows up. I just get a black screen.
Any help is appreciated. Thanks!
The problem is this line:
let playerView = AVPlayerView()
Instead of configuring the player view that is in your interface, you make a whole new separate player view — and then you throw it away.

Loading image from Assets to NSImage keep getting error, expecting NSImage.Name

I am trying to load a file from xcassets to an NSImage, where the asset name is logo.
I tried this:
let logoIcon = NSImage(named: "logo")
But I keep getting this error:
Cannot convert value of type 'String' to expected argument type 'NSImage.Name'
I have looked into the Apple Dev Documentation and from what I can tell this is correct. But for some reason I keep getting the error.
I am trying to do it on macOS if that makes a difference
EDIT:
So I am trying to make a top menu bar app.
And I have adjust the code such that icon is loaded into logoIcon but the Icon is not set in the top menu bar.
import Cocoa
extension NSImage.Name {
static let logo = NSImage.Name("Logo")
}
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.system.statusItem(withLength: -1)
func applicationDidFinishLaunching(_ aNotification: Notification) {
// statusItem.title = "SECRET"
let logoIcon = NSImage(named: .logo)
// icon?.isTemplate = true
statusItem.image = logoIcon
statusItem.menu = statusMenu
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
According to this answer in Apple Developer Forums:
... seems like NSImage(named: String) has been replaced by NSImage(named: NSImage.Name) in Swift 4.
So as suggested in the answer you can create an extension of the struct NSImage.Name:
extension NSImage.Name {
static let logo = NSImage.Name("logo")
}
And use it in this way:
let logoIcon = NSImage(named: .logo)
Francesco Deliro's answer is correct, and you can avoid creating an extension to NSImage.Name with:
let logoIcon = NSImage(named: NSImage.Name("logo"))
To load from the assets catalog of the current bundle, use something like:
let image = Bundle(for: type(of: self)).image(forResource: NSImage.Name(“logo"))!

Shared cookies with WKProcessPool for WKWebView in Swift

Can anyone please tell me how to create a WKProcessPool in Swift? I'm not familiar with Objective-C.
I have to create a WKProcessPool in order to have shared cookies with all WKWebViews. I want to keep cookies even when showing another viewcontroller with same class. I tried the following but it's not working.
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
let processPool = WKProcessPool()
let configuration = WKWebViewConfiguration()
configuration.processPool = WKProcessPool()
webView.navigationDelegate = self
view.addSubview(webView)
}
}
You need to use configuration.websiteDataStore property instead of processpool.
For the stored cookies use WKWebsiteDataStore.default() value.
For the private browsing use WKWebsiteDataStore.nonPersistent().
The apple site say:
If your app creates multiple web views, assign the same WKProcessPool
object to web views that may safely share a process space. Instantiate
an instance of this class and assign it to the processPool property of
each web view’s WKWebViewConfiguration object.
However, you set your processProtocol into class ViewControler. Then, this is redefined each time the view is instantiate. Do it:
import UIKit
import WebKit
let processPool = WKProcessPool()
class ViewController: UIViewController, WKNavigationDelegate { var webView = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
let configuration = WKWebViewConfiguration()
configuration.processPool = WKProcessPool()
webView.navigationDelegate = self
view.addSubview(webView)
}
}

How to embed and stream a video from the web within an Xcode macOS Cocoa Application?

I am trying to get my macOS Cocoa Application Xcode project to play some video when I feed it a specified URL.
To simplify the question lets just use an empty Xcode project.
I want to achieve the same level of control as I am able to get using AVPlayerViewController() in my iOS Single View Application. Within that app I am currently using the solution offered here.
However, only the second example works in my macOS Cocoa Application when adapted like so:
import Cocoa
import AVFoundation
import AVKit
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer?.addSublayer(playerLayer)
player.play()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
This option however has 2 downsides:
It creates a repetitive error message in the console:
2017-06-27 18:22:06.833441+0200 testVideoOnmacOS[24456:1216773] initWithSessionInfo: XPC connection interrupted
2017-06-27 18:22:06.834830+0200 testVideoOnmacOS[24456:1216773] startConfigurationWithCompletionHandler: Failed to get remote object proxy: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.rtcreportingd" UserInfo={NSDebugDescription=connection to service named com.apple.rtcreportingd}
This AVPlayer solution does not offer the same control as the AVPlayerViewController() solution.
So I attempted to get the following AVPlayerViewController() solution to work. But it fails:
import Cocoa
import AVFoundation
import AVKit
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
The error I am getting is:
Use of unresolved identifier 'AVPlayerViewController' - Did you mean
'AVPlayerViewControlsStyle'?
I have tried to work around this in many different ways. It will be confusing if I spell them all out. My prominent problem seems to be that the vast majority of online examples are iOS based.
Thus, the main question:
How would I be able to successfully use AVPlayerViewController within my Xcode macOS Cocoa Application?
Yes, got it working!
Thnx to ninjaproger's comment.
This seems to work in order to get a video from the web playing / streaming on a macOS Cocoa Application in Xcode.
First, create a AVKitPlayerView on your storyboard and link it as an IBOutlet to your NSViewController.
Then, simply apply this code:
import Cocoa
import AVFoundation
import AVKit
class ViewController: NSViewController {
#IBOutlet var videoView: AVPlayerView!
override func viewDidLoad() {
super.viewDidLoad()
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = videoView
playerViewController?.player = player
playerViewController?.player!.play()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
Update august 2021
Ok, it's been a while since this answer has been up and I am no longer invested in it. But it seems others still end up here and the solution needs a bit more work to work properly at times.
With thanks to #SouthernYankee65:
What is needed sometimes is to go to the project file and on the Signing & Capabilities tab check Outgoing Connection (Client). Then in the info.plist add App Transport Security Settings dictionary property, then add Allows Arbitrary Loads boolean property and set it to YES.
The video now plays. However, some errors in the console might occur.