Some background information
I'm using the silentPush feature (didReceiveRemoteNotification) to keep the iOS app synced with other platforms and my backend.
So just to be sure, that the user enabled Background Refresh in his iOS settings, I'm checking the devices settings with the following code:
// Check Background Refresh
switch UIApplication.shared.backgroundRefreshStatus {
case .available:
// iOS background refresh is enabled in iOS settings
// -> No need to ask user for permission
break
case .denied:
// iOS background refresh is disabled in iOS settings
// here is my code to notify user to enable his background refresh iOS settings
break
}
According to the Apple documentation (https://developer.apple.com/documentation/uikit/uiapplication/1622994-backgroundrefreshstatus) there is a property backgroundRefreshStatus, which indicates, if the user has enabled the background services -> This is exactly the code I implemented above.
This property reflects whether the app can be launched into the background to handle background behaviors, such as processing background location updates and performing background fetches. If your app relies on being launched into the background to perform tasks, you can use the value of this property to determine if doing so is possible and to warn the user if it is not. Do not warn the user if the value of this property is set to restricted; a restricted user does not have the ability to enable multitasking for the app.
The following phrase is now interesting in my case
you can use the value of this property to determine if doing so is possible and to warn the user if it is not
I had a look into the iOS background refresh system settings and found 3 possible values, which the user can set:
Aus (Off)
WLAN (WiFi)
WLAN & Mobile Daten (WiFi & Cellular / Mobile Data)
Now my question:
I would like to ask the user for background service permission, if the settings are either on off or only on Wifi (see red rectangle). According to Apples documentation, there is only the possibility to check the general settings -> either on or off. Is there any possibility to check it like I mentioned it on the screenshot?
Related
Hi I am looking into an app which is written in Xamarin iOS. The feature I am trying to implement is
GPS must be enabled when app is running, if gps is not enabled prompt the user to enable. If the answer is yes enable the gps and continue otherwise exit app.
I am really new Xamarin and mobile development in general. After research i have found this link which shows the lifecycle of Xamarin iOS app.
Xamarin Lifecycle
The question I have is
1) Will I be able to show an alert to user from App Delegate to enable GPS when app returns from background or launched in the overrides (See link)
2) If a dialog is not possible from app delegate will it be better to create a new screen and show the dialog to enable gps instead of adding gps check in all screens.
3) Is this the correct way of checking if GPS is enabled
e.g., when app returns from background
public override void WillEnterForeground(UIApplication application)
{
Console.WriteLine("App will enter foreground");
if(CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
}
}
Welcome #Abe you are on the right path!
Yes, you will be. You just have to place it in the overrides as you mentioned.
You can place the check in the AppDelegate, but it may not be the best thing to do. You might want to just place it in the Appear override of your page.
Yes using AppDelegate lifecycle overrides, is one way of checking for GPS if you need the it when your app is in the background.
Tips:
If you are using Xamarin Native, inside the ViewController, you could instead use the ViewDidLoad override to perform the check for GPS
You could instead just also just look into the Xamarin Essentials examples for a simplified way of dealing with GPS
Some background
I am currently writing a UI Test for a settings pane, and click on buttons to enable certain permissions such as push notifications and location services.
However, if the alert for the permission has been displayed before (regardless of the user allowing or denying access to the permission), the alert will not display again, and will just take the user to the settings app. Unfortunately, these settings do not reset, meaning the first time I run the UI tests, alerts will show; and on all subsequent UI test runs, the buttons will take me to the settings app unless I reset the device before the tests begin.
My issue
Thus, my test needs to know if the app went into the background, and attempt to foreground it to continue the testing:
if app.state == background {
foregroundApp()
}
// continue with other tests
Is there any way to determine if the app is in the background?
What I tried
I researched methods to determine the state of the application (running/background/etc) from a UI test, and was not able to find much. I tried to check whether certain elements exist:
if (app.navigationBars.element.exists) ...
but this gives me runtime errors[1] if the user is taken to the settings page because the app under test is in the background, and the test cannot lookup the navigationBars (or other elements).
I tried using some of the methods from Facebook's private headers for XCUIApplication() and XCUIElement().
XCUIApplication().state always returns 3 no matter what state the app is currently in, and any attempts to call XCUIApplication().resolve() to foreground the app give me the same errors as before[1]
I tried to rewrite the logic to foreground the app before resuming the tests, but methods such as XCUIApplication().launch() kill the app before restarting, which I cannot do. Only siri service seems to work for me, but I cannot access the siri service through the corporate proxy, and modifying proxy permissions is not possible.
Is there any other way to check the app state?
Errors
[1] This error is printed every time I try to do something involving state. I do not call snapshotView anywhere, and thus the suggestion to use afterScreenUpdates is useless.
Failure to get snapshot within 15.0s
Cannot snapshot view (<UIKeyboardImpl: 0x7febcc75d000; frame = (0 0;
414 226); layer = <CALayer: 0x608000625720>>) with
afterScreenUpdates:NO, because the view is not in a window. Use
afterScreenUpdates:YES.`
tl;dr
I need to check whether the app I am UI testing has entered the background (i.e. user pressed the home button). Checking for existence of particular elements such as navigation bars doesn't work, neither do most methods from Facebook's private headers for XCUIApplication/XCUIElement. Foregrounding the app also causes issues, and relaunching the app is not an option; neither is siri service.
You can do this in Swift 4, using XCUIApplication.state, which will give you information about the state of the app - whether it's in the foreground or background etc. however, it's not possible to find this information in Swift 3 and below. Essentially, UI testing in Swift 3 doesn't support leaving the app.
I am currently using the Xamarin geolocation plugin found here:
https://github.com/jamesmontemagno/GeolocatorPlugin
To perform location services in an app I am building using Xamarin Forms (PCL).
I believe I have added in the relevant permission settings to allow for this.
The GPS works great while the app is active and locked (but with app in the foreground). However when the app is pushed to the background on iOS by clicking the "home" button, it still tracks the user and highlights the "App is Using Your Location" message as I would expect, however after a certain amount of time between 30-40 minutes, this message disappears, and the GPS appears to stop tracking the user until they bring the app back to the foreground.
Once the app has been brought to the foreground, it can be backgrounded once again for another 30-40 minutes to repeat the cycle.
I have ensured that the locator object allows background updates:
public static Plugin.Geolocator.Abstractions.IGeolocator locator;
locator = CrossGeolocator.Current;
locator.AllowsBackgroundUpdates = true;
locator.DesiredAccuracy = 20;
A call to .PausesLocationUpdatesAutomatically shows that this is false (which I believe is the default).
Edit
I have the following keys to info.plist:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
And enabled background location updates:
However I have not enabled background fetching as Girish has in the answers, is this something I need to do?
Please check whether you have enabled the background mode for location update.
I want to develop an app that detecting the user's moving way (walking, cycling, driving etc...) and send a specific UILocalNotification for each activity type.
My question is: is it possible to detect it on the background (when the app is completely closed) without draining the device's battery? What will be the best way to do it?
Thank you!
There is coprocessor m7(+) in iPhones upper 5s.
It gives you possibility to get device motion.
Just
import CoreMotion
in your file.
Create a CMMotionActivityManager object:
let motionActivityManager = CMMotionActivityManager()
Check if it`s available on your device:
motionActivityManager.isActivityAvailable()
Use this method:
motionActivityManager.startActivityUpdates(to: OperationQueue.main) { (activity) in
if (activity?.automotive)! {
print("User using car")
}
if (activity?.cycling)! {
print("User is cycling")
}
if (activity?.running)! {
print("User is running")
}
if (activity?.walking)! {
print("User is walking")
}
if (activity?.stationary)! {
print("User is standing")
}
if (activity?.unknown)! {
print("Unknown activity")
}
}
It would return you types of user activity.
Regarding the user activity which can be handled in background tasks are the below once which does not mention about (walking, cycling,driving etc...)
Implementing Long-Running Background Tasks
For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that record audio content while in the background.
Apps that keep users informed of their location at all times, such as
a navigation app Apps that support Voice over Internet Protocol
(VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
Yes it´s possible to do that!
If your iOS app must keep monitoring location even while it’s in the
background, use the standard location service and specify the location
value of the UIBackgroundModes key to continue running in the
background and receiving location updates. (In this situation, you
should also make sure the location manager’s
pausesLocationUpdatesAutomatically property is set to YES to help
conserve power.) Examples of apps that might need this type of
location updating are fitness or turn-by-turn navigation apps.
Read more here.
Is it possible that my iOS app can auto-restart, each and every time the user accesses their home screen? This is for a jailbroken device -- the app is not destined for the App store.
In general, how can I make my app restart given specific user actions outside the app?
Accelerometer
If all you want to do is make your app run when you encounter certain accelerometer conditions, you can use Activator for that. Activator is a great app, by Ryan Petrich, available on Cydia for free. It lets you configure your device to run any app (or toggle) whenever a certain user action is taken. That could be a home button press, power/lock button press, or accelerometer shake.
If a basic shake isn't what you want, or you are building an app to give to many users, and don't want them to have to setup Activator themselves, then you probably need to write some code yourself.
For example, you could write a Launch Daemon, in addition to your main UI app, and have the launch daemon monitor the accelerometer.
When you detect the specific kind of motion you're interested in, you can launch your UI app with the open command. If this is just for your own use, just download the open package from Cydia. If this is for release to others, make sure your app depends on open to ensure that it's installed. For example, if packaging in a Debian .deb package, the DEBIAN/control file might have this:
Depends: open
to make sure users installing your app will also automatically get open, which your app needs.
Unlock
Your other problem concerns launching the app when the user unlocks the phone. Again, I would use your Launch Daemon to listen for this condition. On iOS 5, I see this notification when I unlock the phone:
Notification intercepted: com.apple.springboard.lockstate
(I detected this by running the notificationWatcher utility from the command line, while SSH'd into my phone. NotificationWatcher is also available from Cydia, as part of Erica Sadun's Erica Utilities package)
So, I would have your launch daemon register for Darwin notifications for "com.apple.springboard.lockstate". Something like this:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
self, // observer: can be NULL if callback doesn't need self
onLockStateChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
where the callback function is here:
static void onLockStateChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
// if you need access to member data (ivars):
MyLaunchDaemon* this = (MyLaunchDaemon*)observer;
//if (userInfo != nil) {
// CFShow(userInfo);
//}
NSDictionary* info = (NSDictionary*)userInfo;
// I'm not sure if the userInfo object has any useful
// description for the lock state event
if (/* unlocked */) {
// force app to open, or resume from the background
system("/usr/bin/open com.mycompany.MyAppName");
}
}
I see this same notification when the screen is locked, or unlocked, so you may need to have the launch daemon keep track of the locked/unlocked state, or inspect the userInfo object to see if that tells you whether this is a lock or unlock event. I'm sure there's other ways, too.
Update: if you want help sorting out whether the notification occurs when the screen is locked or unlocked, you can see my Update 2 in this other SO answer. notify_get_state() can be used to determine whether the event is an on, or off, event.
Set the value of UIApplicationExitsOnSuspend to YES in your app's Info.plist file.
UIApplicationExitsOnSuspend (Boolean - iOS) specifies that the app
should be terminated rather than moved to the background when it is
quit. Apps linked against iOS SDK 4.0 or later can include this key
and set its value to YES to prevent being automatically opted-in to
background execution and app suspension.