В моем приложении xamarin android AltBeacon DidEnterRegion не срабатывает, если для атрибута MainLauncher установлено значение false для MainActivity. Поскольку у меня есть SplashActivity для отображения экрана spla sh, я должен сделать SplashActivity своим MainLauncher. Я использую службу переднего плана для обнаружения iBeacon.
Код класса моего приложения:
namespace AltBeaconLibrarySample.Droid
{
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application, IBootstrapNotifier
{
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
Region _generalRegion;
public bool IsStartedRanging { get; set; }
string foregroundServiceChannelId = "foregroundService";
string channelName = "ForegroundService";
int pendingIntentId = 1;
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public void DidDetermineStateForRegion(int p0, Region p1)
{
}
public void DidEnterRegion(Region p0)
{
var beaconService = Xamarin.Forms.DependencyService.Get<IAltBeaconService>();
if (!IsStartedRanging)
{
beaconService.StartRanging();
IsStartedRanging = true;
}
}
public void DidExitRegion(Region p0)
{
var beaconService = Xamarin.Forms.DependencyService.Get<IAltBeaconService>();
if (IsStartedRanging)
{
beaconService.StopRanging();
IsStartedRanging = false;
}
beaconService.DidExitRegion();
}
public override void OnCreate()
{
base.OnCreate();
CrossCurrentActivity.Current.Init(this);
BeaconManager bm = BeaconManager.GetInstanceForApplication(this);
CreateNotificationChannel();
bm.EnableForegroundServiceScanning(GetForegroundServiceNotification(), 456);
bm.SetEnableScheduledScanJobs(false);
_generalRegion = new Org.Altbeacon.Beacon.Region/* AltBeaconOrg.BoundBeacon.Region*/("myEmptyBeaconId", Identifier.Parse("23A01AF0-232A-4518-9C0E-323FB773F5EF"), null, null);
regionBootstrap = new RegionBootstrap(this, _generalRegion);
backgroundPowerSaver = new BackgroundPowerSaver(this);
}
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var channelDescription = "Foreground Sertrvice";
var channel = new NotificationChannel(foregroundServiceChannelId, channelName, NotificationImportance.High)
{
Description = channelDescription
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
public Notification GetForegroundServiceNotification()
{
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, foregroundServiceChannelId);
builder.SetSmallIcon(Resource.Drawable.xamagonBlue);
builder.SetContentTitle("Scanning for Beacons");
Intent intent = new Intent(this, typeof(MainActivity));
PendingIntent pendingIntent = PendingIntent.GetActivity(this, pendingIntentId, intent, PendingIntentFlags.UpdateCurrent);
builder.SetContentIntent(pendingIntent);
return builder.Build();
}
}
}
Код класса SplashActivity:
namespace AltBeaconLibrarySample.Droid
{
[Activity(Label = "AltBeaconLibrarySample.Droid",
Icon = "@mipmap/icon",
Theme = "@style/MainTheme",
MainLauncher = true,
NoHistory = true,
LaunchMode = Android.Content.PM.LaunchMode.SingleInstance,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class SplashActivity : Activity
{
static readonly string TAG = "X:" + typeof(SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
}
// Launches the startup task
protected override void OnResume()
{
base.OnResume();
Task startupWork = new Task(() => { SimulateStartup(); });
startupWork.Start();
}
// Simulates background work that happens behind the splash screen
async void SimulateStartup()
{
Log.Debug(TAG, "Performing some startup work that takes a bit of time.");
await Task.Delay(50); // Simulate a bit of startup work.
Log.Debug(TAG, "Startup work is finished - starting MainActivity.");
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
}
}
Android манифест:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.AltBeaconLibrarySample" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:label="AltBeaconLibrarySample.Android">
<service android:enabled="true" android:exported="false" android:isolatedProcess="false" android:label="Beacon" android:name="org.altbeacon.beacon.service.BeaconService"></service>
<service android:enabled="true" android:exported="false" android:name="org.altbeacon.beacon.BeaconIntentProcessor"></service>
<receiver android:name="org.altbeacon.beacon.startup.StartupBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
</application>
</manifest>
Код класса MainActivity:
namespace AltBeaconLibrarySample.Droid
{
[Activity(Label = "AltBeaconLibrarySample.Droid",
Icon = "@mipmap/icon",
Theme = "@style/MainTheme",
MainLauncher = false,
LaunchMode = Android.Content.PM.LaunchMode.SingleInstance,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IBeaconConsumer
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
CrossCurrentActivity.Current.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
#region IBeaconConsumer Implementation
public void OnBeaconServiceConnect()
{
}
#endregion
protected override void OnDestroy()
{
base.OnDestroy();
DependencyService.Get<IAltBeaconService>().OnDestroy();
}
protected override void OnResume()
{
base.OnResume();
}
protected override void OnPause()
{
base.OnPause();
}
}
}
Фрагмент кода BeaconManager:
BeaconManager bm = BeaconManager.GetInstanceForApplication(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity);
var iBeaconParser = new BeaconParser();
// Estimote > 2013
iBeaconParser.SetBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
bm.BeaconParsers.Add(iBeaconParser);
bm.BackgroundMode = false;
bm.Bind((IBeaconConsumer)Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity);