This question already has answers here:
Why cannot I set UIScreen.main.brightness?
(2 answers)
Closed 3 months ago.
I setting UIScreen.main.brightness = 1.0 at viewDidLoad.
But print in console value of UIScreen.main.brightness is 0.9483038187026978.
Please help me.
I not good English , so sorry
You can use SceneDelegate as described in the following article:
https://medium.com/#arikisintown/how-to-create-an-ios-app-that-takes-secret-photos-while-the-iphone-screen-seems-to-be-turned-off-7081d110309e
--
From the article:
We will add a separate class dedicated to controlling the screen brightness:
final class DimUnDim {
static let shared = DimUnDim()
private var originalBrightness = UIScreen.main.brightness
func dim() {
print("dim")
UIScreen.main.wantsSoftwareDimming = true
UIScreen.main.brightness = 0.0
}
func unDim() {
print("unDim")
UIScreen.main.brightness = originalBrightness
}
}
We will call Dim when the app becomes active and call UnDim when the app is not active. Edit the file SceneDelegate.swift and add the following:
func sceneDidBecomeActive(_ scene: UIScene) {
DimUnDim.shared.dim()
}
func sceneWillResignActive(_ scene: UIScene) {
DimUnDim.shared.unDim()
}
Related
I'm new here and new with music apps (and programming in general).
I'm trying to build a synth app using AudioKit 5 for my final project.
I made an oscillator and tried to add Amplitude Envelope but no sound coming out.
(If I put the oscillator in the output - there is a sound.)
I saw this question in the internet several times in different types but without any solution.
Does anyone know what is the problem?
And if not - do you have other solution for envelope?
The code:
import AudioKit
import SoundpipeAudioKit
import UIKit
class TryingViewController: UIViewController {
var osc = Oscillator(waveform: Table(.sine), frequency: 440, amplitude: 0.8)
var engine = AudioEngine()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func onBtn(_ sender: UIButton) {
let envelope = AmplitudeEnvelope(osc)
envelope.attackDuration = 0.1
envelope.decayDuration = 0.01
envelope.sustainLevel = 0.5
envelope.releaseDuration = 0.3
osc.start()
do {
try engine.start()
} catch {
print(error, "Field")
}
engine.output = envelope
envelope.start()
}
#IBAction func offBtn(_ sender: UIButton) {
osc.stop()
}
}
Edit:
I add this code and it works now, thanks to Aurelius Prochazk!
var isGateOpend = false
.
.
.
if isGateOpend{
envelope.closeGate()
isGateOpend = false
} else {
envelope.openGate()
isGateOpend = true
}
I still have a click, but I will open another question about it if I won't figure it out.
Thanks in advance!
The AmplitudeEnvelope is a "Gated" Node meaning that it responds to openGate and closeGate which should be used instead of start stop since those are at the node level rather than control level.
I'm having an issue with UndoManager which might be an iPadOS bug, but could also be my mistake.
I have a simple test app. One button performs an action, which increments an int by 1 and registers an undo with the system UndoManager. Another button manually calls undoManager.undo(), which undoes the last action until no more actions on the undo stack remain. And the overall app is a first responder with the system, so hitting CMD+Z should also trigger the undoManager to call undo() once per CMD+Z press.
Here's some code.
The UIHostingController subclass that allows becoming first responder:
class FirstResponderHostingController<Content: View>: UIHostingController<Content> {
override var canBecomeFirstResponder: Bool { true }
}
SceneDelegate, where I pass in the system undo manager:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let model = MyObject(undoManager: window.undoManager)
let contentView = ContentView(model: model)
window.rootViewController = FirstResponderHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
//...
}
And my SwiftUI view and associated model:
class MyObject: ObservableObject {
var undoManager: UndoManager?
var state: Int = 0
init(undoManager: UndoManager? = nil) {
self.undoManager = undoManager
}
func registerAction() {
state += 1
undoManager?.registerUndo(withTarget: self, selector: #selector(performUndo), object: nil)
print("registered action - state is \(state)")
}
#objc func performUndo() {
state -= 1
print("performUndo called - state is \(state)")
}
func undo() {
print("undo() called")
undoManager?.undo()
}
}
struct ContentView: View {
#ObservedObject var model: MyObject
var body: some View {
VStack(spacing: 16) {
Button(action: {
self.model.registerAction()
}) {
Text("Register an Action")
}
Button(action: {
self.model.undo()
}) {
Text("Manual Undo (Not from Keyboard)")
}
}
}
}
So for example, if I tap "Register Action" twice, and then "Manual Undo" three times, the output is what I expect - the state was incremented twice, then decremented twice, and the last undo() does nothing because the undo stack is empty:
registered action - state is 1
registered action - state is 2
undo() called
performUndo called - state is 1
undo() called
performUndo called - state is 0
undo() called
But if I tap "Register Action" twice, and then hit CMD+Z on the iPad keyboard, I expect the state to be incremented twice and decremented only once, with one call to performUndo, but instead performUndo is still called twice:
registered action - state is 1
registered action - state is 2
performUndo called - state is 1
performUndo called - state is 0
Am I using the system UndoManager incorrectly somehow, or is this a bug?
Update: The above is with Xcode 11.3.1 and iPadOS 13.3. Using the latest Xcode 11.4 beta 2 and iPadOS 13.4 beta 2, the double-undo no longer occurs. Seems fixed!
Using Unity 2019.3.0f3 and its Unity as a library feature I'm trying to embed a Unity project inside my iOS application.
Unity officially only supports full screen rendering. Nevertheless I'm looking for a way around that restriction.
In previous versions of Unity i successfully used swift-unity to do the integration. Within this approach it is easy to just get the View where Unity is rendering to (using UnityGetGLView()). I had no problems regarding stability or resources.
Using the new library approach, every time I try to access the UnityView, unity forces it's complete Window as keyWindow.
I tried accessing the UnityView in my own ViewController using
if let unityView = UnityFramework.getInstance()?.appController()?.rootViewController.view {
// insert subview at index 0 ensures unity view is behind current UI view
view?.insertSubview(unityView, at: 0)
}
But that immediately activates the complete unity-window and hides my parenting UITabBarController.
Trying to make the UnityFramework.getInstance()?.appController()?.rootViewController a child of my UITabBarController failed with the same result.
Furthermore it is not possible to add a child ViewController. Only adding subviews seems possible.
Does anybody know where that window-behaviour is located or how i can access the UnityView (or the RootViewController) and use it freely?
I found a solution to the problem based on this approach from the unity forum. Using this approach I'm able to use the UnityViewController as a child in my own TabBarController.
The approach is working for Unity 2019.3.0f3, but I'm not sure if it will work in future versions. It feels like Unity tries to actively prevent such use. Then again I found hints in comments in the library-code that would suggest that a modified ViewController-Hierarchy was at least contemplated e.g. in UnityAppController+ViewHandling.h. But the instructions are unclear and methods with the hinted names don't exist.
Solution
1. Create UnityEmbeddedSwift.swift
The official example App provided by Unity is a real mess. I ended up using the UnityEmbeddedSwift.swift from the linked forum post with additions for pausing. This class encapsulates all Unity-related functionality in one clean class.
//
// UnityEmbeddedSwift.swift
// Native
//
// Created by NSWell on 2019/12/19.
// Copyright © 2019 WEACW. All rights reserved.
//
//
// Created by Simon Tysland on 19/08/2019.
// Copyright © 2019 Simon Tysland. All rights reserved.
//
import Foundation
import UnityFramework
class UnityEmbeddedSwift: UIResponder, UIApplicationDelegate, UnityFrameworkListener {
private struct UnityMessage {
let objectName : String?
let methodName : String?
let messageBody : String?
}
private static var instance : UnityEmbeddedSwift!
private var ufw : UnityFramework!
private static var hostMainWindow : UIWindow! // Window to return to when exiting Unity window
private static var launchOpts : [UIApplication.LaunchOptionsKey: Any]?
private static var cachedMessages = [UnityMessage]()
// MARK: - Static functions (that can be called from other scripts)
static func getUnityRootViewController() -> UIViewController! {
return instance.ufw.appController()?.rootViewController
}
static func getUnityView() -> UIView! {
return instance.ufw.appController()?.rootViewController?.view
}
static func setHostMainWindow(_ hostMainWindow : UIWindow?) {
UnityEmbeddedSwift.hostMainWindow = hostMainWindow
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
}
static func setLaunchinOptions(_ launchingOptions : [UIApplication.LaunchOptionsKey: Any]?) {
UnityEmbeddedSwift.launchOpts = launchingOptions
}
static func showUnity() {
if(UnityEmbeddedSwift.instance == nil || UnityEmbeddedSwift.instance.unityIsInitialized() == false) {
UnityEmbeddedSwift().initUnityWindow()
}
else {
UnityEmbeddedSwift.instance.showUnityWindow()
}
}
static func hideUnity() {
UnityEmbeddedSwift.instance?.hideUnityWindow()
}
static func pauseUnity() {
UnityEmbeddedSwift.instance?.pauseUnityWindow()
}
static func unpauseUnity() {
UnityEmbeddedSwift.instance?.unpauseUnityWindow()
}
static func unloadUnity() {
UnityEmbeddedSwift.instance?.unloadUnityWindow()
}
static func sendUnityMessage(_ objectName : String, methodName : String, message : String) {
let msg : UnityMessage = UnityMessage(objectName: objectName, methodName: methodName, messageBody: message)
// Send the message right away if Unity is initialized, else cache it
if(UnityEmbeddedSwift.instance != nil && UnityEmbeddedSwift.instance.unityIsInitialized()) {
UnityEmbeddedSwift.instance.ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
}
else {
UnityEmbeddedSwift.cachedMessages.append(msg)
}
}
// MARK - Callback from UnityFrameworkListener
func unityDidUnload(_ notification: Notification!) {
ufw.unregisterFrameworkListener(self)
ufw = nil
UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
}
// MARK: - Private functions (called within the class)
private func unityIsInitialized() -> Bool {
return ufw != nil && (ufw.appController() != nil)
}
private func initUnityWindow() {
if unityIsInitialized() {
showUnityWindow()
return
}
ufw = UnityFrameworkLoad()!
ufw.setDataBundleId("com.unity3d.framework")
ufw.register(self)
// NSClassFromString("FrameworkLibAPI")?.registerAPIforNativeCalls(self)
ufw.runEmbedded(withArgc: CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: UnityEmbeddedSwift.launchOpts)
sendUnityMessageToGameObject()
UnityEmbeddedSwift.instance = self
}
private func showUnityWindow() {
if unityIsInitialized() {
ufw.showUnityWindow()
sendUnityMessageToGameObject()
}
}
private func hideUnityWindow() {
if(UnityEmbeddedSwift.hostMainWindow == nil) {
print("WARNING: hostMainWindow is nil! Cannot switch from Unity window to previous window")
}
else {
UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
}
}
private func pauseUnityWindow() {
ufw.pause(true)
}
private func unpauseUnityWindow() {
ufw.pause(false)
}
private func unloadUnityWindow() {
if unityIsInitialized() {
UnityEmbeddedSwift.cachedMessages.removeAll()
ufw.unloadApplication()
}
}
private func sendUnityMessageToGameObject() {
if (UnityEmbeddedSwift.cachedMessages.count >= 0 && unityIsInitialized())
{
for msg in UnityEmbeddedSwift.cachedMessages {
ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
}
UnityEmbeddedSwift.cachedMessages.removeAll()
}
}
private func UnityFrameworkLoad() -> UnityFramework? {
let bundlePath: String = Bundle.main.bundlePath + "/Frameworks/UnityFramework.framework"
let bundle = Bundle(path: bundlePath )
if bundle?.isLoaded == false {
bundle?.load()
}
let ufw = bundle?.principalClass?.getInstance()
if ufw?.appController() == nil {
// unity is not initialized
// ufw?.executeHeader = &mh_execute_header
let machineHeader = UnsafeMutablePointer<MachHeader>.allocate(capacity: 1)
machineHeader.pointee = _mh_execute_header
ufw!.setExecuteHeader(machineHeader)
}
return ufw
}
}
2. Modify AppDelegate.swift
Sets window and launch options needed by UnityEmbeddedSwift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UnityEmbeddedSwift.setHostMainWindow(window)
UnityEmbeddedSwift.setLaunchinOptions(launchOptions)
return true
}
3. Create RootTabBarController.swift
This class sets up the hierarchy.
It is important to use the UnityRootViewController right after calling UnityEmbeddedSwift.showUnity().
The Tab-Switching is not nice, but if it is missing Unity will pause (or freeze?) during loading. The timing seems to depend on the Unity-Projects loading time. It can be faster for small projects and needs more time for larger projects.
import UIKit
class RootTabBarController: UITabBarController, UITabBarControllerDelegate {
var unityNC: UINavigationController?
var nativeNC: UINavigationController?
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
// start unity and immediatly set as rootViewController
// this loophole makes it possible to run unity in the same window
UnityEmbeddedSwift.showUnity()
let unityViewController = UnityEmbeddedSwift.getUnityRootViewController()!
unityViewController.navigationItem.title = "Unity"
unityNC = UINavigationController.init(rootViewController: unityViewController)
unityNC?.tabBarItem.title = "Unity"
let nativeViewController = UIViewController.init()
nativeViewController.view.backgroundColor = UIColor.darkGray
nativeViewController.navigationItem.title = "Native"
nativeNC = UINavigationController.init(rootViewController: nativeViewController)
nativeNC?.tabBarItem.title = "Native"
viewControllers = [unityNC!, nativeNC!]
// select other tab and reselect first tab to unfreeze unity-loading
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
self.selectedIndex = 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01, execute: {
self.selectedIndex = 0
})
})
}
// MARK: - UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
// pause unity if unity-tab is not selected
if viewController != unityNC {
UnityEmbeddedSwift.pauseUnity()
} else {
UnityEmbeddedSwift.unpauseUnity()
}
}
}
4. Modify Main.storyboard
Modify the storyboard to start with the RootTabBarController.
For anyone who is still interested in preventing the freezing, I am building on top of aalmigthy's answer:
You do not need to add a TabBar controller and switch between the tabs. All you need to do is:
Add the Unity view as a subview
Send the subview to back
Here's the modified ViewController class (no need for a tab bar):
import UIKit
class HybridViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UnityEmbeddedSwift.showUnity()
let uView = UnityEmbeddedSwift.getUnityView()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
self.view.addSubview(uView!)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
self.view.sendSubviewToBack(uView!)
})
})
}
}
in swift3
I want to change the screen to hide the original screen when the app is in the background state.
For example, if you press the home button twice while the app is running, the screen will change to a different screen.
I want to set the screen to change to LaunchScreen.
Thank you for your help.
Try this one:
func applicationDidEnterBackground(_ application: UIApplication) {
let imageView = UIImageView(frame: self.window!.bounds)
imageView.tag = 1001
imageView.image = UIImage(named: "") //your image goes here
UIApplication.shared.keyWindow?.subviews.last?.addSubview(imageView)
}
func applicationWillEnterForeground(_ application: UIApplication) {
if let imageView : UIImageView = UIApplication.shared.keyWindow?.subviews.last?.viewWithTag(1001) as? UIImageView {
imageView.removeFromSuperview()
}
}
"If you do not want your application to remain in the background when it is quit, you can explicitly opt out of the background execution model by adding the UIApplicationExitsOnSuspend key to your application’s Info.plist file and setting its value to YES.
When an application opts out, it cycles between the not running, inactive, and active states and never enters the background or suspended states.
When the user taps the Home button to quit the application, the applicationWillTerminate: method of the application delegate is called and the application has approximately five seconds to clean up and exit before it is terminated and moved back to the not running state."
s
Add this function in your AppDelegate.
func applicationWillResignActive(_ application: UIApplication) {
// Change the view to show what you want here.
}
This method is called to let your app know that it is about to move
from the active to inactive state. This can occur for certain types of
temporary interruptions (such as an incoming phone call or SMS
message) or when the user quits the app and it begins the transition
to the background state.
Source: https://developer.apple.com/reference/uikit/uiapplicationdelegate/1622950-applicationwillresignactive
This is common scenario where we want to avoid screen-shotting by iOS while going to BG or covering app screens when app is in stack.
Here is what I'm doing:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private var appCoverWindow: UIWindow?
private var appCoverVC: UIViewController?
func applicationDidBecomeActive(_ application: UIApplication) {
if appCoverWindow != nil {
appCoverWindow!.isHidden = true
appCoverWindow!.rootViewController = nil
appCoverWindow = nil
appCoverVC = nil
}
}
func applicationWillResignActive(_ application: UIApplication) {
appCoverVC = rootViewController().storyboard!.instantiateViewController(withIdentifier: "AppCoverVCId") as! AppCoverViewController
appCoverWindow = UIWindow(frame: UIScreen.main.bounds)
let existingTopWindow = UIApplication.shared.windows.last
appCoverWindow!.windowLevel = existingTopWindow!.windowLevel + 1
appCoverVC!.view.frame = appCoverWindow!.bounds
appCoverWindow!.rootViewController = appCoverVC!
appCoverWindow!.makeKeyAndVisible()
}
class func appLaunchImage() -> UIImage? {
//this method will return LaunchImage
let launchImageNames = Bundle.main.paths(forResourcesOfType: "png", inDirectory: nil).filter { (imageName) -> Bool in
return imageName.contains("LaunchImage")
}
for imageName in launchImageNames {
guard let image = UIImage(named: imageName) else { continue }
// if the image has the same scale and dimensions as the current device's screen...
if (image.scale == UIScreen.main.scale) && (image.size.equalTo(UIScreen.main.bounds.size)) {
return image
}
}
return nil
}
}
Instead of using UIWindow to cover app, we can directly use UIViewController also, but that may cause issues if keyboard is present while going to BG.
Here is AppCoverViewController.swift:
(It has XIB in storyboard with one full screen UIImageView)
class AppCoverViewController: BaseViewController {
#IBOutlet weak var bgImageView: UIImageView!//full screen image view
override func viewDidLoad() {
super.viewDidLoad()
if let image = AppDelegate.appLaunchImage() {
bgImageView.image = image
}
}
override func deviceOrientationDidChange() {
if let image = AppDelegate.appLaunchImage() {
bgImageView.image = image
}
}
}
This class takes care of device rotations also.
I am trying to create a turn-based game which progresses until 13 rounds are over. However, after I created an infinite while loop which would only break after 13 rounds, the scene never loaded. Why is it that the code in didMoveToView is executed before the scene shows? Is there a way to fix this or am I possibly doing something wrong?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
view.ignoresSiblingOrder = true
roundFirstCard = Card(key: "2c")
var actions = [SKAction]()
let cards = makeDeck()
for c in cards {
let card = Card(key: c)
card.name = card.key
card.position = CGPointMake(500, 400)
addChild(card)
giveCardToCorrectPlayer(cards.indexOf(c)!, c: card)
actions.append(SKAction.runAction(SKAction.moveTo(getTargetLocationForCard(cards.indexOf(c)!), duration: 1.0), onChildWithName: card.name!))
actions.append(SKAction.waitForDuration(0.05))
}
actions.append(SKAction.waitForDuration(1.0))
playerCardSets = [player1Cards, player2Cards, player3Cards, player4Cards]
self.runAction(SKAction.sequence(actions), completion: {self.spreadCards()})
currentPlayer = 1
while true {}
}
You don't need a while loop, especially if your scene is a round.
So I suppose this scene you've write in your question is a typical round of your game.
You can save the rounds number in NSUserDefaults for example in AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
NSUserDefaults.standardUserDefaults().setInteger(0, forKey: "roundCounter")
NSUserDefaults.standardUserDefaults().synchronize()
return true
}
So in your scene you know what is your round:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
var roundCounter = NSUserDefaults.standardUserDefaults().integerForKey("roundCounter")
roundCounter += 1 //Start new round
guard let r = roundCounter where r > 13 {
gameOver() //launch gameOver function
return
}
// do your stuff
// save the actual round number
NSUserDefaults.standardUserDefaults().setInteger(roundCounter, forKey: "roundCounter")
NSUserDefaults.standardUserDefaults().synchronize()
}
func gameOver() {
// reset to zero your round counter
NSUserDefaults.standardUserDefaults().setInteger(0, forKey: "roundCounter")
NSUserDefaults.standardUserDefaults().synchronize()
//do your stuff
}