Why does my Flutter app crash when attempting to launch Apple Maps? - flutter

I am attempting to launch Apple Maps using Launch and a Url, only thing is that it crashes with no error message and I'm not sure why. The Url looks like so: http://maps.apple.com/?saddr=&daddr=
I check if it's Android or ios and build out the urls like this
if (Platform.isAndroid) {
{
await launch("$androidURL${widget.name} ${widget.city}, ${widget.state}");
}
} else if (Platform.isIOS) {
await launch("$iosURL${widget.name} ${widget.city}, ${widget.state}");
}
}
It has worked in the past but doesn't seem to work anymore. Right after it hits the line to build the url and launch maps it loses connection to the emulator and stops, how do I prevent this and just have it open maps as intended? Attached below is my flutter doctor. If I left any essential info out let me know and I'llm include it. Thanks all!

Assuming that you have done the configurations that are needed to use the url_launcher plugin, you can try
await canLaunch(_url) ? await launch(_url) : throw 'Could not launch $_url';
This way you can at least identify the error;

Related

Is it possible to use workmanager in Flutter to relaunch the app after a few hours (depending on the situation) when the app is completely closed?

I want to create an app that shows an alarm screen that sounds when the app is restarted when certain conditions are met after communicating with the api using workmanager in Flutter. However, the app does not restart even if I use the code below.
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
do{
code that api communication....
}while(When conditions are satisfied)
Restart.restartApp();//When I try to relaunch the app, nothing happens
});
return Future.value(true);
}

hive data gets reset when app is restarted

I have stored data in Hive box but whenever i restart the app or kills the app during offline mode i.e when internet conmnection is not there, Data gets resets & shows null error.
await Hive.initFlutter();
Hive.registerAdapter<ProgressList>(ProgressListAdapter());
Hive.registerAdapter<VideoList>(VideoListAdapter());
Hive.registerAdapter<DashBoard>(DashBoardAdapter());
Hive.registerAdapter<CourseDetails>(CourseDetailsAdapter());
Hive.registerAdapter<AnnouncementsListData>(AnnouncementsListDataAdapter());
Hive.registerAdapter<VideoAssignments>(VideoAssignmentsAdapter());
Hive.registerAdapter<LessonDetail>(LessonDetailAdapter());
Hive.registerAdapter<CourseQuestions>(CourseQuestionsAdapter());
await Hive.openBox<ProgressList>("box");
await Hive.openBox<VideoList>("video_box");
await Hive.openBox<DashBoard>("dashboard_box");
await Hive.openBox<CourseDetails>("course_box");
await Hive.openBox<AnnouncementsListData>("announcement_box");
await Hive.openBox<VideoAssignments>("vfs_feedback_box");
await Hive.openBox<LessonDetail>("lesson_box");
await Hive.openBox<CourseQuestions>("questions_box");
await Hive.openBox("video_record_box");
If you're facing this in debug mode, then you probably don't notice the difference between debugging an app and using it in release mode.
Your app may be running fine, if you debug your app on an Android emulator as an example, make sure that whenever you close the emulator, and you want to open it again, make sure that the emulator doesn't clear all phone data whenever you open it again, so it looks like the Hive didn't save your data, but actually the emulator set that it will clean all phone data whenever it's launched.
How this is related to Hive:
The Hive package is a key-value database, which saves its data inside files inside your device, so clearing all phone data will normally clear those files.
You need to try your app in a real device for making sure that your data is saved, and I would recommend to test if first in a release mode version.

How to connect to Ble device without rescan and manual device selection

I'm creating an Ionic react (TypeScript) app which uses the Community Bluetooth-le plugin.
When I try to connect to a device using requestDevice this shows the available devices and I can then pair/connect with that device and all is good.
await BleClient.initialize();
if (isAndroid) {
await BleClient.disconnect(devices.deviceId);
}
const device = await BleClient.requestDevice({
services: services ? services : [],
optionalServices: optionalServices ? optionalServices : [],
namePrefix: prefixFilter ? prefixFilter : "",
});
await BleClient.connect(device.deviceId, (deviceId) => onDisconnect(deviceId));
await BleClient.getServices(device.deviceId).then(
(services) => {
if (services[0]) {
//....
} else {
//....
}
}
)
However, if I save the device ID and then try to directly connect with that device using getDevices (rather than scanning and manually connecting) it always fails with the following console output:
Uncaught (in promise) Error: Device not found. Call "requestDevice", "requestLEScan" or "getDevices" first.
The code I use is this:
await BleClient.initialize();
if (isAndroid) {
await BleClient.disconnect(devices.deviceId);
}
await BleClient.getDevices(devices.deviceId);
await BleClient.connect(devices.deviceId, (deviceId) => onDisconnect(deviceId));
For clarification: I want to be able to search for available devices and connect to the device the first time the app is opened. Then, save the device ID and use this ID to connect to the device directly using getDevices from that point onwards. Likewise if the app is closed and re-opened I need to be able to take the stored device data and connect with that device directly without the whole scan and manual selection process.
I don't understand what I'm missing.
I assume Device-1 (app) is scanning and Device-2 is advertising. Try to bond the devices after first time connection. This allow you to connect it automatically without scanning next time.
Make sure the Device-2 is in connectable mode after getting disconnected from Device-1.
EDIT-1
For example I am using a generic app called nRF connect and a smart watch. In this app we can scan and connect with any BLE device. I am following below steps:
Scan
Connect
Bond (option available under 3 dots at top right corner, refer image)
After third step, device get bonded and later whenever the device is in vicinity you can connect with it, without advertising and scanning. PFA image.
This is the overview of process to be followed, in regards to code you can get many ready examples related to android or iOS. Hope this is helpful!!

Open video call flutter

Is there a solution yet for opening the video call function on the native phone in flutter? I have looked at Agora and others and none of them work the way we need them to.
That was rather annoying to research and come up with, here it goes. This is the best I can come up with while keeping high complexity and paid SDK's outside the solution.
First of all, you have to differentiate between the two platforms (iOS/Android) before initiating the video call. Since there's no uniform solution for both platforms AFAIK.
import 'dart:io';
if (Platform.isAndroid) {
// Android Video Call
} else if (Platform.isIOS) {
// iOS Video Call
}
iOS
Install the infamous url_launcher pub.
You'll need to use FaceTime Links (see full iOS URL Scheme Reference here or here)
Text example: facetime:14085551234 this initiates FaceTime video call to 14085551234 (you use email instead of phone number too)
import 'package:url_launcher/url_launcher.dart';
final String url = 'facetime:$phoneNumber';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
This works surprisingly well. In this case you can replace $phoneNumber variable with something like $userEmail variable.
Android
Install android_intent pub
Add CALL_PHONE permission and show its prompt to user if you're using android.intent.action.CALL, or just use android.intent.action.DIAL without the permission.
This is where the problem lies... I tried the following solution and it only worked for regular calls not video calls
import 'package:android_intent/android_intent.dart';
/// This acton calls the user directly via native phone app but requires `CALL_PHONE` permission in _AndroidManifest_.
final callIntentAction = 'android.intent.action.CALL';
/// This action displays native phone app with dial pad open showing the passed phone number intent's argument/extra. Does not require permissions as of Jan2020.
final dialIntentAction = 'android.intent.action.DIAL';
final intentAction = callIntentAction;
AndroidIntent intent = AndroidIntent(
action: intentAction,
data: Uri.encodeFull('tel:$phoneNumber'),
arguments: {
/// KEY: actual phone number to call [source](https://developer.android.com/reference/android/content/Intent.html#EXTRA_PHONE_NUMBER)
/// VALUE: phoneNumber
'android.intent.extra.PHONE_NUMBER': phoneNumber,
/// KEY: [START_CALL_WITH_VIDEO_STATE](https://developer.android.com/reference/android/telecom/TelecomManager.html#EXTRA_START_CALL_WITH_VIDEO_STATE)
/// VALUE: `3` implies [STATE_BIDIRECTIONAL](https://developer.android.com/reference/android/telecom/VideoProfile.html#STATE_BIDIRECTIONAL)
'android.telecom.extra.START_CALL_WITH_VIDEO_STATE': '3',
},
);
await intent.launch();
Error-handling side-note: unfortunately with android_intent pub there's no error handling or "canOpen" method like url_launcher.
Your problem still lies with Android as there's no native general-purpose video-call app.
You have a couple of options:
A. You can link with your app a video-calling SDK/capability either third-party or your own. (like flutter_webrtc, agora_flutter_webrtc, SightCall, quickblox). This has the downside that the callee has to be using the same software i.e. your app has to be installed on callee's device. This approach is more future-proof. Note I'm not affiliated with any of the libraries I mentioned.
B. You can make a platform method for Android to go over a defined set of intents and check the package name of known video-calling apps with the extra/arguments they require. You'd have to check the list of intents one by one and see which applies and resolves correctly. For apps like Google Duo, Whatsapp, Skype, etc.... This is EXTREMELY prone to errors. As explained here.

How to determine if flutter is running in simulator

Is there a call to determine if flutter is running within a simulator or a physical device?
I am scanning QR codes, and want to bypass, since the camera is unavailable.
I expected to find this in platform.dart[1] but it's not there.
[1]https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/foundation/platform.dart
I imagine I can create a plugin if I really need, I'm hoping it already exists.
Using the device info plus plugin you can get various information about the device you're running on, including 'isPhysicalDevice' for both Android and iOS (although you'll have to read them independently).
2021 Update
It‘s now part of Flutter Community Plus (https://plus.fluttercommunity.dev/)
Device Info Plus Docu: https://plus.fluttercommunity.dev/docs/device_info_plus/overview
e.g.:
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if(Platform.isIOS){
var iosInfo = await deviceInfo.iosInfo;
if(iosInfo.isPhysicalDevice){...}
}
I Know I'm A Bit Late, But If Anyone Else Comes Here, This Can Help Them.
You Can Just Use This Package:
https://pub.dev/packages/safe_device
Add The Latest Version In Your Pubspec.yaml File
Then import it:
import 'package:safe_device/safe_device.dart';
Then You Can Check If Device Is An Emulator:
bool isRealDevice = await SafeDevice.isRealDevice;
No.
But what you can do instead is use different configurations (such as a dev configuration).
For this you can use a different main.dart such as main.dev.dart and then run it with flutter run -t lib/main.dev.dart
I'm using https://pub.dev/packages/flutter_is_emulator
import 'package:flutter_is_emulator/flutter_is_emulator.dart';
....
bool isAnEmulator = await FlutterIsEmulator.isDeviceAnEmulatorOrASimulator;