Bluetooth scan not work when using flutter in ios - ios

I'm using flutter_blue_plus package which is almost same with flutter_blue. When I test with iphone 13 mini connected with mac book xcode, my app scans bluetooth devices well. But when I extract my app to .ipa and install the app using xcode, my iphone 13 mini(which is not connected to mac book) not scan bluetooth devices anymore. Of course I've checked that I give same permission to the iphone both of the test.
Is there any suggestion for test or anyone experienced same situation?
I'm very beginner of flutter and ios development (I just started it from a month ago), so please give me any advice if you have about this bluetooth problem..
My scan function is in the background mode, and I checked the scanned devices using snack bar. But I think it is not the problem, the app works well when I test with xcode and the iphone is connected to mac.
I added a part of my code for your information.
(My function for BLE Scanning)
Future<void> initialScanning() async {
// ios execute this function with .ipa installed but skips scanning.
final FlutterBluePlus flutterBlue = FlutterBluePlus.instance;
// Start scanning
flutterBlue.startScan(timeout: Duration(seconds: _firstScanDuration));
// Listen to scan results
var subscription = flutterBlue.scanResults.listen((results) async {
// Find the device with the name and Register
for (ScanResult r in results) {
print('${r.device.name} rssi: ${r.rssi}');
if (r.device.name == 'raspberrypi') {
if (!devices.contains(r.device)) {
devices.add(r.device);
print('device added!!!!');
}
}
}
for (BluetoothDevice device in devices) {
if (!registeredDevices.contains(device.id.toString())) {
registeredDevices.add(device.id.toString());
await someBleRegister(device);
}
}
});
// Stop scanning
flutterBlue.stopScan();
}
(onEvent function for flutter_foreground_task)
#override
Future<void> onEvent(DateTime timestamp, SendPort? sendPort) async {
if (_eventCount == 0) {
await initialScanning();
} else {
print('number of devices: ${someBles.length}');
for (SomeBle ble in someRegisteredBles) {
await someBleReadAndWrite(ble);
}
}

I my self found out the answer that flutter_blue_plus.startScan (i.e. BLE scan) is not work well with flutter_foreground_task package in ios.
When I use the startScan in onStart( a override method of flutter_foreground_task package), the BLE scanning was work well with normal development setup with xcode.
But the same code was not work when I made .ipa file and installed to iphone.
It never scans anything and skips the scanning.
But when I moved the BLE scanning codes to the foreground, it worked well both xcode connected and .ipa file installed.
I don't know why.. but, anyway, that is true.
(Edit) flutter_reactive_ble not work too in flutter_foreground_task background mode with .ipa file installed.

Related

Flutter - Is there any way to restart iOS version programmatically?

I have an flutter app and i used applifecyclestate.resumed to see if the app is running in the background and I used restart_app library to restart the app when it is in the background.This function worked in android but in ios it is not working
If you please tell is there anyway to restart the application in ios devices?
Here is the code
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed) {
debugPrint('----------> app state resumed');
Restart.restartApp();
}
Thank you

WatchKit App Cannot Connect to the Internet. Works on Simulator but not on Physical Device

This is my first WatchKit App.
I am working on an app that gets an API call to an iCal file and displays the time remaining in two events.
I am working on Xcode 13.4.1 and created an iOS app with watchOS app using swift and storyboard. I set the target deployment for the iOS app to 15.5, which is the highest version of iOS that my current version of Xcode will let me set. The target deployment for the watchOS app is set to version 6.2 because I have an Apple Watch series 2, and the latest version of watchOS is 6.3. I want the app to at least work for my watch. The code for the iOS app and watch app are pretty much the same. The app works as expected on the watch and phone simulators and on my physical iPhone 8 plus. The problem is that the app does not work on my physical watch.
I created a custom class called API_Manager that handles the API call. I handle my API call as a giant string because I am getting an iCal file and parse it later on in the class. url is defined above. Here is my API call for both the phone and watch app:
public func getData() throws{
//api call
do{
// real url is defined above
let url:String = ""
savedData = try String(contentsOf: URL(string: url)!)
} catch{
print("there was an error with the api call")
throw API_Error.apiCallError
}
// parsing data
}
getData() is called in the init function of the API_Manager class.
init() throws {
// checking internet connection
if (!NetworkMonitor.shared.isConnected){
throw API_Error.noInternet
}
do{
try getData()
} catch{
throw API_Error.apiCallError
}
}
I believe the root of the problem is an Internet connection. I check for an Internet connection before the API call, and if there is no Internet connection, then I throw a custom error. I used this video to create a Network_Monitor class. This is the startMonitoring() function which is called in the applicationDidFinishLaunching() in extensionDelegate of the watch app and application didFinishLaunchingWithOptions in the appDelegate.
public func startMonitoring(){
monitor.start(queue: queue)
monitor.pathUpdateHandler = { [weak self] path in
self?.isConnected = path.status == .satisfied
// getting connection type
self?.getConnectionType(path)
}
}
I created a custom error that is thrown throughout the API_Manager if things don't work as expected. Here is how I created the custom errors:
enum API_Error: Error{
case noInternet
case apiCallError
}
extension API_Error: CustomStringConvertible{
public var description:String {
switch self{
case .noInternet:
return "Error: No internet connection"
case .apiCallError:
return "There was an error with the api call"
}
}
}
I created another enum that is used to display text on a label in the Interface Controller if a specific error is thrown.
enum API_Manager_Status{
case active
case noInternet
case apiCallError
case null // if the api manager is nill
}
Here is how I used the two enums in InterfaceController:
main() is called in the awake() function.
func main(){
do{
apiManager = try API_Manager()
apiManagerStatus = .active
} catch API_Error.noInternet{
apiManagerStatus = .noInternet
} catch API_Error.apiCallError{
apiManagerStatus = .apiCallError
} catch{
apiManagerStatus = .null
}
if (apiManagerStatus == .noInternet){
periodLabel.setText("Error")
timeRemaining.setText("No Internet")
print(API_Error.noInternet)
} else if (apiManagerStatus == .apiCallError){
periodLabel.setText("Error")
timeRemaining.setText("API Call")
print(API_Error.apiCallError)
} else if (apiManagerStatus == .null){
periodLabel.setText("Error")
timeRemaining.setText("Other Error")
print("Cought all errors")
} else{
// main code to display time remaining
}
So I guess my questions are:
Why is my Apple Watch not getting an Internet connection?
How can I fix my app if it worked on the simulators and iPhone, but not watch?
Can the Apple Watch do an API call?
Do I need to configure my app to connect with the iPhone, given that my watchOS verison is 6.2?
Sorry if this is a long question. This is my first time posting a question on Stack Overflow. I would appreciate any help. Let me know if I need to add any more information to help clear things up.
I have tried many potential solutions to fix the problem, but none have worked:
I distributed the app on Test Flight and had my dad download it. He has an Apple Watch Series 4 running on watchOS 9.2, and the app still does not work on his watch.
I have restarted my phone and watch multiple times and even tried to run the app with my phone off, so the watch could connect to wifi.
I tried to install a watchOS 9 beta profile on my watch, knowing it would not work, but I still wanted to see what would happen.
I tried setting the build target to watchOS 8.5, which is the highest my version of Xcode would allow, to see if the problem was watchOS 6.2, and if it would work on my dad's watch.
Lastly, I tried adding privacy messages in the Info.plist for both the phone and the watch app. The messages did not display when I re-downloaded the app, but it still did not fix the issue.
(the messages I used were: "Privacy - Nearby Interaction Usage Description" which does not work on watchOS 6.2, but I still kept in the info.plist, and "Privacy - Bluetooth Always Usage Description")
I know Apple Watches are supposed to use the connected phone for Internet and then wifi if a phone is not connected. My watch shows that my phone is connected, and I have tried it with just wifi. I believe my watch can still get an Internet connection because I can still use Siri and even go to the App Store on my watch, which needs an Internet connection. I would appreciate any help. Let me know if I need to add any more information to help clear things up.

Detecting app run on emulator or real device

I need to detect, if an app is running on an iOS or Android emulator to skip an QR code scan method and just return a scanned code.
Q: How do I detect
on which device type - iOS or Android - an app is running and
if an app is running on an emulator?
Just found this plugin, which prints various details:
https://pub.dartlang.org/packages/device_info#-readme-tab-
Output on Android emulator [see last line]:
safe_device: ^1.1.1
import 'package:safe_device/safe_device.dart';
Checks whether device is real or emulator
bool isRealDevice = await SafeDevice.isRealDevice;
(ANDROID ONLY) Check if development Options is enable on device
bool isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable;

Xamarin Forms location services work on iOSimulator but not on Testflight build

I am working on a Xamarin Forms app that asks the user for Location services permission using PermissionsPlugin. I use Visual Studio 2017 in Windows and a Virtual Machine as my MAC build host (macOS High Sierra 10.13.4).
My problem is that the app works as intended when deployed to the iOSimulator. It prompts the user to allow or deny the use of location services. In the simulator, the app is even listed under Settings>Privacy>Location Services. But after delivering the built IPA file to Apple and testing it via Testflight, the app does not prompt anything and just loads indefinitely. The app is also not listed in Settings>Privacy>Location Services.
Here is the code from the app for requesting permission:
async Task<bool> AskPermission()
{
var hasPermission = false;
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Location))
{
await App.Current.MainPage.DisplayAlert("Need location", "Allow app to access location?", "OK", "Cancel");
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
if (results.ContainsKey(Permission.Location))
{
status = results[Permission.Location];
}
}
if (status == PermissionStatus.Granted)
{
hasPermission = true;
}
else if (status != PermissionStatus.Unknown)
{
await App.Current.MainPage.DisplayAlert("Location Denied", "Can not continue, try again.", "OK");
}
}
catch (Exception ex)
{
}
return hasPermission;
}
This is one of the methods that is called on click of a button. An activity indicator then appears since it is bound to a boolean that is toggled when the all methods are started/done.
This is pretty much the sample code from James Montemagno's plugin. I suspect the app gets stucked on await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location).
I also added the necessary additions to Info.plist in the iOS project of the App:
<key>NSLocationWhenInUseUsageDescription</key>
<string>prompt message</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>prompt message</string>
I also tested variations where I used NSLocationAlwaysUsageDescription instead of NSLocationWhenInUseUsageDescription but got similar results...
I tested this in iOSimulator (iPhone 5, 6, 7, all in 11.3, all worked) and tested in Testflight using an iPhone 7 and an iPad, both in 11.3 as well; unfortunately, both cases didn't prompt permission request dialog.
For reference, this works as intended in Android both in debugging and testing from Play store.
I got the fix; just had to include all 3 NSLocationWhenInUseUsageDescription, NSLocationAlwaysUsageDescription, and NSLocationWhenInUseUsageDescription...
I was under the impression that I can only add either one of NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription. I must have read an outdated answer somewhere that gave me that wrong impression.

Flutter's readAsBytes is very slow on iOS device

Running the following code is very slow on iOS device although it is fast on iOS simulator.
The file comes from its album.
How can I speed it up?
Future<List<int>> decoding(File f) async {
return await f.readAsBytes();
}

Resources