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
Related
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
As the title suggests, im trying to listen for click-event from my connected BLE peripheral device even after my react-native app is killed/background mode.
While connected i have a notification subscription on my BLE peripheral device and everytime i press button on device, my app gets notified. I want this subscription to last even if the user kills the application.
The app works fine in foreground and inactive, but when i kill the app on iOS it stops responding to button click.
On android i found a library react-native-background-actions which helped solve this. Here is the background code that is currently working on android.
import BackgroundJob from "react-native-background-actions";
playing = BackgroundJob.isRunning();
const sleep = (time) =>
new Promise((resolve) => setTimeout(() => resolve(), time));
BackgroundJob.on("expiration", () => {
console.log("iOS: I am being closed!");
});
const taskRandom = async (taskData) => {
if (Platform.OS === "ios") {
console.warn(
"This task will not keep your app alive in the background by itself, use other library like react-native-track-player that use audio,",
"geolocalization, etc. to keep your app alive in the background while you excute the JS from this library."
);
}
await new Promise(async (resolve) => {
// For loop with a delay
const { delay } = taskData;
console.log(BackgroundJob.isRunning(), delay);
for (let i = 0; BackgroundJob.isRunning(); i++) {
console.log("Ran -> ", i);
// await BackgroundJob.updateNotification({
// taskDesc: "Emergency -> " + i,
// });
await sleep(delay);
}
});
};
const options = {
taskName: "Example",
taskTitle: "ExampleTask title",
taskDesc: "ExampleTask desc",
taskIcon: {
name: "ic_launcher",
type: "mipmap",
},
color: "#ff00ff",
linkingURI: "exampleScheme://chat/jane",
parameters: {
delay: 30000,
},
};
/**
* Toggles the background task
*/
export const toggleBackground = async () => {
playing = !playing;
if (playing) {
try {
console.log("Trying to start background service");
await BackgroundJob.start(taskRandom, options);
console.log("Successful start!");
} catch (e) {
console.log("Error", e);
}
} else {
console.log("Stop background service");
await BackgroundJob.stop();
}
};
I tried reading the core bluetooth background processing for iOS apps and added a restoration identifier on my start method like this:
BleManager.start({
showAlert: true,
restoreIdentifierKey: "IDENTIFIER",
queueIdentifierKey: "IDENTIFIER",
}).then(() => {
console.log("Module initialized");
});
Does anyone have a suggestion on how to keep the subscription while app is in background? react-native-background-actions suggests audio or geolocation libraries, but these are not relevant for my application.
Any help would be greatly appreciated.
You have two very different states you are talking about; Background and killed.
If your app is not onscreen but is still in memory then it is "suspended". It remains suspended until
It is brought back into the foreground by the user
A supported background event occurs and it executes briefly while before becoming suspended again.
It is removed from memory because iOS needs resources
It is removed from memory by the user "Swiping it away"
If an iOS app is suspended and you have added Bluetooth background mode to your app then it will just work; This is scenario 2.
You need to consider what you want to do if the peripheral goes out of range; Do you want to try and reconnect or do you want to give up.
If you want to try and reconnect then you simply call connect in response to a disconnection. If the peripheral comes into range then Core Bluetooth will provide a call-back to your app (even if it is suspended). This applies in both scenario 1 & 2.
An app can be in two different "killed" states; terminated by the system and terminated by the user. These are scenarios 3 & 4
If the app is terminated by the system, scenario 3, and you have set up Core Bluetooth state restoration when you initialised Core Bluetooth then iOS will relaunch your app. When relaunched you need to set up Core Bluetooth again and then the event will be delivered to your app as usual.
If the app is terminated by the user swiping up, scenario 4, then generally speaking your app is dead until the user relaunches it.
You haven't shown how you are using Core Bluetooth, so I can't offer any concrete suggestions but I can say the approach you have shown, trying to keep your app running in the background, is not the right approach and will definitely not work on iOS. There may even be a better approach on Android, but I am not familiar with that platform. Generally keeping an app around, in memory, performing useless work is just wasting memory and battery resources.
Is it possible to use flutter to keep the notification badge on the app icon even after opening and closing the app? Ex.: user has a badge of value 6, opens app to read one message, closes app, badge now reads as 5.
How do I achieve this functionality? (Specifically looking for iOS solution, but also interested in hearing about Android side if you have tips)
One way of achieving this is using the flutter_app_badger package, which allows you to set the app badge using the updateBadgeCount function. The trick is that you need to call this function at least once when your app is in the foreground before the app is put to the background or closed. One way to do this is to extend WidgetsBindingObserver and override didChangeAppLifecycleState in one of your widgets at the top of the widget tree:
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
print("app in resumed");
if (PushNotificationsManager.appBadgeSupported) {
FlutterAppBadger.updateBadgeCount(14);
}
break;
case AppLifecycleState.inactive:
print("app in inactive");
break;
case AppLifecycleState.paused:
print("app in paused");
break;
case AppLifecycleState.detached:
print("app in detached");
break;
}
}
}
The app badge will not persist by itself, which is why you need to call this function at least once each time your app is in the foreground and a great place to do that is in didChangeAppLifecycleState when AppLifecycleState changes. If you call updateBadgeCount in the AppLifecycleState.resumed state like above, you'll also need to call updateBadgeCount once when your app starts (you can do this in the init function of a class like PushNotificationsManager if you have one, otherwise just do it in one of your widgets init function).
You can also put updateBadgeCount in the other states like AppLifecycleState.inactive or AppLifecycleState.paused, which will work in most cases but be cautious about this because if the app is closed/terminated without the inactive or paused state triggering, then the app badge will not be updated because the updateBadgeCount function is not called.
For completeness: when your app is closed or in the background, you can update your app badge using Apple Push Notification service. Include the badge number in the payload, as shown here. Then when the user opens your app, the code above will execute and the badge number will be updated again so that when the user closes the app or the app goes into the background, the badge number will "persist" as seen by the user.
More about WidgetsBindingObserver and how to detect if app is in foreground/background here.
I have an adobe air application - AS3 for iOs and Android.
Whenever the user clicks the home button, and thus the application is now in the background, the application automatically stops, which is the expected behavior. Now, if the user is in the application, and he double clicks his home button, showing all the multiple windows, the application continues running, which is not what i want. How can i access that state ( Not Background, not foreground )? If i can access it, i would then put my pausing code into that state, but how can i access that particular state?
When the user clicks the home button the app is moved to the background and suspended. The app isn't closed. The OS can close the app to free memory. If your app is a memory hog you'll see this happening.
You use events dispatched by the NativeApplication object. Below is example code to listen and handle these events.
import flash.events.Event;
import flash.desktop.NativeApplication;
import flash.desktop.SystemIdleMode;
// create listeners to NativeApplication
private var naApplication: NativeApplication;
naApplication = NativeApplication.nativeApplication;
naApplication.addEventListener(Event.ACTIVATE, eActivate);
naApplication.addEventListener(Event.DEACTIVATE, eDeactivate);
naApplication.addEventListener(Event.EXITING, eExiting);
private function eActivate(e: Event): void {
// app has opened or resumed
application.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
}
private function eDeactivate(e: Event): void {
// app is going to be moved to background
application.systemIdleMode = SystemIdleMode.NORMAL;
}
private function eExiting(e: Event): void {
// app is going to be closed by user or by the OS (usually to free up memory)
// do whatever exit code here then remove all listeners (to be clean don't rely on OS to close them)
application.removeEventListener(Event.ACTIVATE, eActivate);
application.removeEventListener(Event.DEACTIVATE, eDeactivate);
application.removeEventListener(Event.EXITING, eExiting);
application.systemIdleMode = SystemIdleMode.NORMAL;
removeEventListener(Event.ENTER_FRAME, eMainTimer);
}
The systemIdleMode and ENTER_FRAME are just examples of typical code. Let me know of any questions.
How can I set local notifications with out forcing user to open app.
I need my app set a local notification for sunrise and sunset, but I don't want to ask people open app.
I know I can have up to 64 notifications via scheduleLocalNotification, but I need to set it for a year so I should be able to run app in background and set alarms for future sunrises and sunsets in background.
The simple answer is you can't. Your app can't run whenever it wants in the background; it can't schedule a timer to wake itself up to post more notifications when they are due.
The only way you could come close to something like this is by having a server which send a background push notification to your app as a wake-up call when a new batch of 64 notifications are coming close to needed to be posted.
However this would be relying on the fact the user doesn't terminate your app. If the user does then you'd have to send a non-background push notification to the user and hope they click on it to launch your app.
Android Awareness API has recently announced new features that provide a simple solution for your use-case (that avoids you having to explicitly manage location request or computing sunrise times). The way to achieve what you're trying to do is to create and register a TimeFence specified relative to sunrise/sunset.
For example:
// Create TimeFence
AwarenessFence sunriseFence =
TimeFence.aroundTimeInstant(TimeFence.TIME_INSTANT_SUNRISE,
0, 5 * ONE_MINUTE_MILLIS);
// Register fence with Awareness.
Awareness.FenceApi.updateFences(
mGoogleApiClient,
new FenceUpdateRequest.Builder()
.addFence("fenceKey", sunriseFence, myPendingIntent)
.build())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Fence was successfully registered.");
} else {
Log.e(TAG, "Fence could not be registered: " + status);
}
}
});
You will get callbacks when the fence evaluates to TRUE at sunrise, and when it evaluates back to FALSE at 5-min after sunrise.
Please check Fence API code snippets docs for how to add your custom app logic.