I am building a game with SpriteKit that requires use of the proximity sensor. I have a swipe gesture that turns proximity sensing on, when the proximity sensor senses something it turns off. My problem is that the first time I swipe and put my hand over the sensor, the functions runs and everything works fine. The second time I swipe and put my hand over the sensor the screen just turns black, when I move my hand away from the proximity sensor it then runs the function and everything works. I want it to activate and run the function when I put my hand over the sensor instead of when I remove my hand. Does anybody no how I could fix this?
Proximity sensor code:
func setProximitySensorEnabled(_ enabled: Bool) {
let device = UIDevice.current
device.isProximityMonitoringEnabled = enabled
if device.isProximityMonitoringEnabled == true {
NotificationCenter.default.addObserver(self, selector: #selector(proximityChanged), name: .UIDeviceProximityStateDidChange, object: device)
print("added observer!!!")
} else {
NotificationCenter.default.removeObserver(self, name: .UIDeviceProximityStateDidChange, object: nil)
print("removed observer!!!")
}
}
func proximityChanged(_ notification: Notification) {
if let device = notification.object as? UIDevice {
print("\(device) detected!")
print("An object is near!!")
vibrate()
setProximitySensorEnabled(false)
}
}
Swipe function:
func swipe() {
print("swipe detected")
setProximitySensorEnabled(true)
}
In my case, I found that somewhere in my project set UIDevice.current.isProximityMonitoringEnabled = false after I add the observer. The selector method would not get any notification then.
Related
How to notify the message when manually changes from device notifications from setting
. notifications changes, what method will be invoke inside app, to know that notification was changes
override func awakeFromNib() {
super.awakeFromNib()
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized)
{
print(" authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = true
}
}
else
{
print(" not authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = false
}
}
}
I got tableview inside SettingViewcontroller customize my cell where added the swift onOffSwift.
Based on the setting manually user changes the notifications from setting I wants my app sync accordingly.
SettingViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tbl_SettingView.reloadData()
}
I expected this will work for me? but not
How to handle when user changes there notifications from setting screen should reflect on mobile app screen.
Your app doesn't get an automatic notification when the settings are changed. But the user can make this change only in the Settings app, so you can check the settings when your app comes back to the foreground.
The reason your
override func viewWillAppear(_ animated: Bool) {
doesn't help is that viewWillAppear is not called when the app comes back to the foreground.
There might be better ways but the one I know is this:
Store Settings.authorizationStatus as value in a singleton class or as an entry in UserDefaults
Whenever the app becomes active compare the new value to the stored value. If the they are not the same than you know the settings were changed
I believe you want to get your updated settings when your app enters foreground and not when viewWillAppear called. Just add the observer to your viewDidLoad() (and don't forget to remove it once you're done with the controller):
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { settings in
DispatchQueue.main.async {
// update your view with current settings.authorizationStatus
}
})
}
I have code that puts a blurred UIVisualEffectView over the current window when the didEnterBackgroundNotification notification is fired. It then tries to reverse this when willEnterForegroundNotification is fired (simplified for easy reading):
class AutoBlur {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func appDidEnterBackground() {
blur()
}
#objc func appWillEnterForeground() {
guard UserState.isScreenLockEnabled else {
unblur()
return
}
let authContext = LAContext()
authContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "test") { success, error in
DispatchQueue.main.async {
guard success else {
return
}
unblur()
}
}
}
//...
}
While this approach generally works, when testing the Face ID functionality of app I found the following anomaly:
Open the app
Turn the screen off on the device
Wake the device
Swipe up on the device's lock-screen
Expected results: The device should unlock, and then my app should run its Face ID evaluate code to un-blur the view.
Actual results: The swipe-up action is undercut by my app's Face ID evaluation code. It prevents the user from being able to swipe up on their lock-screen, effectively locking them out of their device.
Is there some state I should be monitoring or some other event that's safer to respond to for triggering my Face ID evaluation?
Ok, maybe I missed something here. I want to use the black remote with my app and got this code essentially from the WWDC 2017 talk on the issue. It says ...
Consistent and intuitive control of media playback is key to many apps on tvOS, and proper use and configuration of MPNowPlayingInfoCenter and MPRemoteCommandCenter are critical to delivering a great user experience. Dive deeper into these frameworks and learn how to ensure a seamless experience whether your app is being controlled using Siri, the Siri Remote, or the iOS Remote app.
So I added these lines to viewDidLoad of my tvOS app and well they do nothing basically?
var commandCenter = MPRemoteCommandCenter.shared()
override func viewDidLoad() {
super.viewDidLoad()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
print("You Pressed play")
return .success
}
commandCenter.pauseCommand.addTarget { (commandEvent) -> MPRemoteCommandHandlerStatus in
print("You Pressed pause")
return .success
}
}
I run the app, and try the play/pause button on the black remote and nothing is printed to the debugging console? Also added some code the plist related to background mode...Should this work or did I miss the point here somewhere?
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>external-accessory</string>
</array>
The commands in MPRemoteCommandCenter aren't triggered by the Siri Remote when your app is in the foreground. To get events from the remote when you're in the foreground, use UIGestureRecognizer like you're probably already used to.
These commands in MPRemoteCommandCenter are for other ways the system may want to interact with your playback, such as:
Your app is playing audio in the background, and the user presses the pause button on the remote: your app I'll be asked to pause playback.
The user is using the TV Remote app for iOS and is using that app's playback control screen.
Posted the question to Apple support; who pointed me in the right direction, need to use the GCMicroGamepad controller or its related GameKit frameworks. Than found a 2015 example posted by blauzahn who most certainly deserves the credit really for this post. Here is his code slightly modified for Swift 3.0, ios 10.x
import GameController
..
var gamePad: GCMicroGamepad? = nil
NotificationCenter.default.addObserver(self,
selector: #selector(gameControllerDidConnect),
name: NSNotification.Name.GCControllerDidConnect,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(gameControllerDidDisconnect),
name: NSNotification.Name.GCControllerDidDisconnect,
object: nil)
func gameControllerDidConnect(notification : NSNotification) {
if let controller = notification.object as? GCController {
if let mGPad = controller.microGamepad {
// Some setup
gamePad = mGPad
gamePad!.allowsRotation = true
gamePad!.reportsAbsoluteDpadValues = true
print("MicroGamePad connected...")
// Add valueChangedHandler for each control element
if gamePad?.buttonA.isPressed == true {
print("button A pressed")
}
if gamePad?.buttonX.isPressed == true {
print("button X pressed")
}
gamePad!.dpad.valueChangedHandler = { (dpad: GCControllerDirectionPad, xValue: Float, yValue: Float) -> Void in
print("dpad xValue = \(xValue), yValue = \(yValue)")
}
gamePad!.buttonA.valueChangedHandler = { (buttonA: GCControllerButtonInput, value:Float, pressed:Bool) -> Void in
print("\(buttonA)")
}
gamePad!.buttonX.valueChangedHandler = { (buttonX: GCControllerButtonInput, value:Float, pressed:Bool) -> Void in
print("\(buttonX)")
}
}
}
}
// Game controller disconnected
func gameControllerDidDisconnect(notification : NSNotification) {
if let controller = notification.object as? GCController {
if controller.microGamepad != nil {
self.gamePad = nil
print("MicroGamePad disconnected...")
}
}
}
Αccording to the Apple's documentation, the image picker only supports portrait mode.
But i want my custom OverlayView to detect device Orientation, for rotate respectively the custom buttons/images i use.
Apple doing that also, on Camera App. If you rotate your device on Landscape, you'll notice that Switch Front Camera Button and Photos thumbnail, rotate itself too.
Is there any way to achieve that?
Well, tried something simple on Controller that uses the imagePicker and did worked.
Let me know, if you have a better solution.
func checkRotation(){
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("landscape")
} else {
print("portrait")
}
}
override func viewDidLoad(){
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(self.checkRotation),
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
EDIT : After struggling with UIDevice.currentDevice().orientation I noticed that randomly didn't received rightly results of orientation. So i followed that one solution posted here on stackoverflow by using CMMotionManager. Just made some changes by using observer and async_patch.
SNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.accelerationGetOrientation), name: UIDeviceOrientationDidChangeNotification, object: nil)
func accelerationGetOrientation(){
uMM = CMMotionManager()
uMM.accelerometerUpdateInterval = 0.2
uMM.startAccelerometerUpdatesToQueue( NSOperationQueue() ) { p, _ in
if p != nil {
if abs( p!.acceleration.y ) < abs( p!.acceleration.x ) {
//LANDSCAPE
dispatch_async(dispatch_get_main_queue()) {
//Do UI Changes
}
}
else {
//PORTRAIT
dispatch_async(dispatch_get_main_queue()) {
//Do UI Changes
}
}
}
}
}
My app continues to play music even when the app is in the background and I am hoping to send the user a notification when the AVPlayer gets overridden (e.g. if the user uses another app that over rides it).
Currently my solution is to use a checkInTimer that sets up a notification and if the app does not checkIn after x amount of time, then the notification goes off, but if it does checkIn it deletes the notification and sets up another one. But this solution sucks..
Any ideas?
You need to observe audio interruptions:
import AVFoundation
func setup() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(myInterruptionHandler), name: AVAudioSessionInterruptionNotification, object: nil)
}
func myInterruptionHandler(notification: NSNotification) {
var info = notification.userInfo!
var intValue: UInt = 0
(info[AVAudioSessionInterruptionTypeKey] as! NSValue).getValue(&intValue)
if let type = AVAudioSessionInterruptionType(rawValue: intValue) {
switch type {
case .Began:
// interruption began
case .Ended:
// interruption ended
}
}
}