How to publish or send a message by MQTT client framework when application is in background in iOS Swift - ios

I am developing an application to send the current user location every 15 minutes via the MQTT client framework. When the application is in the foreground it works fine but when the application is in background, the MQTT delegate function "messageDelivered" doesn't get called
We want to use the MQTT client framework to publish message in background in iOS swift.
import UIKit
import MQTTClient
class MainViewController: UIViewController {
let MQTT_HOST = "next.nanolink.com" // or IP address e.g. "192.168.0.194"
//let MQTT_HOST = "tnclicks.free.beeceptor.com" // or IP address e.g. "192.168.0.194"
let MQTT_PORT: UInt32 = 1883
private var transport = MQTTCFSocketTransport()
fileprivate var session = MQTTSession()
fileprivate var completion: (()->())?
override func viewDidLoad() {
super.viewDidLoad()
//notification observer
NotificationCenter.default.addObserver(self, selector: #selector(onDidReceiveData(_:)), name: .didReceiveData, object: nil)
//MQTT
self.session?.delegate = self
self.transport.host = MQTT_HOST
self.transport.port = MQTT_PORT
session?.transport = transport
updateUI(for: self.session?.status ?? .created)
session?.connect() { error in
print("connection completed with status \(String(describing: error?.localizedDescription))")
if error != nil {
self.updateUI(for: self.session?.status ?? .created)
} else {
self.updateUI(for: self.session?.status ?? .error)
}
}
}
private func subscribe() {
self.session?.subscribe(toTopic: "test/message", at: .exactlyOnce) { error, result in
print("subscribe result error \(String(describing: error)) result \(result!)")
}
}
private func updateUI(for clientStatus: MQTTSessionStatus) {
DispatchQueue.main.async {
switch clientStatus {
case .connected:
print("Connected")
self.publishMessage("on", onTopic: "test/message")
case .connecting,
.created:
print ("Trying to connect...")
default:
print ("Connetion Failed...")
}
}
}
private func publishMessage(_ message: String, onTopic topic: String)
{
session?.publishData(message.data(using: .utf8, allowLossyConversion: false), onTopic: topic, retain: false, qos: .exactlyOnce)
}
#objc func onDidReceiveData(_ notification:Notification) {
print("check return")
guard session?.status == .connected else {
self.updateUI(for: self.session?.status ?? .error)
return
}
let obj = notification.object! as! NSMutableDictionary
print(notification.object!)
let notificationLatitude = obj.value(forKey: "latitude")!
let notificationLongitude = obj.value(forKey: "longitude")!
//let notificationLongitude = notification.object
// print(" Saved latitude:", latitude!)
// print(" Saved longitude:", longitude!)
print(" notification latitude:", notificationLatitude)
print(" notification longitude:", notificationLongitude)
guard session?.status == .connected else {
return
}
publishMessage("on", onTopic: "test/message")
}
}
extension MainViewController: MQTTSessionManagerDelegate, MQTTSessionDelegate {
func newMessage(_ session: MQTTSession!, data: Data!, onTopic topic: String!, qos: MQTTQosLevel, retained: Bool, mid: UInt32) {
if let msg = String(data: data, encoding: .utf8) {
print("topic \(topic!), msg \(msg)")
}
}
func messageDelivered(_ session: MQTTSession, msgID msgId: UInt16) {
print("delivered")
DispatchQueue.main.async {
self.completion?()
}
}
}
extension Notification.Name {
static let didReceiveData = Notification.Name("didReceiveData")
}

We have implemented update location in Background so update your code with update location to send Message in background.
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,CLLocationManagerDelegate {
var window: UIWindow?
var locationManager = CLLocationManager()
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
var bgtimer = Timer()
var latitude: Double = 0.0
var longitude: Double = 0.0
var current_time = NSDate().timeIntervalSince1970
var timer = Timer()
var f = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.doBackgroundTask()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("Entering foreBackground")
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("Entering Background")
// self.doBackgroundTask()
}
func doBackgroundTask() {
DispatchQueue.main.async {
self.beginBackgroundUpdateTask()
self.StartupdateLocation()
self.bgtimer = Timer.scheduledTimer(timeInterval:-1, target: self, selector: #selector(AppDelegate.bgtimer(_:)), userInfo: nil, repeats: true)
RunLoop.current.add(self.bgtimer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
self.endBackgroundUpdateTask()
}
}
func beginBackgroundUpdateTask() {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
}
func StartupdateLocation() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while requesting new coordinates")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
self.latitude = locValue.latitude
self.longitude = locValue.longitude
f+=1
print("New Coordinates: \(f) ")
print(self.latitude)
print(self.longitude)
}
#objc func bgtimer(_ timer:Timer!){
sleep(2)
/* if UIApplication.shared.applicationState == .active {
timer.invalidate()
}*/
self.updateLocation()
}
func updateLocation() {
self.locationManager.startUpdatingLocation()
self.locationManager.stopUpdatingLocation()
}}

Related

Sending location to server in background every x minutes

I would like to send the device's location to a server every x minutes, even if the location does not change, while the app is in the background. (most optimal timeframe would be like 1.5 - 2 hours)
Currently it gets terminated after 30 sec.
I have seen some articles about adding these to the AppDelegate's didFinishLaunchingWithOptions method:
application.setMinimumBackgroundFetchInterval(1800)
UIApplication.shared.setMinimumBackgroundFetchInterval(1800)
but it got deprecated in iOS 13.
The AppDelegate looks like this:
import UIKit
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
var backgroundTaskTimer: Timer! = Timer()
var locationManager: LocationManager!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
locationManager = LocationManager()
let coordinator = AppCoordinator(window: window)
coordinator.start()
return true
}
func applicationDidEnterBackground(_ application: UIApplication) {
doBackgroundTask()
}
func applicationWillEnterForeground(_ application: UIApplication) {
if backgroundTaskTimer != nil {
backgroundTaskTimer.invalidate()
backgroundTaskTimer = nil
}
}
#objc func startTracking() {
self.locationManager.sendLocation()
}
func doBackgroundTask() {
DispatchQueue.global(qos: .default).async {
self.beginBackgroundTask()
if self.backgroundTaskTimer != nil {
self.backgroundTaskTimer.invalidate()
self.backgroundTaskTimer = nil
}
//Making the app to run in background forever by calling the API
self.backgroundTaskTimer = Timer.scheduledTimer(timeInterval: AppEnvironment.backgroundTimeInterval,
target: self, selector: #selector(self.startTracking),
userInfo: nil, repeats: true)
RunLoop.current.add(self.backgroundTaskTimer, forMode: RunLoop.Mode.default)
RunLoop.current.run()
// End the background task.
self.endBackgroundTask()
}
}
func beginBackgroundTask() {
backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(withName: "Track trip", expirationHandler: {
self.endBackgroundTask()
})
}
func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundUpdateTask)
backgroundUpdateTask = UIBackgroundTaskIdentifier.invalid
}
}
The LocationManager looks like this:
import Foundation
import CoreLocation
class LocationManager: NSObject, CLLocationManagerDelegate {
private let locationService: LocationServiceProtocol
private let manager = CLLocationManager()
private var lastLocation: Coordinate?
private var offlineCoordinates: [Coordinate] = []
init(locationService: LocationServiceProtocol = LocationService()) {
self.locationService = locationService
}
func sendLocation() {
manager.delegate = self
manager.requestLocation()
}
private func handleLocation() {
guard let coordinate = lastLocation else { return }
guard Connectivity.isConnectedToTheInternet else {
offlineCoordinates.append(coordinate)
return
}
if !offlineCoordinates.isEmpty {
offlineCoordinates.forEach { postCoordinate($0) }
offlineCoordinates.removeAll()
}
postCoordinate(coordinate)
}
private func postCoordinate(_ coordinate: Coordinate) {
locationService.sendLocation(coordinate) { [weak self] result in
guard self != nil else { return }
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(_):
print("Location sent.")
}
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
manager.delegate = nil
guard let location = locations.first else { return }
let latitude = location.coordinate.latitude
let longitude = location.coordinate.longitude
print("\tLatitude: \(latitude), Longitude: \(longitude)")
lastLocation = Coordinate(lat: latitude, lon: longitude,
supervisorNfc: GlobalAppStorage.shared.defaults.string(forKey: Constants.StorageKeys.supervisorNfc) ?? "")
handleLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}
}
In Background Modes the following are enabled:
• Location updates
• Background fetch
• Background processing
In Info.plist I have set the following properties:
• Privacy - Location Usage Description
• Privacy - Location When In Use Usage Description
• Privacy - Location Always and When In Use Usage Description
• and the above mentioned under the Required background modes.
Thanks in advance for your help!

Geofencing stops working after 7-8 hours. It notifies only when I open the app

I have implemented geofencing to detect the entry and exit from the region. It seems working fine when the app is in a foreground/background/terminated state initially. I am testing this functionality using GPX. When an app is terminated, I am getting entry exit notifications too. But I have observed that in many scenarios when an app is suspended or terminated for a longer period of time, Even though the user is entering and leaving the region, No notifications are triggered. When I open the app manually, I can see the entry,or exit notifications instantly.
Here is my code snippet.
class LocationService: NSObject, CLLocationManagerDelegate {
static let sharedInstance: LocationService = { LocationService()
}()
var locationManager: CLLocationManager?
var startLocation: CLLocation?
var lastLocation: CLLocation?
var delegate: LocationServiceDelegate?
var isAuthorized: ((Bool) -> Void)?
var boolSendUpdate = false
var locationTimer = Timer()
var isFirstTime:Bool!
override init() {
super.init()
self.locationManager = CLLocationManager()
guard let locationManager = self.locationManager else {
return
}
//locationManager.desiredAccuracy = kCLLocationAccuracyBest // The accuracy of the location data
locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.allowsBackgroundLocationUpdates = true// if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self){
// print("Available")
// }
//
NotificationCenter.default.addObserver(self, selector:#selector(startUpdatingLocation), name: UIApplication.didBecomeActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(stopUpdatingLocation), name: UIApplication.willTerminateNotification, object: nil)
}
func checkPermission(isAuthorized: ((Bool) -> Void)? = nil) {
guard let locationManager = self.locationManager else {
return
}
switch(CLLocationManager.authorizationStatus()) {
case .authorizedAlways,.authorizedWhenInUse:
self.startUpdatingLocation()
isAuthorized?(true)
// get the user location
case .restricted, .denied:
isAuthorized?(false)
// redirect the users to settings
popupAlert(title: NSLocalizedString("settings", comment: ""), message:go_to_settings, actionTitles: [NSLocalizedString("Cancel", comment: ""),NSLocalizedString("Settings", comment: "")], actions:[{action1 in
},{action2 in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in })
}
}, nil])
case .notDetermined:
isAuthorized?(false)
locationManager.requestWhenInUseAuthorization()
#unknown default:
isAuthorized?(false)
locationManager.requestWhenInUseAuthorization()
}
}
#objc func startUpdatingLocation() {
self.locationManager?.startUpdatingLocation()
self.locationManager?.requestAlwaysAuthorization()
}
#objc func stopUpdatingLocation() {
if !CLLocationManager.significantLocationChangeMonitoringAvailable() {
return
}
self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoringSignificantLocationChanges()
}
func setUpGeofenceing(location:CLLocation,identifier:String = "",radius:CLLocationDistance,status:enumShiftStatus) {
let geofenceRegionCenter = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let geofenceRegion = CLCircularRegion.init(center: geofenceRegionCenter, radius: radius, identifier: identifier)
geofenceRegion.notifyOnExit = true
geofenceRegion.notifyOnEntry = true
if !CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
print("Geofencing is not supported on this device!")
UIApplication.shared.windows.first?.rootViewController?.presentAlert(withTitle:"MetroOne Officer", message: "Geofencing is not supported on this device!")
return
}
if locationManager?.monitoredRegions.contains(geofenceRegion) == false {
locationManager?.startMonitoring(for: geofenceRegion)
}
}
func stopGeoFenceing(identifier: String = ""){
}
// CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard let delegate = self.delegate else {
return
}
delegate.didChangeAuthorization(status: status)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
// singleton for get last location
self.lastLocation = location
// use for real time update location
updateLocation(currentLocation: location)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// do on error
updateLocationDidFailWithError(error: error as NSError)
}
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
debugPrint("Started Monitoring for Region:::",region.description)
guard #available(iOS 14, *) else {
self.locationManager?.requestState(for:region)
return
}
}
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
debugPrint("error::\(error.localizedDescription)")
}
// Private function
private func updateLocation(currentLocation: CLLocation){
guard let delegate = self.delegate else {
return
}
delegate.tracingLocation(currentLocation: currentLocation)
}
private func updateLocationDidFailWithError(error: NSError) {
guard let delegate = self.delegate else {
return
}
delegate.tracingLocationDidFailWithError(error: error)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
switch state {
case .inside:
postApiGeoFenceEntries(type: RegionType.In.rawValue, shiftStatus: enumShiftPostStatus.CheckIn.rawValue)
case .outside:
postApiGeoFenceEntries(type: RegionType.Out.rawValue, shiftStatus: enumShiftPostStatus.CheckOut.rawValue)
case .unknown:
print("Unknown")
default:
print("Default")
}
}
}
App delegate code snippet.
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch
if launchOptions?[UIApplication.LaunchOptionsKey.location] != nil {
_ = LocationService.sharedInstance
UNUserNotificationCenter.current().delegate = self
}
return true
}
}
I have also enabled location updates in capabilities. Please let me know if I am missing something.
Thank you.

Background Fetch is not Working on Real iOS Device?

I have created an iOS application which just sends the Location Coordinates to the server after the user's login. I have also implemented the widget which takes the snapshot of the location displayed it on the widget screen and send it to the server. The application is simple. I just want to open the app or widget for a short time in the background after 20-30 mins and send the location to the server.
For this, I have implemented the Background Fetch in the app. It is working while simulating from the debugger. But won't work on the real iOS device. App Code is below.
If there is any other solution to perform such task let me know except the Push/Remote Notifications. Thanks
AppDelegate.swift
import UIKit
import UserNotifications
import Alamofire
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var myLat:Double = 0.0
var myLong:Double = 0.0
let locationManager = CLLocationManager()
var MSISDN = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(
UIApplication.backgroundFetchIntervalMinimum)
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self as? CLLocationManagerDelegate
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
return true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
myLat = locValue.latitude
myLong = locValue.longitude
print(locValue)
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if let userDefaults = UserDefaults(suiteName: "group.com.demo.spoton") {
var value1 = userDefaults.bool(forKey: "IsLogin")
if value1 == true {
print (value1)
MSISDN = userDefaults.string(forKey: "MSISDN")!
var fetchResult: UIBackgroundFetchResult!
print("i'm executing a task")
let Type = 2
let root = "https://demourl.com/locreciver.php?latitude="
let url = "\(root)\(myLat)&longitude=\(myLong)&type=\(2)&msisdn=\(MSISDN)&battery=\(1)";
Alamofire.request(url, method:.post).responseString {
response in
switch response.result {
case .success:
print(response)
completionHandler(.newData)
case .failure(let error):
print(error)
completionHandler(.failed)
}
}
return
}
else{
print("notLogin")
}
}
}// fecth function
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
}
// TodayViewController.swift //Widget
import UIKit
import NotificationCenter
import CoreLocation
import Alamofire
import Swift
import GoogleMaps
import MapKit
class TodayViewController: UIViewController, NCWidgetProviding, CLLocationManagerDelegate,MKMapViewDelegate {
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var mapImage: UIImageView!
let locationManager = CLLocationManager()
var myLat:Double = 0.0
var myLong:Double = 0.0
var MSISDN = ""
#objc func doLaunchApp(){
if let url = NSURL(string: "mainAppUrl://"){
self.extensionContext?.open(url as URL, completionHandler: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// self.extensionContext?.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded
// let url = URL(string: "mainAppUrl://")!
// self.extensionContext?.open(url, completionHandler: { (success) in
// if (!success) {
// print("error: failed to open app from Today Extension")
// }
// })
//
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(TodayViewController.doLaunchApp))
self.view.addGestureRecognizer(tapGesture)
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
myLat = locValue.latitude
myLong = locValue.longitude
}
func SendData(){
print("Sent")
takeShot()
var batteryLevel:Float = UIDevice.current.batteryLevel
let Type = 2
let root = "https://demourl.com/locreciver.php?latitude="
let url = "\(root)\(myLat)&longitude=\(myLong)&type=\(Type)&msisdn=\(MSISDN)&battery=\(batteryLevel)";
Alamofire.request(url, method:.post).responseString {
response in
switch response.result {
case .success:
print(response)
case .failure(let error):
print(error)
}
}
}
func takeShot(){
let mapSnapshotOptions = MKMapSnapshotter.Options()
// Set the region of the map that is rendered.
let location = CLLocationCoordinate2DMake(myLat, myLong) // Apple HQ
let region = MKCoordinateRegion(center: location, latitudinalMeters: 900, longitudinalMeters: 900)
mapSnapshotOptions.region = region
// Set the scale of the image. We'll just use the scale of the current device, which is 2x scale on Retina screens.
mapSnapshotOptions.scale = UIScreen.main.scale
// Set the size of the image output.
mapSnapshotOptions.size = CGSize(width: mapImage.frame.width, height: mapImage.frame.height)
// Show buildings and Points of Interest on the snapshot
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.showsPointsOfInterest = true
let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
snapShotter.start { (snapshot:MKMapSnapshotter.Snapshot?, NSError) in
let image = snapshot?.image
var annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: self.myLat, longitude: self.myLong)
annotation.title = "Your Title"
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "annotation")
let pinImage = UIImage(named: "pin")
print(pinImage)
UIGraphicsBeginImageContextWithOptions(image!.size, true, image!.scale);
image?.draw(at: CGPoint(x: 0, y: 0)) //map
pinImage!.draw(at: (snapshot?.point(for: annotation.coordinate))!)
annotationView.drawHierarchy(in: CGRect(x: snapshot!.point(for: annotation.coordinate).x, y: (snapshot?.point(for: annotation.coordinate).y)!, width: annotationView.frame.size.width-100, height: annotationView.frame.size.height-100), afterScreenUpdates: true)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// completion(image: finalImage, error: nil)
self.mapImage.image = finalImage
//self.mapImage.image = snapshot?.image
}
}
func widgetPerformUpdate(completionHandler: (#escaping (NCUpdateResult) -> Void)) {
if let userDefaults = UserDefaults(suiteName: "group.com.demo.spoton") {
var value1 = userDefaults.bool(forKey: "IsLogin")
if value1 == true {
print (value1)
MSISDN = userDefaults.string(forKey: "MSISDN")!
lblTitle.text = "Service Active"
let timer1 = Timer.scheduledTimer(withTimeInterval: 1500.0, repeats: false) { (timer) in
self.SendData()
}
let timer2 = Timer.scheduledTimer(withTimeInterval: 1500.0, repeats: true) { (timer) in
print("Looop")
self.SendData()
}
}
else {
lblTitle.text = "SpotOn Service InActive. Needs Login"
}
}
completionHandler(NCUpdateResult.newData)
}
}

Google ChromeCast iOS (Swift 3) can't play video

I need help! Once i connected the device to chromecast, it crashed right when it's about to load. I have no clue why it cause that. I followed GoogleCast for Docs and few examples and seems that it's missing something. Could you guys help me?
This my code
This is on my OnCreate
override func viewDidLoad() {
sessionManager = GCKCastContext.sharedInstance().sessionManager
sessionManager?.add(self)
castMediaController = GCKUIMediaController()
if isCastEnabled() {
playSelectedItemRemotely()
}
}
//////////////////////////////////////////////////////
// //
// Start du Google ChromeCast //
// //
//////////////////////////////////////////////////////
private func buildMediaInformation() -> GCKMediaInformation {
let metadata = GCKMediaMetadata(metadataType: GCKMediaMetadataType.generic)
metadata.setString("Title", forKey: kGCKMetadataKeyTitle)
metadata.setString("Studio", forKey: kGCKMetadataKeyStudio)
let mediaInfo = GCKMediaInformation(contentID: "streamURL",
streamType: GCKMediaStreamType.none,
contentType: "video/m3u",
metadata: metadata,
streamDuration: 60,
mediaTracks: nil,
textTrackStyle: nil,
customData: nil)
print(mediaInfo.contentID)
return mediaInfo
}
func isCastEnabled() -> Bool {
switch GCKCastContext.sharedInstance().castState {
case GCKCastState.connected:
print("cast connected")
return true
case GCKCastState.connecting:
print("cast connecting")
return true
case GCKCastState.notConnected:
print("cast notConnected")
return false
case GCKCastState.noDevicesAvailable:
print("cast noDevicesAvailable")
return false
}
}
func playSelectedItemRemotely() {
let castSession = GCKCastContext.sharedInstance().sessionManager.currentCastSession
if (castSession != nil) {
castSession?.remoteMediaClient?.loadMedia(self.buildMediaInformation(), autoplay: true)
self.dismiss(animated: true, completion: nil)
}
else {
print("no castSession!")
}
}
func sessionManager(_ sessionManager: GCKSessionManager, didStart session: GCKSession) {
playSelectedItemRemotely()
}
func sessionManager(_ sessionManager: GCKSessionManager, didResumeSession session: GCKSession) {
}
func sessionManager(_ sessionManager: GCKSessionManager, didEnd session: GCKSession, withError error: Error?) {
let castSession = GCKCastContext.sharedInstance().sessionManager.currentCastSession
castSession?.endAndStopCasting(true)
}
func sessionManager(_ sessionManager: GCKSessionManager, didFailToStart session: GCKSession, withError error: Error) {
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// playerView.player?.replaceCurrentItem(with: nil)
//
// //this stops the session manager sending callbacks to your VideoVC
// sessionManager?.remove(self)
}
And this is on my AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let castAppID = "myKey"
let options = GCKCastOptions.init(receiverApplicationID: castAppID)
GCKCastContext.setSharedInstanceWith(options)
GCKLogger.sharedInstance().delegate = self
I got it. My issue was in the Google Cast Console i had a remote receiver. Need to have a custom style receiver or media. So make sure you have that right!! Or just use a kGCKMediaDefaultReceiverApplicationID on your AppID to get the default one.

Get User Location Every 5 minutes with background modes in Swift 3

I want to ;
Get User Location Every 5 minutes with background modes in Swift 3
But my codes don't any action. I need to get and send server ,longitude , latitude , and altitude values every 5 minutes
My codes under below.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
sleep(2)
BackgroundLocationManager.instance.start()
return true
}
BackgroundLocationManager - Class
import Foundation
import CoreLocation
import UIKit
class BackgroundLocationManager :NSObject, CLLocationManagerDelegate {
static let instance = BackgroundLocationManager()
static let BACKGROUND_TIMER = 15.0 // restart location manager every 150 seconds
static let UPDATE_SERVER_INTERVAL = 60 * 5 // 5 minutes server send
let locationManager = CLLocationManager()
var timer:Timer?
var currentBgTaskId : UIBackgroundTaskIdentifier?
var lastLocationDate : NSDate = NSDate()
private override init(){
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.activityType = .other;
locationManager.distanceFilter = kCLDistanceFilterNone;
if #available(iOS 9, *){
locationManager.allowsBackgroundLocationUpdates = true
}
NotificationCenter.default.addObserver(self, selector: #selector(self.applicationEnterBackground), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
}
func applicationEnterBackground(){
// FileLogger.log("applicationEnterBackground")
start()
}
func start(){
if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways){
if #available(iOS 9, *){
locationManager.requestLocation()
} else {
locationManager.startUpdatingLocation()
}
} else {
locationManager.requestAlwaysAuthorization()
}
}
func restart (){
timer?.invalidate()
timer = nil
start()
}
private func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.restricted: break
//log("Restricted Access to location")
case CLAuthorizationStatus.denied: break
//log("User denied access to location")
case CLAuthorizationStatus.notDetermined: break
//log("Status not determined")
default:
//log("startUpdatintLocation")
if #available(iOS 9, *){
locationManager.requestLocation()
} else {
locationManager.startUpdatingLocation()
}
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if(timer==nil){
// The locations array is sorted in chronologically ascending order, so the
// last element is the most recent
guard locations.last != nil else {return}
beginNewBackgroundTask()
locationManager.stopUpdatingLocation()
let now = NSDate()
if(isItTime(now: now)){
//TODO: Every n minutes do whatever you want with the new location. Like for example sendLocationToServer(location, now:now)
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
beginNewBackgroundTask()
locationManager.stopUpdatingLocation()
}
func isItTime(now:NSDate) -> Bool {
let timePast = now.timeIntervalSince(lastLocationDate as Date)
let intervalExceeded = Int(timePast) > BackgroundLocationManager.UPDATE_SERVER_INTERVAL
return intervalExceeded;
}
func sendLocationToServer(location:CLLocation, now:NSDate){
//TODO
}
func beginNewBackgroundTask(){
var previousTaskId = currentBgTaskId;
currentBgTaskId = UIApplication.shared.beginBackgroundTask(expirationHandler: {
// FileLogger.log("task expired: ")
})
if let taskId = previousTaskId{
UIApplication.shared.endBackgroundTask(taskId)
previousTaskId = UIBackgroundTaskInvalid
}
timer = Timer.scheduledTimer(timeInterval: BackgroundLocationManager.BACKGROUND_TIMER, target: self, selector: #selector(self.restart),userInfo: nil, repeats: false)
}
}

Resources