我正在使用Xamarin.Forms开发适用于Android和iOS的应用程序。该应用程序需要从Firestore中提取社区列表,如果用户启用了它,则可以在每个社区中订阅警报。
在Android中,我做了一个粘性应用程序,该应用程序在启动时会启动,然后在OnStartCommand函数中,该服务使用AddSnapshotListener(this)订阅每个社区。函数(下面是示例代码)。一切正常,但是现在我需要在iOS中做同样的事情。
我进行了研究,并尝试学习iOS中的后台系统。在Microsoft的文档中,我发现iOS具有称为“提取”的后台模式,据我了解,iOSD中每隔X秒/分钟调用一次AppDelegate中的一个函数。但是,除了我将应用程序预订为类的Android之外,我无法想象如何在系统调用的函数中使用AddSnapshotListener。
那么,我该如何在iOS的后台监听Firestore集合中的更改?
一种方法可能是使用Background Fetch并调用.GetCollection(“ community1”)并检查新文档,但是问题是用户可以添加多个社区,然后可能是一个很大的互联网数据问题(另外,我认为最多需要30秒才能从Fetch Function进行回调,否则iOS可能会终止该应用。)
这是我在Android中使用的代码(我简化了代码):
DroidCommonFunctions.cs
public void UpdateCommunityAlertListener(List<LocalCommunity> Communities)
{
if (MainActivity.ThisAct == null || Communities == null)
return;
try
{
MainActivity.ThisAct.StopService(new Intent(MainActivity.ThisAct, typeof(BackgroundTask.CommunityAlertsListener)));
if (Communities.Count == 0)
return;
Intent serviceIntent = new Intent(MainActivity.ThisAct, typeof(BackgroundTask.CommunityAlertsListener));
serviceIntent.PutExtra("CommunityLength", Communities.Count);
for (int i = 0; i < Communities.Count; i++)
{
serviceIntent.PutExtra("CommunityId" + i, Communities[i].Id);
serviceIntent.PutExtra("CommunityName" + i, Communities[i].Alias);
}
MainActivity.ThisAct.StartService(serviceIntent);
} catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("ACAL: " + ex.Message);
}
}
DroidBackgroundTask.cs
[Service]
public class CommunityAlertsListener : Service, IEventListener
{
public class CommunityRegistration
{
public string Name { get; set; } = "";
public IListenerRegistration Registration { get; set; }
}
public Dictionary<string, CommunityRegistration> CommunityDic = new Dictionary<string, CommunityRegistration>();
public override void OnCreate()
{
base.OnCreate();
StartServiceWithNotification(); //Create Android Notification
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if(FirestoreService.Instance == null)
{
StopSelf();
return StartCommandResult.RedeliverIntent;
}
int comLength = intent.GetIntExtra("CommunityLength", 0);
for(int i = 0; i < comLength; i++)
{
string comId = intent.GetStringExtra("CommunityId" + i);
string comName = intent.GetStringExtra("CommunityName" + i);
if (string.IsNullOrWhiteSpace(comId) || string.IsNullOrWhiteSpace(comName) || CommunityDic.ContainsKey(comId))
continue;
IListenerRegistration comReg = FirestoreService.Instance.Collection("communities").Document(comId).Collection("security_events").AddSnapshotListener(this);
CommunityDic.Add(comId, new CommunityRegistration()
{
Name = comName,
Registration = comReg
});
}
if (comLength == 0 || CommunityDic.Count == 0)
StopSelf();
else
System.Diagnostics.Debug.WriteLine("CommunityAlertsListener STARTED!");
return StartCommandResult.RedeliverIntent;
}
public void OnEvent(Java.Lang.Object value, FirebaseFirestoreException error)
{
if (error != null)
{
System.Diagnostics.Debug.WriteLine("Listen failed: " + error.Message);
return;
}
try
{
QuerySnapshot snapshot = (QuerySnapshot)value;
if (snapshot.Query == null || snapshot.Query.GetType() != typeof(CollectionReference))
return;
NotifySnapshot(snapshot); //Create Android Notification
}
catch
{
System.Diagnostics.Debug.WriteLine("Listen Failed: " + error.Message);
}
}
public override void OnDestroy()
{
foreach(CommunityRegistration comReg in CommunityDic.Values)
{
try
{
if (comReg != null && comReg.Registration != null)
comReg.Registration.Remove();
} catch
{
if (comReg != null)
System.Diagnostics.Debug.WriteLine(string.Format("{0} wasn't being removed", comReg.Name));
else
System.Diagnostics.Debug.WriteLine("A community wasn't being removed");
}
}
System.Diagnostics.Debug.WriteLine("CommunityAlertsListener STOPPED!");
base.OnDestroy();
}
}