0

[预期行为:专门针对 iOS 15。iOS 14 或更低版本可以正常工作]

我有一个 Xamarin.Forms iOS 应用程序,我在其中监视和测距 BLE 信标。目标是处于前台、后台或终止状态时,当我进入一个区域时,应调用 EnteredRegion() 方法,并且 DidRangeBeacons() 应该开始被触发,每秒触发一次,并且永远不会停止。当我离开区域时,应该调用 ExitRegion() 并且 DidRangeBeacons 应该停止被解雇。如果我关闭应用程序/终止应用程序,走出该区域并再次走进去,应用程序应该调用 EnteredRegion 方法并且 DidRangeBeacons() 应该开始被调用,并且只要手机在范围内,这个方法 (DidRangeBeacons) 就永远不会停止的信标。

[当前功能:始终提供位置许可]

目前,当应用程序完全关闭/杀死并且我走进该区域时, EnteredRegion 方法将执行并且 DidRange 开始被调用。它执行几秒钟并在显示关闭时停止。当显示屏再次打开时,它再次开始调用。有时,它会执行一两分钟然后再次停止。只有当显示器打开时它才会重新开始。

如果我再次解锁屏幕并浏览手机,DidRangeBeacons 将停止执行。如果再次锁定手机并打开显示屏,DidRangeBeacons 将再次开始执行。

[代码]

public class AppDelegate : UIResponder, IUIApplicationDelegate
{

    [Export("window")]
    public UIWindow Window { get; set; }

    [Export("application:didFinishLaunchingWithOptions:")]
    public bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        // Override point for customization after application launch.
        // If not required for your application you can safely delete this method

        var bt = new BTManager();

        return true;
    }

    // UISceneSession Lifecycle

    [Export("application:configurationForConnectingSceneSession:options:")]
    public UISceneConfiguration GetConfiguration(UIApplication application, UISceneSession connectingSceneSession, UISceneConnectionOptions options)
    {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration.Create("Default Configuration", connectingSceneSession.Role);
    }

    [Export("application:didDiscardSceneSessions:")]
    public void DidDiscardSceneSessions(UIApplication application, NSSet<UISceneSession> sceneSessions)
    {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after `FinishedLaunching`.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
}



public class BTManager : CLLocationManagerDelegate
{
    UNUserNotificationCenter center =  UNUserNotificationCenter.Current;
    UNMutableNotificationContent content = new UNMutableNotificationContent();
    AppleLocalNotificationManager notifcationmanager = new AppleLocalNotificationManager();

    CLLocationManager locationmanager;
    CLBeaconRegion region;

    public BTManager()
    {
        UNUserNotificationCenter.Current.RequestAuthorization(
            UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
            (approved, error) => { }
          );
        UNUserNotificationCenter.Current.Delegate = new AppleLocalNotificationManager();


        locationmanager = new CLLocationManager();
        locationmanager.Delegate = this;

        locationmanager.RequestAlwaysAuthorization();

        region = new CLBeaconRegion(new NSUuid("3ABFAA22-5624-11EA-8E2D-0242AC130003"), 0, 109,, "Region 1");

        region.NotifyOnEntry = true;
        region.NotifyOnExit = true;
        region.NotifyEntryStateOnDisplay = true;

    }


    public override void DidChangeAuthorization(CLLocationManager manager)
    {
        if (manager.AuthorizationStatus == CLAuthorizationStatus.AuthorizedAlways ||
             manager.AuthorizationStatus == CLAuthorizationStatus.AuthorizedWhenInUse ||
             manager.AuthorizationStatus == CLAuthorizationStatus.Authorized)
        {

            locationmanager.StartMonitoring(region);
            locationmanager.StartRangingBeacons(region);
            notifcationmanager.Send("Started monitoring from auth changed", "...", "0021");
        }
    }

    public override void DidDetermineState(CLLocationManager manager, CLRegionState state, CLRegion region)
    {
        if (state == CLRegionState.Inside)
        {
            var reg = region as CLBeaconRegion;
            
            notifcationmanager.Send("Inside State: ", reg.Uuid.ToString(), "1121");

        }
        else if (state == CLRegionState.Outside)
        {
            var reg = region as CLBeaconRegion;
            
            notifcationmanager.Send("Outside state: ", reg.Uuid.ToString(), "1151");

        }
        else
        {
            notifcationmanager.Send("Unknown state", "...", "131");
        }
    }

    public override void RegionEntered(CLLocationManager manager, CLRegion region)
    {
        var reg = region as CLBeaconRegion;
        if (reg != null)
        {
            notifcationmanager.Send("Entered Region", "...", "111");
        }

    }

    public override void RegionLeft(CLLocationManager manager, CLRegion region)
    {
        var reg = region as CLBeaconRegion;
        if (reg != null)
        {
            notifcationmanager.Send("Left Region", "...", "111");
        }
    }

    public override void DidRangeBeacons(CLLocationManager manager, CLBeacon[] beacons, CLBeaconRegion region)
    {
        notifcationmanager.Send("Ranged Beacons", "...", "121");
    }

   
}






public class AppleLocalNotificationManager : UNUserNotificationCenterDelegate
{
    public void Send(string title,string message,string id)
    {
        
        var content = new UNMutableNotificationContent
        {
            Title = title,
            Body = message,
            Sound = UNNotificationSound.Default,
           
        };
        UNNotificationRequest request = UNNotificationRequest.FromIdentifier(
          id,
          content,
          trigger: null
        );
        UNUserNotificationCenter.Current.AddNotificationRequest(
          request,
          error =>
          {
              
          }
        );
    }
   
    public override void WillPresentNotification(
      UNUserNotificationCenter center,
      UNNotification notification,
      Action<UNNotificationPresentationOptions> completionHandler
    )
    {
        completionHandler(UNNotificationPresentationOptions.Alert);
    }
    
}

当用户在范围内时,我希望 DidRangeBeacons 始终在前台、后台和终止状态下执行。任何建议如何相应地解决它?

4

1 回答 1

1

这就是 iOS 上测距的设计方式——每当您收到信标区域进入/退出事件、应用程序进入前台或后台,或者(通过适当的配置)屏幕打开时,您只会获得几秒钟的测距时间.

可以通过后台任务和其他技巧来延长此测距时间。在此处查看我的博客文章。我不是 Xamarin 专家,因此我无法给出在 Xamarin 上设置后台任务以扩展测距的具体说明。但是博客文章中描述的相同技术将适用。

编辑:这是一个相关的答案,更详细地描述了如何在 iOS 的后台设置无限范围。同样,这些说明适用于原生 iOS 代码。使用 Xamarin 之类的抽象层执行这些技巧很困难,因为它们的设计旨在跨平台工作,并且不容易让您进行具体的平台特定配置。

于 2021-09-24T16:55:48.177 回答