How can I test the background scan and launch the application in background with iBeacon-Android? - ibeacon

I am using the pro library.
But I just found doc for free library
I cannot find any doc for pro version.
Also, I don't know how to implement the background mode even using the pro sample.
Here are the steps:
Build the pro sample project
start the iBeacon source(using iPad) and it can be detected
start the application and then press home button the make it in
background
Turn off the iBeacon source
Turn on the iBeacon source
However, more than 5 minutes, the application does not launch
So, can anyone verify the step I did?
How can I test the background mode more easily?
Also, for the BootstrapNotifier, is it just work only first time when the device reboot?
After that, even I put application in background, the application will not launch when it detect iBeacon?

Your testing method sounds fine. I think the issue is that the reference app for the pro library only auto launches the app on the first detection after boot. After that, it sends a notification instead, and tapping on that notification launches the app.
This is purely for demonstration purposes. You can change it to auto launch on every detection if you wish. Simply alter the haveDetectedIBeaconsSinceBoot logic in this code:
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever an iBeacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedIBeaconsSinceBoot) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an iBeacon, we launch the
// MainActivity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedIBeaconsSinceBoot = true;
} else {
// If we have already seen iBeacons and launched the MainActivity before, we simply
// send a notification to the user on subsequent detections.
Log.d(TAG, "Sending notification.");
sendNotification();
}
}
The javadoc link was missing from the main documentation page when you posted this question. That is fixed now.

Related

Android Beacon Library - didEnterRegion not firing when app in background or stopped for pre-Android 8

First some background:
My setup uses a Service, which implements BeaconConsumer and binds to the BeaconManager. I have additional handling so when my app leaves the foreground, I move my Service to run in foreground, and when my app enters the foreground, I move my Service to run in background. That way, the persistent notification should display if and only if the app isn't displaying. In accordance, I am using the pattern here to tell BeaconManager I'm running this Service in the foreground, to allow for more frequent scanning. The link above isn't quite clear about this, but I believe this pattern should work without alterations needed on both pre-Android 8 as well as Android 8+. It shouldn't be strictly necessary on pre-Android 8, since the OS is more lenient. However, using this setup across all versions has the collateral benefit of ensuring that the OS does not kill the Service. If the app is in the foreground, the Service is background but has priority by virtue of the app, and if the app is not in the foreground, the Service is, and therefore has priority.
Now the problem: On pre-Android 8 devices, my Service is not seeing didEnterRegion called when the app is not in the foreground (but the Service is). It works fine on Android 8+.
some code snippets:
In my Service, set up the BeaconManager, set scan intervals
_beaconManager = BeaconManager.getInstanceForApplication(this);
_beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(IBEACON_PATTERN_1));
_beaconManager.setEnableScheduledScanJobs(false);
_beaconManager.setBackgroundBetweenScanPeriod(0);
_beaconManager.setBackgroundScanPeriod(1100);
Function in my Service I invoke to send the service to the foreground, and background:
private void sendServiceToForeground() {
this.startForeground(NOTIFICATION_ID, _notification);
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.enableForegroundServiceScanning(_notification, NOTIFICATION_ID);
_beaconManager.bind(this);
}
}
private void sendServiceToBackground() {
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.disableForegroundServiceScanning();
_beaconManager.bind(this);
}
this.stopForeground(true);
}
I can provide more code as requested. Not sure what all is relevant.
Calls to unbind() and bind() are asynchronous, so calling them one after another will be a problem unless you first wait for the unbind() operation to complete. This is tricky, because the library's BeaconManager does not provide a callback to tell you when unbind is complete (indeed, this is because the underlying Android service APIs also do not provide such a callback. You essentially don't know when the library's scanning service has stopped so you can safely restart it again in a different mode.)
It's a bit of a hack, but you might try adding a delay between unbind() and bind() to see if that makes a difference.

Why does Xcode simulator launch app with didEnterRegion call, while iPhone does not?

I'm troubleshooting a location-based app launch cycle that works fine on iOS simulator, but apparently does not launch the app on an actual device.
I've set up UNNotifications for both enter and exit events. Both the simulator and the device(s) register and display these notifications.
The next thing that is supposed to happen is that the app goes through a launch process, setting the app's state in such a way that I can tell without being connected to the debugger whether the app has launched or not when I open it from the home screen.
On simulator, the didEnterRegion code gets called and I can step through the subsequent launch code using the debugger - success.
However when I take the device out (for a walk) all I get are UNNotifications, and no app launch (which I can tell from the UI in the app on the real device)
I'm sure I need to improve my testing strategy (welcome to suggestions!), but at this point I should be able to expect that the app should behave the same on the simulator and the actual device - it is not.
Why is the expected outcome happening on the simulator but not on the device?
LocationService.swift
func handleRegionEnterEvent (for region: CLRegion) {
ApplicationController.sharedInstance.didEnterRegion(region)
}
func handleRegionExitEvent (for region: CLRegion) {
ApplicationController.sharedInstance.didExitRegion(region)
}
ApplicationController.swift
func didEnterRegion (_ region: CLRegion) {
// Present Alert
delegate?.handleUNEvent(note: "ENTER: \(region.identifier)")
// Start launch cycle
}
AppDelegate.swift
extension AppDelegate: AppControllerDelegate {
func handleUNEvent(note: String?) {
// Show an alert if application is active
if UIApplication.shared.applicationState == .active {
guard let message = note else { return }
Alert().showAlert(withMessage: "Application received UN while active: \(message)", title: "UNNotification")
} else {
// Otherwise present a local notification
guard let body = note else { return }
let notificationContent = UNMutableNotificationContent()
notificationContent.body = body
notificationContent.sound = UNNotificationSound.default
notificationContent.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "location_change",
content: notificationContent,
trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Error: \(error)")
}
}
}
}
}
The simulator sadly has a lot of differences from a device both in terms of data reported (you will not get speed for example) and also as you saw call flow may be different...
Something to check is to make sure you have the descriptions for the specific location permissions you are asking for in relation to location set up. For entering regions you probably want to make sure you have "always" access.
It may also be worth enabling wireless debugging, and walking around with laptop tethered to the device to verify with the debugger the didEnterRegion is truly not called, and there is a bug in the code that is supposed to display the UI you are expecting. At the very least perhaps you could get better logging as to the status of various location callbacks.
What happened: Code that executed on simulator was indeed crashing on the device and I was not reviewing crash logs from the device. This question arose from an issue that is neither ios, or core-location specific.
It has everything to do with choosing appropriate testing strategies and using all available information at one's disposal before coming to what may turn out to be premature conclusions.
However when I take the device out (for a walk) all I get are UNNotifications, and no app launch (which I can tell from the UI in the app on the real device)
I was mistaken to think that a) User Notifications that appear when the App is not running are presented by the system (as banners) and b) the App launches in another process. In fact my own code specifically executes the code that makes those notifications appear. Face-to-palm: Copying code from tutorials to achieve quick test results without even trying to understand what the code does can lead to that I suppose.
In Xcode, plug in your device and hit command-shift-2 to open Devices & Simulators window. Select your device on the left and hit "View Logs" button to bring up your crash log.

How do I deal with a possible exception in a Xamarin Forms application deployed to iOS or Android?

I have a finished application which I would like to make available to run on the iOS and Android platforms.  I have tested the application as much as possible and it works without problem.  But I know there is always the chance that something might go wrong and I could get an exception.
My question is how can I deal with this or what should I do. What happens on the phone, if a Forms application is deployed and there is an exception.
Would appreciate any advice or even links as to how this is handled.
If an exception is thrown and not handled by your code, the app will stop working (i.e. crash).
In order to handle these crashes we are using MS AppCenter (the successor to HockeyApp/Xamarin AppInsights).
You'll have to create a project there (one for each platform), and add the NuGet package to your projects. Afterwards you can initialize it with
AppCenter.Start("ios={Your App Secret};android={Your App Secret}",
typeof(Crashes)); // you'll get the app secrets from appcenter.ms
Crashes will be logged to AppCenter now and you'll be informed whenever there is a new crash.
Please note that it's best practice (if not required by law), that you ask the user for consent before sending the crash report (see here). You are using the delegate Crashes.ShouldAwaitUserConfirmation for that matter. You could for example show an action sheet with Acr.UserDialogs
private bool AwaitUserConfirmation()
{
// you should of course use your own strings
UserDialogs.Instance.ActionSheet(
new ActionSheetConfig
{
Title = "Oopsie",
Message = "The app crashed. Send crash to developers.",
Options = new List<ActionSheetOption>
{
new ActionSheetOption("Sure", () => Crashes.NotifyUserConfirmation(UserConfirmation.Send)),
new ActionSheetOption("Yepp, and don't bug be again.", () => Crashes.NotifyUserConfirmation(UserConfirmation.AlwaysSend)),
new ActionSheetOption("Nope", () => Crashes.NotifyUserConfirmation(UserConfirmation.DontSend))
}
});
return true;
}

Xamarin Forms - How to open specific page after clicking on notification when the app is closed?

I'm actually working on a Xamarin Forms application that need push notifications. I use the Plugin.PushNotification plugin.
When the app is running in the foreground or is sleeping (OnSleep), I have no problem to open a specific page when I click on a notification that I receive. But I was wondering how can I do that when the app is closed. Thanks!
I finally found the answer by myself and I want to share it in case someone needs it.
Nota bene: according to the official documentation of the plugin, it's Xam.Plugin.PushNotification that is deprecated. I use the new version of this plugin, Plugin.PushNotification which uses FCM for Android and APS for iOS.
There is no significant differences to open a notif when the app is running, is sleeping or is closed. Just add the next callback method in the OnCreate method (MyProject.Droid > MainApplication > OnCreate) and FinishedLaunching method (MyProject.iOS > AppDelegate > FinishedLaunching):
CrossPushNotification.Current.OnNotificationOpened += (s, p) =>
{
// manage your notification here with p.Data
App.NotifManager.ManageNotif(p.Data);
};
Common part
App.xaml.cs
// Static fields
// *************************************
public static NotifManager NotifManager;
// Constructor
// *************************************
public App()
{
...
NotifManager = new NotifManager();
...
}
NotifManager.cs
public class NotifManager
{
// Methods
// *************************************
public void ManageNotif(IDictionary<string, object> data)
{
// 1) switch between the different data[key] you have in your project and parse the data you need
// 2) pass data to the view with a MessagingCenter or an event
}
}
Unfortunately there is no succinct answer for either platform. Generally speaking, you need to tell the OS what to do when it starts the app as a result of the push notification. On both platforms, you should also consider what API level you are targeting, otherwise it won't work or even crash the app.
On iOS, you will need to implement this method in AppDelegate appropriately: FinishedLaunching(UIApplication application, NSDictionary launchOptions). The launchOptions will have the payload from the push notification for you to determine what to do with it (e.g. what page to open). For more information on iOS, Xamarin's documentation is a good place to start.
Android has a more complicated topology in terms of more drastic differences between API levels, whether you are using GCM/FCM, as well as requiring more code components. However, to answer the question directly, you will need to handle this in OnCreate(Bundle savedInstanceState) of your main Activity. If you are using Firebase, the push notification payload is available in Intent.Extras. Again, Xamarin's documentation has a good walkthrough.
Finally, note that the Plugin.PushNotification library you are using has been deprecated. I suggest you either change your library and/or your implementation soon. Part of the reason that library has been deprecated is because Google has deprecated the underlying Google Cloud Messaging (GCM) service, which will be decommissioned on April 11, 2019.

How to launch a BREW application in background?

I know the Brew application have 3 types: active, suspend & background. Launch one BREW application as active or suspend is very simple. I know in BREW2.0 and later version, there is a new application type can allow we create one application in the background. It will not stay in the application stack and change status by active or resume command. It will always stay in the background no matter what user command system received. In one of my small project, I need to create and launch one background application like this.
Unfortunately, I cannot find a simple example on Qualcomm or Google. Is there any programmer who has encountered the same problem?
Yes, you are right. BREW2.0+ do support background application.
When we initial a background application, just like other normal new application, it can be launched by the brew application interface directly. You also can launch it by ISHELL_StartApplet function.
When you want to put one brew application in the background, you need do it when handle EVT_APP_STOP event and must set dwParam to false. After handling EVT_APP_STOP by this, the application will be put in the background. And if you want to change it to normal application, you need call ishell_StartApplet function to active to itself again.
Example code:
typedef struct _bgApp
{
AEEApplet a;
boolean m_bGoBg;
} bgApp;
switch (eCode)
{
case EVT_APP_START:
if(pMe->m_bGoBg)
ISHELL_CloseApplet(pMe->a.m_pIShell, FALSE);
case EVT_APP_STOP:
if(pMe->m_bGoBg)
*((boolean*) dwParam) = FALSE;
return TRUE;
case EVT_USER:
if(pMe->m_bGoBg)
{
pMe->m_bGoBg = FALSE;
// make applet active
ISHELL_StartApplet(pMe->a.m_pIShell, AEECLSID_BGAPP); }
else
{
pMe->m_bGoBg = TRUE;
// trigger EVT_APP_STOP to send app to background
ISHELL_CloseApplet(pMe->a.m_pIShell, FALSE);
}
return TRUE;
}
There is a limitation of background application. You cannot change the screen or communicate with user directly. Developer should be careful on the memory used by the background application. This is very important.

Resources