Running timer and functions at background in Bluetooth App(Swift after iOS 13) - timer

I have an app which is looking for bluetooth devices at background and there is a timer which looking for devices and some other functions to notify user. When the app is running, the timer and functions are working perfectly but when it is closed, it stops.
I tried to check every document I found on web and stackoverflow but found nothing. Actually I check BG fetch and processing in "Target" section and made configuration in info.plist.
But I am not sure exactly what to do in AppDelegate. Here is the functions I want to run in BG:
timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(refreshViews), userInfo: nil, repeats: true)
timer = Timer.scheduledTimer(timeInterval: 9.0, target: self, selector: #selector(removeDevices), userInfo: nil, repeats: true)
timer = Timer.scheduledTimer(timeInterval: 6.0, target: self, selector: #selector(alarm), userInfo: nil, repeats: true)

Related

How do I create a timer in Godot?

How do I create a timer in Godot which destroys the script's object after a given amount of time? I am looking to remove bullets from a game after a while to reduce lag.
There is a Timer node that you can use. You can add it as a child, set the wait time (in seconds) - you probably to set it as one shot and auto start - connect the "timeout" signal to your script, and on the method call queue_free to have the Node (and children, which includes the Timer) freed safely.
You can do that from code too, if that is what you prefer. So, let us go over what I just said, but instead of doing it from the editor, let us see the equivalent code:
Create a Timer, add it as a child:
var timer := Timer.new()
add_child(timer)
Set the wait time (in seconds):
timer.wait_time = 1.0
Set as oneshot:
timer.one_shot = true
Instead of setting it to auto start (which would be timer.autostart = true, let us start it:
timer.start()
Connect the "timeout" signal to a method. In this case, I'll call the method "_on_timer_timeout":
timer.connect("timeout", self, "_on_timer_timeout")
func _on_timer_timeout() -> void:
pass
Then in that method _on_timer_timeout, call queue_free:
timer.connect("timeout", self, "_on_timer_timeout")
func _on_timer_timeout() -> void:
queue_free()
You may want to use the SceneTreeTimer, like in the following code:
func die(delay: float):
yield(get_tree().create_timer(delay), "timeout")
queue_free()
Please refer to Godot Engine's documentation.
In Godot 4, there's an easier way to do this:
# Do some action
await get_tree().create_timer(1.0).timeout # waits for 1 second
# Do something afterwards
queue_free() # Deletes this node (self) at the end of the frame
However, if you do this in the _process() or _physics_process() functions, more timers get created every frame, which causes several runs to occur all at once before then running the following code. To handle this, simply track whether a timed event is happening.
Example in the _process() with simple attack logic:
var attack_started = false;
func _process(delta):
if attack_started:
print("Not attacking, attack code running in background")
return
else:
attack_started = true
prepare_attack()
await get_tree().create_timer(1.0).timeout # wait for 1 second
begin_attack()
attack_started = false
This await keyword works with everything that emits signals, including collision events!
FYI: yield was replaced with await in Godot 4, and await really just waits for a signal/callback to complete:
await object.signal
get_tree().create_timer(5.0) will create a timer that runs for 5 seconds, and then has a timeout callback/signal you can tap into.

User location in Codename One

Our goal is to obtain maximum accuracy (gps) if possible with a 30 seconds timeout and then
if this operation fails, we want to get the location with less accuracy (network) with a 10 seconds timeout
as a last resort (if even the less accurated location is not provided) we want to get last know position
We know that in codename one exists two way of querying location manager
1) by using getCurrentLocationSync:
Location position = LocationManager.getLocationManager().getCurrentLocationSync();
but in this way we don't know how to set accuracy using that API (you confirm that there isn't a way of setting accuracy in this way?)
2) by using setLocationListener:
public MyListener implements LocationListener {
public void locationUpdated(Location location) {
// update UI etc.
}
public void providerStateChanged(int newState) {
// handle status changes/errors appropriately
}
}
LocationManager.getLocationManager().setLocationListener(new MyListener());
but even using this we have only gps position
As an example: the previous version of our application ( using Apache Cordova ) gets the position using this method:
this._getPosition = function(cb,err_cb){
this._open_loading("Ricerca posizione...");
err_cb = err_cb || function(){};
first_err_cb = function(d){
self.options.locationService.getCurrentPosition(
function(pos){
self._close_loading();
cb(pos);
},
function(e){
self._close_loading();
err_cb(e);
},
{ maximumAge: 30000, timeout: 10000, enableHighAccuracy: false }
);
};
self.options.locationService.getCurrentPosition(
function(pos){
self._close_loading();
cb(pos);
},
first_err_cb,
{ maximumAge: 30000, timeout: 20000, enableHighAccuracy: true }
);
};
setLocationListener uses hybrid location and will work with the native device location API which means it will use whatever the device uses including GPS and other sensors. In iOS this is seamless. In Android if you manipulated build hints in some way this can be inadvertently disabled in which case you will fallback to legacy GPS only code.
Notice you can use the setLocationListener(LocationListener, LocationRequest) variant of the method to configure accuracy etc. We don't recommend using the simpler synchronous location API's as their implementation is naive.
To make sure the play services location API will be used in Android you can use the build hint: android.playService.location=true.

MPMusicPlayerController slow to respond when systemMusicPlayer, fast when application

I have a music app that uses the MPMusicPlayerController.
I originally wrote it using the systemMusicPlayer option under iOS 9.
I had some trouble with the player not shutting down correctly under certain circumstances so I switched to the appplicationMusicPlayer
(see Quitting app causes error "Message from debugger: Terminated due to signal 9")
However, as an application player, I can't get a lot of the benefits like control center handling, bluetooth data display, etc.
So, I switched back to the systemMusicPlayer.
I have also changed to Xcode 9.2 and a compile target of iOS 10.3.
Now when I run my app, it can take several seconds for it to respond to controls like play/pause or next/previous. My whole UI is painfully unresponsive.
I tried switching back to applicationMusicPlayer, recompiled, and sure enough - the UI is at normal speed.
So now I'm in a crappy position - with systemMusicPlayer, the app is barely usable, but with applicationMusicPlayer I lose a ton of capabilities.
This seems directly related to either iOS 11.2.2 on my iPhone, or something to do with targeting iOS 10.3+
Does anyone have any information about what is going on and how to fix it
EDIT:
I created a very basic player and it seems to work fine in either mode, so now I'm puzzled - I'll be testing other MP commands to see what the
issue is but since even my UI slows down I'm not sure.
EDIT 2:
I believe I've found the culprit to be NotificationCenter, and also getting States from the MPMusicPlayerController. I've updated my sample code below which shows the problem. Once running, clicking the 'next' button will be slow sometimes, but clicking 'previous' can cause delays of up to two seconds!!
Here is the basic code if you want to create a simple player.
Be sure to add three buttons in the storyboard and connect them accordingly.
//
// ViewController.swift
// junkplayer
//
import UIKit
import MediaPlayer
let notificationCenter = NotificationCenter.default
let myMP:MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
//let myMP:MPMusicPlayerController = MPMusicPlayerController.applicationMusicPlayer()
class ViewController: UIViewController {
#IBOutlet weak var xxx: UIButton!
#IBOutlet weak var nextbut: UIButton!
#IBOutlet weak var prevbut: UIButton!
var qrySongs = MPMediaQuery()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myMP.repeatMode = MPMusicRepeatMode.none
myMP.shuffleMode = MPMusicShuffleMode.off
myMP.prepareToPlay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
stopMPNotifications()
startMPNotifications()
}
#IBAction func nextbut(_ sender: Any) {
myMP.skipToNextItem()
}
#IBAction func prevbut(_ sender: Any) {
myMP.skipToPreviousItem()
}
#IBAction func playbut(_ sender: UIButton) {
qrySongs = MPMediaQuery.songs()
myMP.setQueue(with: qrySongs)
myMP.play()
}
func startMPNotifications(){
notificationCenter.addObserver(self, selector: #selector(showNowPlaying), name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
notificationCenter.addObserver(self, selector: #selector(handlePlayState), name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
myMP.beginGeneratingPlaybackNotifications()
}
func stopMPNotifications(){
notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerPlaybackStateDidChange, object: myMP)
notificationCenter.removeObserver(self, name: .MPMusicPlayerControllerNowPlayingItemDidChange, object: myMP)
myMP.endGeneratingPlaybackNotifications()
}
#objc func handlePlayState(){
if myMP.playbackState == .playing {
print("handlePlayState playback state = playing")
}else{
print("handlePlayState playback state NOT playing")
}
print("handlePlayState going to shownowplaying")
showNowPlaying()
}
#objc func showNowPlaying(){
if myMP.nowPlayingItem != nil {
print("shownowplaying nowplaying not null")
}
}
}
The app seems to lock up once you start playing, but if you swipe up to show the Control Centre then dismiss it, the app starts working fine immediately.
I am having the same problem. I think it’s something wrong with the API. It's especially slow for large queries. But you can put a predicate on the quart, that allows no cloud music to go on it.
For anyone browsing this thread in the future, this was a known bug within all versions of iOS 11.2. It affected anyone using the systemMusicPlayer.
Apple sure does love to discourage us third party music app developers, eh? ;)
Regardless of my conspiracy theories (and I'm sure you have yours too), this bug was fixed in iOS 11.3.
We warn users on iOS 11.2 about the bug and recommend that they upgrade to iOS 11.3 for a (more or less) lag-free experience.
I ran into this problem today - working code just stopped running correctly, but I found a (partial) workaround:
\\Do anything that updates (like changing the song title in the UI) in the selector called by this notification
NotificationCenter.default.addObserver(self, selector: #selector(remoteMusicChange), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: nil)
The issue is that calls to say go to the next track for systemMusicPlayer are no longer (always) happening immediately. If you wait for the notification, at least you can be sure systemMusicPlayer has updated.
The problem with this is sometimes it can take a perceptibly long time for that notification to fire (and sometimes it's instant).
EDIT: https://forums.developer.apple.com/thread/96287 I am guessing this is related to these issues
EDIT2: Tested another related issue quickly in iOS12 and the problem no longer existed (changing playback speed) and the pauses when changing songs went away.

iOS11, Xcode 9, iPhone6 Plus, UIDeviceDidChangeOrientation notification not called,UIDevice.current.orientation only returns portrait

Im using xcode 9, ios 11. I have an observer for UIDeviceOrientationDidChange and it works well on my 6s, but on the 6s Plus, it is not called when the device changes orientation, and checking UIDevice.current.orientation shows portrait at all times regardless of device position.
Anyone have any information about this?
Code is really basic
NotificationCenter.default.addObserver(self, selector: #selector(showHideRotateOverlay), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
added in viewWillAppear. Works in ios 8, 9, 10.
Portrait and LandscapeRight are enabled in settings. this DOES WORK on previous ios versions

UIActivityViewController.completionWithItemsHandler is not called on iOS 10.0 when I select "Print" menu and cancel it

I created a simple application which uses UIActivityViewController as below.
let text = "Test Text"
let printData = UISimpleTextPrintFormatter(text: text)
let vc = UIActivityViewController(activityItems: [text, printData], applicationActivities: nil)
vc.completionWithItemsHandler = { (type,completed,items,error) in
print("completed. type=\(type) completed=\(completed) items=\(items) error=\(error)")
}
vc.modalPresentationStyle = .popover
vc.popoverPresentationController?.sourceView = self.openActivityButton
vc.popoverPresentationController?.sourceRect = self.openActivityButton.bounds
vc.popoverPresentationController?.permittedArrowDirections = .up
vc.popoverPresentationController?.delegate = self
self.present(vc, animated: true) { () in
}
and I run this application on iOS 10 (Xcode 8.0 beta 6).
When I close activity dialog, the completionWithItemsHandler is called.
When I select "Copy" activity, the completionWithItemsHandler is called.
When I select "Mail" activity and cancel it, the completionWithItemsHandler is called.
But, when I select "Print" activity and cancel it, the completionWithItemsHandler is not called.
This strange behavior occurred on iOS 10 but not occurred on iOS9 (the handler was called on iOS9)
Is this iOS 10's bug? If so, are there any workarounds to detect the UIActivityController is dismissed?
I pushed this sample app on https://github.com/kunichiko/ios10-activity-bug
I had a similar problem. In my case, I noticed that the completion handler was not called because the UIActivityController was already dismissed and deallocated. What I did was just add a property to hold a strong reference and set it to nil later. Then the completion handler was called properly.

Resources