Issue Connecting AWS Amplify to Flutter App - flutter

I am trying to connect my AWS amplify data model to my flutter app and have followed all the configuration steps (as per this video: https://www.youtube.com/watch?v=9UjP_TJOY5E&t=642s), however, when I go to run the app in Chrome, I get the following error. error message.
I have imported all the relevant amplify packages:
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:amplify_datastore/amplify_datastore.dart';
And this is my configuration function:
void _configureAmplify() {
final provider = ModelProvider();
final dataStorePlugin = AmplifyDataStore(modelProvider: provider);
try {
Amplify.addPlugin(dataStorePlugin);
Amplify.configure(amplifyconfig);
debugPrint('Amplify Configured');
} catch (e) {
debugPrint('$e');
}
}
I have also tried running the app on an android emulator, but this does not work either.
Please let me know how I should approach fixing this problem. Thanks!

UPDATE: I also made this video to help you out --> https://www.youtube.com/watch?v=ooCc5wdVyMo
Addition to our discussions on the comment section. I recommend calling the _configureAmplify function from the main function. You can call it like the following:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await _configureAmplify();
runApp(const AmplifyGroceryListApp());
}
Future<void> _configureAmplify() async {
// Add the following lines to your app initialization to add the DataStore plugin
final datastorePlugin = AmplifyDataStore(modelProvider: ModelProvider.instance);
await Amplify.addPlugin(datastorePlugin);
try {
await Amplify.configure(amplifyconfig);
} on AmplifyAlreadyConfiguredException {
safePrint(
'Tried to reconfigure Amplify; this can occur when your app restarts on Android.');
}
}

Related

Flutter - Firebase Dynamic Link not Working while app is in kill mode

I have integrated Firebase Dynamic link in my Flutter application to open and navigate application users to specific screen in app.
For that first of all I have added below plugin in pubspec.yaml file:
firebase_dynamic_links: ^5.0.5
Then, I have created a separate class to handle related stuffs as below:
class DynamicLinkService {
late BuildContext context;
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
Future<void> initDynamicLinks(BuildContext context) async {
this.context = context;
dynamicLinks.onLink.listen((dynamicLinkData) {
var dynamicLink=dynamicLinkData.link.toString();
if (dynamicLink.isNotEmpty &&
dynamicLink.startsWith(ApiConstants.baseUrl) &&
dynamicLink.contains("?")) {
//Getting data here and navigating...
...
...
...
}
}).onError((error) {
print("This is error >>> "+error.message);
});
}
}
Now, I am initialising Deep-link as below in my home_screen:
final DynamicLinkService _dynamicLinkService = DynamicLinkService();
and then calling below method in initState()
#override
void initState() {
SchedulerBinding.instance.addPostFrameCallback((_) async {
await _dynamicLinkService.initDynamicLinks(context);
});
}
This is working like a charm! when my application is in recent mode or in background mode.
But the issue is when the application is closed/Killed, clicking on dynamic link just open the app but could not navigate.
What might be the issue? Thanks in advance.
Let me answer my own question, It might be useful for someone!
So, In above code I forgot to add code to handle dynamic link while the app is in closed/kill mode.
We need to add this code separately:
//this is when the app is in closed/kill mode
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
handleDynamicLink(initialLink);
}
So, final code looks like as below:
//this is when the app is in closed/kill mode
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
handleDynamicLink(initialLink);
}
//this is when the app is in recent/background mode
dynamicLinks.onLink.listen((dynamicLinkData) {
handleDynamicLink(dynamicLinkData);
}).onError((error) {
print("This is error >>> "+error.message);
});
Its working like a charm now! That's All.

FlutterDriver.Connect Requires VM_SERVICE_URL or String?

My app is the basic counter, with a FlutterDriver for UI Automation. My conundrum is when I attempt to run my test, it tells me that I need to specify a connection or set the VM_SERVICE_URL
ERROR:
DriverError: Could not determine URL to connect to application. Either
the VM_SERVICE_URL environment variable should be set, or an explicit
URL should be provided to the FlutterDriver.connect() method.
I've tried a few things.
Using FlutterDriver.connect();
Setting the VM_SERVICE_URL in Terminal (MacOS)
Setting the Dart Command Line to include VM_SERVICE_URL with a value
The most success I've had is with the code below. By adding enableFlutterDriverExtension to the lib/main.dart, then executing lib/main.dart, I can copy/paste the ws://127.0.0.1 connection into the test/my_test.dart. This allows me to successfully run my tests, but this isn't an ideal process.
Is there a way to pull in the connection string automatically?
Why does Platform.environment['VM_SERVICE_URL'] always return null despite my having set it?
lib/main.dart
void main() {
enableFlutterDriverExtension();
runApp(const MyApp());
}
test/main_app.dart
void main() {
// enableFlutterDriverExtension();
MainApp.main();
MyTest.main();
}
test/my_test.dart
void main() {
FlutterDriver? driver;
dynamic DartVmServiceUrl;
DartVmServiceUrl ??= Platform.environment['VM_SERVICE_URL'];
print('VM_SERVICE_URL:\t${DartVmServiceUrl}');
String vmServURL = 'ws://127.0.0.1:59488/WK8KTNVXXOo=/ws';
setUpAll( () async {
driver = await FlutterDriver.connect(dartVmServiceUrl: vmServURL);
});
tearDownAll( () {
driver?.close();
});
test('Push Button',() async {
var pushMeButton = find.byValueKey('IncrementButton');
await driver!.tap(pushMeButton);
} );
}
you have to move the files in the specific folders you see below, then try to run from terminal with
flutter drive \
--driver=test/my_test.dart \
--target=test_driver/test_driver.dart
in your lib/main.dart you don't need enableFlutterDriverExtension(); because it is already linked to your main() in the test_driver.dart
also your main in test_driver/test_driver.dart should look like this:
import 'package:{here}/main.dart' as app; // insert here your main app
import 'package:flutter_driver/driver_extension.dart';
void main() {
enableFlutterDriverExtension();
app.main();
}
your my_test.dart should look like this:
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
late FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() {
driver.close();
});
test('check flutter driver health', () async {
Health health = await driver.checkHealth();
print(health.status);
});
}
give attention to use the correct packages to avoid this error.
Error: Not found: 'dart:ui'
import 'dart:ui';

how to save data in Hive database when receiving data in the background?

I have an issue saving data to Hive when receiving Firebase Cloud Messaging (FCM) push notification data when the app is in the background.
I have a static method to set up hive like this
static Future<void> setUpHive() async {
try {
await Hive.initFlutter();
if (!Hive.isBoxOpen("Box Name")) {
await Hive.openBox("Box Name");
}
} catch (error) {
print(error.toString());
}
}
I use that setUpHive static method in main function like this
Future<void> main() async {
await HiveHelper.setUpHive();
runApp(
MyApp(),
);
}
when the app is in the background, and then it receives FCM message, then this code below will be called. after that I try change the data stored in the Hive box
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// when receive FCM message when app is in the background, this block will be executed
// set up the hive first
await HiveHelper.setUpHive();
// then I try to change the data stored in the Hive box
final myBox = Hive.box("BOX NAME");
myBox.put("key", 12345);
}
it seems okay after receiving FCM background data, but when I fully close the app, and the main called again I have error when trying to open the box like this
static Future<void> setUpHive() async {
try {
await Hive.initFlutter();
if (!Hive.isBoxOpen("Box Name")) {
await Hive.openBox("Box Name"); // Error in this line
}
} catch (error) {
print(error.toString());
}
}
the error is:
HiveError: This should not happen. Please open an issue on GitHub.
E/flutter (13142): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)]
Unhandled Exception: HiveError: This should not happen. Please open an
issue on GitHub. E/flutter (13142): #0 BinaryReaderImpl.readFrame
(package:hive/src/binary/binary_reader_impl.dart:250:7)
E/flutter
I try to find the solution, and I find similar issue from here about Using Hive DB in a Background Process and it is said
leisim:
Unfortunately, Hive does not support opening boxes in multiple
isolates. That means you can either close the box in the main isolate,
update it in your background isolate and reopen it in the main isolate
or you pass the data from the background to the main isolate and
perform the update there...
I am new in Flutter, and I don't understand what he said. please help :(
You can try the following code. The basic idea is to send data from background isolate to main isolate.
Future<void> backgroundMessageHandler(RemoteMessage msg){
IsolateNameServer.lookupPortByName('main_port')?.send(msg);
}
#override
void initState(){
super.initState();
ReceivePort receivePort = ReceivePort();
IsolateNameServer.registerPortWithName(receivePort.sendPort,'main_port');
receivePort.listen((message) {
if(message is RemoteMessage){
//TODO: save your data in hive box
}
}
}
You need to close your hive box in the main isolate once app goes into background. When it does, you need to CRUD in the background isolate. If you want to sync data between two isolates (because they don't share the same hive data) then you need a two way communication between isolates.
Here is an example code of communicating between two isolates.
import 'dart:io'; // for exit();
import 'dart:async';
import 'dart:isolate';
Future<SendPort> initIsolate() async {
Completer completer = new Completer<SendPort>();
ReceivePort isolateToMainStream = ReceivePort();
isolateToMainStream.listen((data) {
if (data is SendPort) {
SendPort mainToIsolateStream = data;
completer.complete(mainToIsolateStream);
} else {
print('[isolateToMainStream] $data');
}
});
Isolate myIsolateInstance = await Isolate.spawn(myIsolate, isolateToMainStream.sendPort);
return completer.future;
}
void myIsolate(SendPort isolateToMainStream) {
ReceivePort mainToIsolateStream = ReceivePort();
isolateToMainStream.send(mainToIsolateStream.sendPort);
mainToIsolateStream.listen((data) {
print('[mainToIsolateStream] $data');
exit(0);
});
isolateToMainStream.send('This is from myIsolate()');
}
void main() async {
SendPort mainToIsolateStream = await initIsolate();
mainToIsolateStream.send('This is from main()');
}
for more go to https://medium.com/#lelandzach/dart-isolate-2-way-communication-89e75d973f34

flutter opening a Hive box gives error -says box not found, Did you forget to call Hive openbox()

I have a class where I am doing the graphql setup and the hive box setup. Here is the class -
class GraphQLConfiguration {
ValueNotifier<GraphQLClient> client = new ValueNotifier<GraphQLClient>(
GraphQLClient(
cache:
GraphQLCache(store: HiveStore(Hive.box(HiveStore.defaultBoxName))),
link: HttpLink('http://localhost:4000/graphql/',),
),
);
GraphQLConfiguration() {
initializeHive();
}
void initializeHive() async {
await initHiveForFlutter(); // or await initHiveForFlutter();
await Hive.openBox('bolBox');
}
}
Now I initialize this class in the Flutter main method -
Future main() async {
GraphQLConfiguration graphql = new GraphQLConfiguration();
}
When I run this code I get this error message -
Error - Unhandled Exception: HiveError: Box not found. Did you forget to call Hive.openBox()?
I followed this post as well Box not found. Did you forget to call Hive.openBox()?, didn't help.
Initialize Hive by giving it a home directory by using path_provider
final Directory appDocDir = await getApplicationDocumentsDirectory();
Hive.init(appDocDir.path);
then open box
await Hive.openBox('bolBox');
Add initHiveForFlutter in your root folder & it solve the problem.
void main() async{
await initHiveForFlutter();
runApp(MyApp());
}
Worked for me.
No need to initialise with open box & path as GraphQl handles that internally inside initHiveForFlutter.

Flutter How To Ensure a Function is Called Whenever App Hot Reloads in Android Studio?

I have a Flutter App that relies on a correct Server URL being set based on the environment it is running in. However, my function seems to not be called during Hot reloads.
I have at the top of my main.dart:
String TARGET_URL; /// TODO: Replace once figure out how to set environment Variables based on type of device.
void setTargetURLForEnv() async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isIOS) {
IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
if (iosDeviceInfo.isPhysicalDevice) {
TARGET_URL = 'http://aws-server-url.com';
} else {
TARGET_URL = 'http://localhost:6900';
}
}
}
void main() async {
runApp(App());
setTargetURLForEnv();
}
Hot Reloads cause TARGET_URL to be null, even when running on a iOS simulator. How do I force this method to be called?
Try setTargetURLForEnv() above the runApp(App()). I think because it is outside the App(), hot reloading the app won't execute the function. Try hot restart ('R') instead of hot reload in terminal.