iOS location regions firing events incorrectly since app has been built with Xcode 8 - ios

So I have an iOS application that was built with Xcode 7 up until recently. It uses iOS location regions for determining if users enter/exit regions. I simply have code in the DidDetermineState method of the CLLocationManagerDelegate that sends API calls to my backend based on the state (entered/left). It was working very well with very minimal issues up until I upgraded my build machine to Xcode 8 and made a new build. Suddenly, some users are reporting "flip flopping" where they'll be sleeping and their phone will "enter home" then "left home" all while the phone is sitting on their night stand. This never happened before upgrading to Xcode 8. Were there some location changes in Xcode 8 that I missed that I'm not accounting for?
What's strange is I cannot reproduce it. And they claim that it's working normally, but misfiring a lot. I'm looking at their logs and seeing exactly what they're describing. It'll be 3am and DidDetermineState will fire with "left home" only to "enter home" seconds or minutes later. This seems to be ~10+% of users (total rough estimation).
public override void DidDetermineState(CLLocationManager manager, CLRegionState state, CLRegion region)
{
this.HandleRegionEnterExitDebugStuff("Did Determine State = " + state, manager, region);
//Console.WriteLine("region.id = " + region.Identifier);
// This is all code that hasn't changed in a long time and worked fine when built with Xcode 7. But this event is misfiring (false positives) with Xcode 8....
string message = null;
switch (state)
{
case CLRegionState.Inside:
RegionLogic (region, manager, "Region Entered", LocationManager.Location_WebHook_Enter);
break;
case CLRegionState.Outside:
RegionLogic (region, manager, "Region Exit", LocationManager.Location_WebHook_Exit);
break;
case CLRegionState.Unknown:
message = String.Format("DidDetermineState state = CLRegionState.Unknown for region.Identifier = " + region.Identifier);
LogManager.LogMessage(
LogManager.LogType.Location,
message
);
LogManager.LogMessage(
LogManager.LogType.CriticalInfo,
message
);
break;
default:
message = String.Format("DidDetermineState state = invalid for region.Identifier = " + region.Identifier);
LogManager.LogMessage(
LogManager.LogType.Location,
message
);
LogManager.LogMessage(
LogManager.LogType.CriticalInfo,
message
);
break;
}
}
Additional information:
So far i've dug into 3 users and confirmed they're seeing "false positives" via their logs and they have the following information:
User 1: iOS 10.3.1 iPhone 6s. Location USA. Language English.
User 2: iOS 10.3.1 iPhone 6s. Location USA. Language English.
User 3: iOS 10.3.2 (beta version) iPhone 7. Location USA. Language English.
Me (cannot reproduce issue): iOS 10.3.1 iPhone 6. Location USA. Language English.
Application is built with Xamarin.iOS
Target Deployment is 9.0

Related

Network change state not getting detected in Release mode background - Xamarin.iOS

In my application, I have used Xamarin.Essentials to detect network changes in background & fire notifications based on network availability. The code works perfectly on the device & simulator during Debug. However, the Xamarin.Essentials fail to detect connectivity changes in Release mode, especially in the background. The events get triggered when the application reenters into the application (when application becomes ro foreground)
Following is the code I have used
CrossConnectivity.Current.ConnectivityChanged += Current_ConnectivityChanged;
private void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
if (_networkService.IsConnected())
{
ShowBannerNotificaiton("Internet", "Available", "data1");
}
else
{
ShowBannerNotificaiton("Internet", "Not Available", "data2");
}
}
Appreciate the solution given

iOS Location Manager - isAuthorizedForPreciseLocation doesn't seem to exist

In the LocationManager's desiredAccuracy documentation page, Apple says
If your app isn’t authorized to access precise location information (isAuthorizedForPreciseLocation is false), changes to this property’s value have no effect; the accuracy is always kCLLocationAccuracyReduced.
I can't find this attribute anywhere, and no documentation about it either. Can someone give me some insight into this, please?
Swift
if #available(iOS 14.0, *) {
if locationManager != nil {
switch locationManager!.accuracyAuthorization {
case .fullAccuracy:
print("Full Accuracy")
case .reducedAccuracy:
print("Reduced Accuracy")
#unknown default:
print("Unknown Precise Location...")
}
}
}
Desired accuracy is a new iOS 14 setting exposed to users in every app's location permission page like below.
If the user changes this to be off, this blocks beacon detections, core bluetooth scanning and nearby interaction scanning. Lat/lon location updates from CoreLocation are degraded to be similar to what you get from cell towers. Read more in my answer here

Notification not come when app is killed in vivo

I have implemented the notification code in xamarin android. I tested this code on Samsung device using android version Pie works fine,this works fine.However when
I tested on Vivo the notification does not come up when the app is killed and android version is (Pie on both).
Chinese ROMs using (Oxygen OS, MIUI etc) when the apps are swiped from the recent app tray your app gets terminated ( similar to Force Stop). And due to this every task running in the background like Services, Jobs gets killed with the app. Even High priority FCM doesn’t see the daylight in Chinese ROMs
So user needs to enable auto start in settings for app to keep background service/Job running.By default it is off.To do this in some of the devices we can use,
try this:
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
Intent intent = new Intent();
string manufacturer = Android.OS.Build.Manufacturer;
switch (manufacturer)
{
case "xiaomi":
intent.SetComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
break;
case "oppo":
intent.SetComponent(new ComponentName("com.coloros.safecenter",
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
break;
case "vivo":
intent.SetComponent(new ComponentName("com.vivo.permissionmanager",
"com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
break;
}
IList<ResolveInfo> arrayList = PackageManager.QueryIntentActivities(intent,
PackageInfoFlags.MatchDefaultOnly);
if (arrayList.Count> 0)
{
StartActivity(intent);
}
}
more info you could refer to Enable background services and Jobs (or FCM) in Chinese ROMs

Altbeacon and bootstrap always defaults to default beacon format

I have used the Alt-Beacon reference application as a starting point on how to implement bootstrap regions. The application restarts if killed but the beacon format is always being set to Alt-Beacon and not iBeacon.
Logcat on startup:
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
Bootstrap code:
beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().clear();
beaconManager
.getBeaconParsers()
.add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundBetweenScanPeriod(5000l);
beaconManager.setBackgroundScanPeriod(1000l);
beaconManager.setRegionStatePersistenceEnabled(false);
Region region = new Region("backgroundRegion",null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
BackgroundPowerSaver backgroundPowerSaver = new BackgroundPowerSaver(this);
I would expect that when the app was restarted I should see:
m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24
I am using 2.15.2 of AltBeacon in Android Studio 3.1.3 with test device of Samsung S5 Mini running Android 6.0.1
Further information: When the phone is rebooted and the USB connected I would expect to see the app start and listen for iBeacon packets. It appears to restart but is killed by the OS.
Logcat:
12-07 17:32:08.132 8359-8359/net.simplesdktest I/InstantRun: starting instant run server: is main process
12-07 17:32:08.212 8359-8359/net.simplesdktest I/BeaconManager: BeaconManager started up on pid 8359 named 'net.simplesdktest' for application package 'net.simplesdktest'. isMainProcess=true
12-07 17:32:08.357 4889-4889/? I/TaskManager:PackageInfo:
getRunningAppProcesses() - proc:net.simplesdktest, pkg:net.simplesdktest, uid:10346, pid:8359
12-07 17:32:12.822 2390-3458/? I/ActivityManager: Killing 8359:net.simplesdktest/u0a346 (adj 15): DHA:empty #21
setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"));
This one detects ibeacon format BLE beacons doesn't it?
Source
It appears that when the beacon manager is first created it adds the AltBeacon format by default. I have managed to clear this out and set iBeacon which is now being detected.

Altbeacon - Samsung Galaxy s9 not ranging beacons as expected when locked and power cable unplugged

I'm using the Altbeacon library and implementing the foreground service to allow for faster ranging. My app is designed to send a notification to the user whenever a matching beacon is ranged. The goal is that this happens no matter what, phone locked, unlocked, app open, app closed, and app cleared from task manager.
The app works as expected with a Samsung Galaxy s7 running Android 8.0. The issue I'm experiencing with the Samsung Galaxy s9 running Android 8.0, is when the power button is pressed to lock the phone. The phone no longer receives the notifications as often as it should, as if the foreground beacon scanning is being blocked.
The device sending the beacons can transmit a new beacon continuously at a 25ms rate for 12 seconds, for testing purposes, at the end of the 12 seconds it is set to repeat that process. The user should receive a new notification every 12 seconds, however the s9 may only receive 1 notification and then 5 could be missed before is sees another. The s7 will receive every single notification as expected.
The background scan rate is set to scan for 1.1 secs and wait for 10 seconds. I wish I could provide logs for the issue but when the phone is plugged in the issue doesn't occur, so I can't really pin point why the s9 would be acting this way when the s7 doesn't. I assume it has to be something with doze mode or sleep mode since when the power cord is plugged in, the s9 receives all the notifications as expected. Those are the only two phones I have been able to test so I don't know if it is also an issue with the s8.
What could be causing the s9 to not range the same as the s7 when locked by the power button? If the phone just goes to sleep on its own, it acts the same as if the power button were pressed to put it to sleep. Code snippet below.
Thanks!
mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
set_forground_notification(true);
logManager.setLogger(Loggers.verboseLogger());
logManager.setVerboseLoggingEnabled(true);
mBeaconManager.setAndroidLScanningDisabled(false); // Setting to false allows low latency scanning
mBeaconManager.setRegionStatePersistenceEnabled(false);
mBeaconManager.setBackgroundScanPeriod(1100);
mBeaconManager.setForegroundScanPeriod(1100);
mBeaconManager.setForegroundBetweenScanPeriod(2000);
mBeaconManager.setBackgroundBetweenScanPeriod(10000);
mBeaconManager.setBackgroundMode(true); // this is being set to true here so that on app termination
// or reboot when the app starts back up because of the service, the scanning period
// is set to background and not foreground
private void set_forground_notification(boolean post)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (post) {
String CHANNEL_ID = "Scanning_for_device";
CharSequence name = "Scanning_for_device";
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, android.app.NotificationManager.IMPORTANCE_HIGH);
mChannel.setShowBadge(false);
mChannel.setSound(null,null);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_foreground_logo)
.setContentTitle("Scanning for Device")
.setSound(null)
.setOnlyAlertOnce(true);
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(pendingIntent);
android.app.NotificationManager mNotificationManager =
(android.app.NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(mChannel);
// sends foreground notification and starts foreground scanning?
mBeaconManager.enableForegroundServiceScanning(mBuilder.build(), 457);
} else {
// removes foreground notification and stops foreground scanning?
mBeaconManager.disableForegroundServiceScanning();
}
}
}

Resources