How to configure Workmanager Flutter iOS correctly? - ios

I create a background fecth with workmanager flutter and following as the instruction on their documentation [here]https://github.com/fluttercommunity/flutter_workmanager/blob/main/IOS_SETUP.md. On android is working properly, but I am not sure with ios.
I add this on my main.dart
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) {
switch (task) {
case Workmanager.iOSBackgroundTask:
stderr.writeln("The iOS background fetch was triggered");
break;
}
bool success = true;
return Future.value(success);
});
}
and call it on here
void main() async {
.....
//workmanager
if (Platform.isIOS) {
Workmanager().initialize(
callbackDispatcher, // The top level function, aka callbackDispatcher
isInDebugMode:
true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
);
}
}
and I tested via simulator and simulate background fecth. And its print
The iOS background fetch was triggered
SwiftWorkmanagerPlugin - ThumbnailGenerator createThumbnail(with:) something went wrong creating a thumbnail for local debug notification
but the notification didn't appear as on the documentation did. Is my workmanager working?
Logically, I think is work, but im not sure. Also, it will running on background (even the apps is close/kill/terminated) every 15 minutes in iOS?

Related

iOS requestTrackingAuthorization callback is not on the main thread

The iOS ATT Alert needs to be shown on startup before an app starts, so the remaining app code needs to be run in the completion handler (eg initialising advert code and starting the main game).
However, this crashes because the completion handler callback is not on the main thread (after the alert is actually shown and Allow or Ask App Not to Track is selected).
In iOS (Xamarin C# code):
public override void OnActivated(UIApplication application) // RequestTrackingAuthorization must be called when app is Active
{
if (!this.shownAlert)
{
this.shownAlert=true;
Debug.WriteLine("1) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=1
ATTrackingManager.RequestTrackingAuthorization(delegate (ATTrackingManagerAuthorizationStatus trackingManagerAuthorizationStatus)
{
Debug.WriteLine("2) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=7
});
}
}
Prints:
1) ThreadId=1
2) ThreadId=7
And the similarly in Unity:
Debug.WriteLine("1) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=1
ATTrackingStatusBinding.RequestAuthorizationTracking(delegate (int status)
{
Debug.WriteLine("2) ThreadId={0}", Environment.CurrentManagedThreadId); // ThreadId=4
});
This seems like a bug to me. So how do all the apps and games out there get this to work? Somehow switch to the main thread in the callback? I don’t see any examples of this.

Bundle ID breaks audio in the background

The audio works in the background as long as my bundle id is "dev.suragch.flutterAudioServiceDemo" (not mine)
but if I change bunde id to my "com.ambee.new":
— background stops working.
What's going on? How to make it work with my bundleId "com.ambee.new"?
This is my main.dart:
import 'package:audio_service/audio_service.dart';
import 'package:get_it/get_it.dart';
import 'package:audioplayers/audioplayers.dart' as audioplayers;
void main() async {
await setupServiceLocator();
final _audioHandler = getIt<AudioHandler>();
_audioHandler.play();
}
GetIt getIt = GetIt.instance;
Future<void> setupServiceLocator() async {
// services
getIt.registerSingleton<AudioHandler>(await initAudioService());
}
Future<AudioHandler> initAudioService() async {
return await AudioService.init(
builder: () => MyAudioHandler(),
config: AudioServiceConfig(
androidNotificationChannelId: 'com.mycompany.myapp.audio',
androidNotificationChannelName: 'Audio Service Demo',
androidNotificationOngoing: true,
androidStopForegroundOnPause: true,
),
);
}
class MyAudioHandler extends BaseAudioHandler {
final _player = audioplayers.AudioPlayer();
MyAudioHandler() {
_player.setReleaseMode(audioplayers.ReleaseMode.LOOP);
}
#override
Future<void> play() => _player.play(
'https://firebasestorage.googleapis.com/v0/b/ambee-cloud.appspot.com/o/Sound%2Fshort.wav?alt=media&token=bd7cc97f-d3d8-490b-9aff-b92df304e145');
}
You can reproduce the issue yourself by going to ios -> Runner.xcworkspace from this repo. Test the background audio loop with a physical iPhone, not simulator.
When you test it with this bundle ID in Xcode:
dev.suragch.flutterAudioServiceDemo: once you block the physical iPhone, it keeps looping the audio in background
com.ambee.new: once you block the physical iPhone, it STOPS looping the audio in background
It's because you need to add the background audio capability to your new bundle ID. Without this being added, the app doesn't have permission to play audio in the background.
You can find the documentation here: https://developer.apple.com/documentation/avfoundation/media_playback_and_selection/creating_a_basic_video_player_ios_and_tvos/enabling_background_audio

React Native : messaging().onMessage is not triggered very first time app launched in iOS

I want to handle foreground firebase messages.
But messaging().onMessage is not triggered very first time app launched in iOS. This is working fine in Android.
Exact scenario is:
First time launch app : messaging().onMessage not triggered in iOS
Close and reopen app : messaging().onMessage will trigger
import { Alert } from 'react-native';
import messaging from '#react-native-firebase/messaging';
function FCMReadInForeGround() {
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}, []);
}
export default FCMReadInForeGround;```
i hope this help you. i have same problem, and the im looking documentation ios messaging setup.
here the link : https://rnfirebase.io/messaging/usage/ios-setup .
in my case I haven't Linking APNs with FCM (iOS)
Try calling setBackgroundMessageHandler outside your component.
// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
try {
console.log('Remote notification', remoteMessage)
} catch (err) { console.log(err) }
});

React-native: display foreground notifications like background notifications with zo0r/react-native-push-notification

I have set up push notifications on my React-native app with zo0r / react-native-push-notification . It works on Android, and on iOS when the app is in background mode.
However, the notification does not display when the app is in foreground mode with iOS. I'm aware that I have to handle the notification when in foreground mode but I'd like to display them exactly the same way there are displayed when in background mode.
So I did the following:
import {PushNotificationIOS} from 'react-native';
PushNotification.configure({
...
onNotification: function(notification) {
if (notification.foreground) {
PushNotification.localNotification(notification);
}
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
...
}
But nothing happens, the notification is still not displayed, what am I missing?
I had to add some configuration inside the ios file AppDelegate.m
Following this gist did make it work.
My code look like:
onNotification(notification) {
if (isIos) {
if (
notification.foreground &&
(notification.userInteraction || notification.remote)
) {
PushNotification.localNotification(notification);
}
notification.finish(PushNotificationIOS.FetchResult.NoData);
} else {
if (notification.foreground) {
PushNotification.localNotification(notification);
}
}
},
I also set popInitialNotification to true

Flutter IOS in-app purchases initialization problem on IOS

I've just finished working on a personal app that has in-app purchases (Non-consumable). Unbelievably, the IAP part took me a lot of time due to a lack of documentation and complex testing process.
I am using the following package:
https://pub.dev/packages/in_app_purchase
Problem:
If you reopen the app on IOS, the app doesn't initialize the purchases until you click the button to buy again. However, it works perfectly on Android.
Future<void> initializeIap() async {
iapAvailable = await _iap.isAvailable();
if (iapAvailable) {
await _getProducts();
await _getPastPurchases();
_subscription = _iap.purchaseUpdatedStream.listen((data) {
_purchases.addAll(data);
_verifyPurchase();
});
_verifyPurchase();
}
}
Future<void> _getPastPurchases() async {
QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases();
//TODO: IOS Complete Purchases
for (PurchaseDetails purchase in response.pastPurchases) {
if (Platform.isIOS) {
InAppPurchaseConnection.instance.completePurchase(purchase);
}
}
_purchases = response.pastPurchases;
}
TIP:
Don't use
PurchaseStatus status; to validate the state of the purchase.

Resources