I would like to implement background bluetooth scanning on IOS. When the application goes in background mode it calls TestCentralManagerDelegate which implements DiscoveredPeripheral function. It is triggered when a new bluetooth peripheral device is detected. If a new bluetooth device is detected the application read the manufacture data which is presented in Dictionary advertisementData (as argument of DiscoveredPeripheral function). The manufacture data are obtained by calling ManufactureData = advertisementData["kCBAdvDataManufacturerData"].ToString(). The discovering of the manufacture data was tested on two different iPhones 5s and 6 with the same iOS 12.1. When the application goes in background mode, I locked the screen.
In the case of iPhone 5s, I observed that ManufactureData was found each time
the DiscoveredPeripheral function is triggered. This fact is not true for iPhone 6, each time I got ManufactureData = null. It is worth mentioning that the manufacture data are received in both cases if the screen is not locked.
I do not understand why the iPhone 6 does not find ManufactureData, meanwhile the iPhone 5s does. I would accept the fact that phones have different operating systems and this implies different responses, but in my case this is not the case. I will appreciate any help for better understanding aforementioned problem.
Here is code I am using Xamarin.iOS.
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
try
{
central.StopScan();
if (peripheral == null || advertisementData == null)
{
central.ScanForPeripherals(cbuuids);
return;
}
string ManufactureData;
if (advertisementData.ContainsKey(new NSString("kCBAdvDataManufacturerData")))
{
ManufactureData = advertisementData["kCBAdvDataManufacturerData"].ToString();
}
else
{
ManufactureData = null;
CrossLocalNotifications.Current.Show("no advertising data", "no advertising data", 10);
central.ScanForPeripherals(cbuuids);
return;
}
central.ScanForPeripherals(cbuuids);
}
catch
{
central.ScanForPeripherals(cbuuids);
}
}
Related
I want to use CMSensorRecorder to continuously collect the Accelerometer data, also if user didn't open my app on watch\phone.
What I want to do is - "whenever possible" (i.e. watch is awake and I can execute code), do the following:
call recordAccelerometerForDuration to tell watch to keep collecting data for as long as possible
call accelerometerDataFromDate to get data collected so far (or from last time I got the data)
My question is - how to implement the "whenever possible", i.e. how can I cause my watch application to wake up and execute these apis whenever the watch itself wakes up ?
CMSensorRecorder- to recored data continuously use ExtentionDelegate to triger CMSensorRecorder to invoke start recording and reading data.
func applicationDidBecomeActive() {
print("Active")
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
AccelorometerDataReader.sharedReader.sessionEndDate = Date()
AccelorometerDataReader.sharedReader.getRecordedData()
}
func applicationWillResignActive() {
// Sent when the application is about to move from 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 application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, etc.
print("inactive")
AccelorometerDataReader.sharedReader.startReadingAccelorometerData()
AccelorometerDataReader.sharedReader.sessionStartDate = Date()
}
//AccelorometerReaderCode
func startReadingAccelorometerData()
{
if CMSensorRecorder.isAccelerometerRecordingAvailable()
{
if CMSensorRecorder.isAuthorizedForRecording()
{
print("Authorized.......")
DispatchQueue.global(qos: .background).async
{
self.recorder?.recordAccelerometer(forDuration: 3 * 60) // Record for 3 minutes
}
}
else
{
print("not authorized")
}
}
else
{
print("NOt available for recording")
}
}
func getRecordedData()
{
DispatchQueue.global(qos: .background).async
{
if self.sessionStartDate < self.sessionEndDate
{
if let list = self.recorder?.accelerometerData(from: self.sessionStartDate, to:self.sessionEndDate)
{
for record in list
{
let data = record as! CMRecordedAccelerometerData
print("x: \(data.acceleration.x) y: \(data.acceleration.y) z: \(data.acceleration.z) time :\(data.startDate.getFormattedDate())")
}
}
}
}
}
}
It doesn't seem you can. I have tried the following but none of these really work.
Register for backgroundApplicationRefresh (watchOS 3) and make sure the app is saved to the Dock. Dock apps can rely on getting one call an hour to update themselves.
On completion of the period query for the accelerometer data and archive the result to file and then transfer the file to the iOS companion app. The file transfer will occur in the background independent of the watch kit app assuming you get enough CPU time to write the accelerometer data to file.
Try using ProcessInfo API to keep the process running.
To date the only success I have had is in running an async thread to extract the data and keeping the watch kit app active by tapping on the screen each time the screen blanks.
Hope this helps and please post any better solution you find.
I'm working on an OS X application that displays custom windows on all available spaces of all the connected displays.
I can get an array of the available display objects by calling [NSScreen screens].
What I'm currently missing is a way of telling if the user connects a display to or disconnects a screen from their system.
I have searched the Cocoa documentation for notifications that deal with a scenario like that without much luck, and I refuse to believe that there isn't some sort of system notification that gets posted when changing the number of displays connected to the system.
Any suggestions on how to solve this problem?
There are several ways to achieve that:
You could implement applicationDidChangeScreenParameters: in your app delegate (the method is part of the NSApplicationDelegateProtocol).
Another way is to listen for the NSApplicationDidChangeScreenParametersNotification sent by the default notification center [NSNotificationCenter defaultCenter].
Whenever your delegate method is called or you receive the notification, you can iterate over [NSScreen screens] and see if a display got connected or removed (you have to maintain a display list you can check against at program launch).
A non-Cocoa approach would be via Core Graphics Display services:
You have to implement a reconfiguration function and register it with CGDisplayRegisterReconfigurationCallback(CGDisplayReconfigurationCallBack cb, void* obj);
In your reconfiguration function you can query the state of the affected display. E.g.:
void DisplayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void* userInfo)
{
if(display == someDisplayYouAreInterestedIn)
{
if(flags & kCGDisplaySetModeFlag)
{
...
}
if(flags & kCGDisplayRemoveFlag)
{
...
}
if(flags & kCGDisplayDisabledFlag)
{
...
}
}
if(flags & kCGDisplaySetModeFlag || flags & kCGDisplayDisabledFlag || flags & kCGDisplayRemoveFlag)
{
...
}
}
in swift 3.0:
let nc = NotificationCenter.default
nc.addObserver(self,
selector: #selector(screenDidChange),
name: NSNotification.Name.NSApplicationDidChangeScreenParameters,
object: nil)
NC call back:
final func screenDidChange(notification: NSNotification){
let userInfo = notification.userInfo
print(userInfo)
}
I am developing a network monitor app that runs in background as a service. Is it possible to get a notification/call when the screen is turned on or off?
It exists in Android by using the following code:
private void registerScreenOnOffReceiver()
{
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenOnOffReceiver, filter);
}
screenOnOffReceiver is then called when screen is turned on/off. Is there a similar solution for iOS?
Edit:
The best I've found so far is UIApplicationProtectedDataWillBecomeUnavailable ( Detect if iPhone screen is on/off ) but it require the user to enable Data Protection (password protection) on the device.
You can use Darwin notifications, to listen for the events. I'm not 100% sure, but it looks to me, from running on a jailbroken iOS 5.0.1 iPhone 4, that one of these events might be what you need:
com.apple.iokit.hid.displayStatus
com.apple.springboard.hasBlankedScreen
com.apple.springboard.lockstate
Update: also, the following notification is posted when the phone locks (but not when it unlocks):
com.apple.springboard.lockcomplete
To use this, register for the event like this (this registers for just one event, but if that doesn't work for you, try the others):
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.iokit.hid.displayStatus"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
where displayStatusChanged is your event callback:
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
NSLog(#"event received!");
// you might try inspecting the `userInfo` dictionary, to see
// if it contains any useful info
if (userInfo != nil) {
CFShow(userInfo);
}
}
If you really want this code to run in the background as a service, and you're jailbroken, I would recommend looking into iOS Launch Daemons. As opposed to an app that you simply let run in the background, a launch daemon can start automatically after a reboot, and you don't have to worry about iOS rules for apps running tasks in the background.
Let us know how this works!
Using the lower-level notify API you can query the lockstate when a notification is received:
#import <notify.h>
int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_token, dispatch_get_main_queue(), ^(int token) {
uint64_t state = UINT64_MAX;
notify_get_state(token, &state);
NSLog(#"com.apple.springboard.lockstate = %llu", state);
});
Of course your app will have to start a UIBackgroundTask in order to get the notifications, which limits the usefulness of this technique due to the limited runtime allowed by iOS.
While iPhone screen is locked appdelegate method
"- (void)applicationWillResignActive:(UIApplication *)application"
will be called you can check that. Hope it may help you.
How to detect if a sensor is available on a Windows 8 device? My app needs GPS to work properly, so I need a way to detect if it is available on the device it is running on.
Here are some available sensors for Windows 8 devices.
you can check if they are available by GetDefault() method. It returns 'null' if the sensor is not available.
if(Accelerometer.GetDefault() != null)
{
// your code
}
if (Compass.GetDefault() != null)
{
// your code
}
if (Gyrometer.GetDefault() != null)
{
// your code
}
you can check the LocationStatus property of the Geolocator object... if it is NotAvailable or Disabled you are out of luck...
I want to check if an iOS device is currently connected to a computer (Wifi And Cable)
I tried to google it and looked into the Apple Developer site, but couldn't seem to find anything related to my question.
If the device is physically connected you can check the battery state, like so:
UIDeviceBatteryState myBatteryState = [UIDevice currentDevice].myBatteryState;
if (myBatteryState == UIDeviceBatteryStateCharging) {
//code
} else if (myBatteryState == UIDeviceBatteryStateFull) {
//code
}