Bundle ID breaks audio in the background - ios

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

Related

Flutter: geolocator Error? Warning? [CoreLocation] This method can cause UI unresponsiveness if invoked ... . I can't get GPS information

I am developing in Flutter and am trying to get GPS information using the geolocator package.
I was able to get GPS information on the emulator with no problem, but when I started the app on the actual device, I could not get GPS.
The app was working fine, so it was not an error, but there was a message.
"This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the -locationMana gerDidChangeAuthorization: callback and checking authorizationStatus first."
Code on Flutter side
Future<Position> getGps(BuildContext context) async {
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: Duration(seconds: 5),
);
}
(WARNING)Code on IOS side
- (ServiceStatus)checkServiceStatus:(PermissionGroup)permission {
return [CLLocationManager locationServicesEnabled] ? ServiceSttus Enabled
: ServiceStatusDisabled;
}
2023/1/26 added
I had added it to info.plist. Still, I am not getting GPS information.
info.plist
<key>NSLocationAlwaysUsageDescription</key>
<string>Access location information to get a location</string>.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Access location information to get location</string>
How do I get GPS information?
Permission to acquire location services is granted.
iOS:16.2
xcode: 14
geolocator: 7.7.1
2023/1/26 added
Current Status
Emulator(Android) ...〇(GPS information has been acquired.)
Emulator(iOS(iphone SE2)) ...〇(GPS information has been acquired.)
Actual Device(iOS(iphone SE2)) ...× (GPS cannot be acquired)
Try this
Add "location_permissions: 3.0.0+1" this dependencies in "pubspec.yaml". Please note that I did that for flutter 1.22.0 so for flutter 2.0 this might be an issue.
Import the package in the file
import 'package:location_permissions/location_permissions.dart';
Add the following code on the page where you want to ask for permission. (Better to add that on the very first page of your app.)
#override
void initState() {
....
if (Platform.isIOS) {
location_permission();
}
....
}
Add the following two methods in the same file
void location_permission() async {
final PermissionStatus permission = await _getLocationPermission();
if (permission == PermissionStatus.granted) {
final position = await geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
// Use the position to do whatever...
}
}
Future<PermissionStatus> _getLocationPermission() async {
final PermissionStatus permission = await LocationPermissions()
.checkPermissionStatus(level: LocationPermissionLevel.location);
if (permission != PermissionStatus.granted) {
final PermissionStatus permissionStatus = await LocationPermissions()
.requestPermissions(
permissionLevel: LocationPermissionLevel.location);
return permissionStatus;
} else {
return permission;
}
}
I was able to solve my problem.
I thought it was a permissions issue in my case, but it was just a location acquisition timeout. I modified the location acquisition timeout from 5 seconds to 20 seconds and was able to get the necessary information without any problems.
The warnings are still there, but we decided not to worry about them since we were able to solve the problem.
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: Duration(seconds: 20),
);

Flutter, Deep link is not working on iOS when app is closed

In Flutter, I am using Navigator 2.0 using go_router.
I want deeplink in my app to work properly and my app has some properties which needs to be initialized before going to any screen so I have put my MaterialApp.router(...) in a conditional boolean and Splash screen is shown while app is being initialized.
But deeplink doesn't redirect to given path when app is closed on iOS, it just opens the app.
Everything is working fine in android.
It starts working fine in iOS too when I remove async app initialization function from MaterialApp.
What am I doing wrong? Is there better way to initialze app instead of a conditional check in MaterialApp.
I have created a basic reproducible code repo https://github.com/sgshivamgarg8/testapp. Please try it out. To test deeplinks I have put required scripts in scripts/ folder.
Future<void> _appInit() async {
setState(() {
isLoading = true;
});
await Future.delayed(
const Duration(seconds: 1)); // commenting this line solves the issue
setState(() {
isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return isLoading
? const CircularProgressIndicator()
: MaterialApp.router(
routerConfig: _router,
title: 'Test',
theme: ThemeData.light(),
debugShowCheckedModeBanner: false,
);

How to configure Workmanager Flutter iOS correctly?

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?

Native camera rendering broken after upgrade to Expo 42(from 39) (React Native)

I am using the native camera (iOS/Android) calling as following:
async function takePhoto() {
const photo = await ImagePicker.launchCameraAsync(cameraOptions);
if (photo.cancelled) {
return '';
}
return photo.uri;
}
Since upgraded from Expo 39 to 42 it is broken (see screenshots)
Portrait
Landscape
It seems to me, that it is beeing opened as Modal. I don't know where to change this.
Expected behaviour:
Display of camera in fullscreen as native camera under iOS
Update: 20210730: Meanwhile it has been opend as a bug/issue:
https://github.com/expo/expo/issues/13614
Any ideas, suggestions - especially in terms of a workaround?
Thanks a lot.
I've done a massive upgrade from EXPO SDK 37 to EXPO SDK 42. Had to change alot of things around camera, location and permissions.
I do not experience this behavior when using the following (I cannot see your import statements or your package versions but this is what I've implemented and experience no issue)
// Import statements...
import * as ImagePicker from 'expo-image-picker';
import * as FileSystem from 'expo-file-system';
import { Camera } from 'expo-camera';
// Code within Component
const takePicture = async () => {
// You MUST ask for permissions first.
const permissions = {
[Camera]: await Camera.requestPermissionsAsync()
};
// If denied let the user know its required.
if (permissions[Camera].status !== 'granted') {
return Promise.reject(new Error('Camera Permission Required'));
}
// Then let them launch the camera and perform any other task
await ImagePicker.launchCameraAsync({
allowsEditing: false
})
.then(({ uri }) => imageProcesser(uri))
.then(res => onImageAdded(res))
.catch((e) => console.log(e));
};
// These are my concerning package versions
"expo-camera": "^11.2.2"
"expo-file-system": "~11.1.3",
"expo-image-picker": "~10.2.2",
"expo": "^42.0.3"

Recording and playing video

In my current flutter project i need to record video, modified it and then show to user.
The problem is that in the iOS (14.2) the recorded video/modified can not be shown by video player, unfortunately there is no error from iOS (tested on physical devices).
Libraries and versions:
video_player: 1.0.1
flick_video_player: ^0.1.1
camera: ^0.5.8+17
flutter_ffmpeg: ^0.3.0
The reason why i do not use newest version of camera is that it is bugged and for certain number of devices there is no way to show even the preview.
Code:
Camera initialization
Future<void> _initCamera() async {
final cameras = await availableCameras();
final camera = cameras.firstWhereOrNull(
(element) => element.lensDirection == CameraLensDirection.back,
);
_controller = CameraController(
camera,
resolutionTarget,
enableAudio: false,
);
await _controller.initialize();
await _controller.prepareForVideoRecording();
//Show the preview
setState(() {});
}
Recording video
Future<void> startVideoRecording() async {
_videoPath = await generatePath(PathExtension.mp4);
await _controller.startVideoRecording(_videoPath);
}
Future<String> stopVideoRecording() async{
await _controller.stopVideoRecording();
return _videoPath;
}
Showing recorded video
void _createFlickManager(File videoFile) {
final videoController = VideoPlayerController.file(videoFile);
_flickManager = FlickManager(
videoPlayerController: videoController,
);
}
Widget _buildVideoPreview(){
return FlickVideoPlayer(
flickManager: _flickManager,
flickVideoWithControls:
FlickVideoWithControls(controls: Container()),
);
}
Summary:
the camera preview is showing properly,
the recording video file has size and does not throw any exception,
black screen when trying to show video using FlickVideoPlayer or just VideoPlayer,
converted video to mp4/mov by ffmpeg still not working.
Apparently in iOS 14.2 there is problem with paths that contains spaces, as i used DateTime.now()
to generate unique file name and that was reason of the problem. Changing it to DateTime.now().millisecond solved it.

Resources