Open Flutter Application Using Dynamic Links [closed] - android

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm building a flutter application, and am having some trouble actually opening the app using the firebase_dynamic_links package. I basically took the example code found at https://pub.dev/packages/firebase_dynamic_links#-example-tab- in order to get started, but changed the information in their example to match my own firebase project (which has been setup in both android and iOS, but this testing has all been done with iOS).
I will include code and more useful information below, but I was really just hoping to get a simplified example of how this process should work. I have searched online quite a bit, following different tutorials, but none of them have done the trick for me. It could just be that I'm quite new to flutter, and am missing basic things. In my final application, I will be using dynamic links to allow users to invite other users to join the app (as well as groups within the app) via text, just to give context as to why it is needed.
Here is the code for what I have so far, but as I mentioned it is largely based off of the example from the link above.
main.dart
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:shopsync/helloworld.dart';
void main() async {
//Setup firebase connection
WidgetsFlutterBinding.ensureInitialized();
final FirebaseApp app = await FirebaseApp.configure(
name: 'shop-sync-d97d8',
options: Platform.isIOS
? const FirebaseOptions(
googleAppID: 'my_googleAppID',
gcmSenderID: 'my_senderID',
databaseURL: 'https://shop-sync-d97d8.firebaseio.com',
apiKey: 'AIzaSyC1TdwTs_KRXMGG2oIAGMX8v48HWqS62dc',
)
: const FirebaseOptions(
googleAppID: 'my_googleAppID',
apiKey: 'myApiKey',
databaseURL: 'my_url',
),
);
runApp(MaterialApp(
title: 'Dynamic Links Example',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => _MainScreen(),
'/helloworld': (BuildContext context) => HelloWorldScreen(),
},
));
}
class _MainScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MainScreenState();
}
class _MainScreenState extends State<_MainScreen> {
String _linkMessage;
bool _isCreatingLink = false;
String _testString =
"To test: long press link and then copy and click from a non-browser "
"app. Make sure this isn't being tested on iOS simulator and iOS xcode "
"is properly setup. Look at firebase_dynamic_links/README.md for more "
"details.";
#override
void initState() {
super.initState();
initDynamicLinks();
}
void initDynamicLinks() async {
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
}
Future<void> _createDynamicLink(bool short) async {
setState(() {
_isCreatingLink = true;
});
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: "https://shopsync.page.link",
link: Uri.parse("https://shopsync.page.link/helloworld"),
androidParameters: AndroidParameters(
packageName: 'com.chrismcdonnell.shopsync',
minimumVersion: 0,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
),
iosParameters: IosParameters(
bundleId: 'com.chrismcdonnell.shopsync',
minimumVersion: '0',
),
);
Uri url;
if (short) {
final ShortDynamicLink shortLink = await parameters.buildShortLink();
url = shortLink.shortUrl;
} else {
url = await parameters.buildUrl();
}
setState(() {
_linkMessage = url.toString();
_isCreatingLink = false;
});
}
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: const Text('Dynamic Links Example'),
),
body: Builder(builder: (BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: !_isCreatingLink
? () => _createDynamicLink(false)
: null,
child: const Text('Get Long Link'),
),
RaisedButton(
onPressed: !_isCreatingLink
? () => _createDynamicLink(true)
: null,
child: const Text('Get Short Link'),
),
],
),
InkWell(
child: Text(
_linkMessage ?? '',
style: const TextStyle(color: Colors.blue),
),
onTap: () async {
if (_linkMessage != null) {
await launch(_linkMessage);
}
},
onLongPress: () {
Clipboard.setData(ClipboardData(text: _linkMessage));
Scaffold.of(context).showSnackBar(
const SnackBar(content: Text('Copied Link!')),
);
},
),
Text(_linkMessage == null ? '' : _testString)
],
),
);
}),
),
);
}
}
class _DynamicLinkScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: const Text('Hello World DeepLink'),
),
body: const Center(
child: Text('Hello, World!'),
),
),
);
}
}
helloworld.dart
//IMPORT NEEDED PACKAGES
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
//CREATE STATEFUL WIDGET
class HelloWorldScreen extends StatefulWidget {
#override
_HelloWorldScreen createState() => _HelloWorldScreen();
}
//CREATE STATE WIDGET
class _HelloWorldScreen extends State<HelloWorldScreen> {
#override
Widget build(BuildContext context) {
//Since this class represents an entire screen, return a scaffold with elements inside it
return Scaffold(
backgroundColor: Colors.white,
//Create AppBar w/ title "My Account"
appBar: AppBar(
title: Text('Hello World'),
automaticallyImplyLeading: false,
),
//Most of the content of the screen will go here
body: SafeArea(
child: Text('Testing'),
),
);
}
}
And lastly, here is the dynamic link I created within the console for testing. Although the final version of the application will create them programatically.
If anything else is needed please let me know. Any help would be greatly appreciated.

Related

Agora in Flutter- navigating to the video chat screen more than one time keeps local video loading forever

I am using Agora for a one-to-one video chat purpose in Flutter.
User1 has an app to go online and user2 has another app to go online. After both of them go online, they can do video chat with one another. Both apps have almost similar codebase.
I have a screen or activity (say screen1) where an alert dialog is shown on tapping a button (say button1). On tapping the Continue button in the alert dialog, the dialog disappears and the user is taken to the screen (say screen2) where the video chat takes place. But after going to the video chat screen successfully, if the user taps on the back button on the mobile set then s/he is taken to screen1 and after tapping on button1, if the user taps on the Continue button in the popped up alert dialog, the user is again taken to screen2 but this time the local video (i.e. video of the user using the app) keeps loading for ever. Obviously I want the local video to load as it did for the first time.
I am gonna put my code here in such a way that you can easily run that.
Following code is for user1. For user2, no alert box is there in the app. Same code from user1 is used for user2 app, except the value of remoteUid is set to be 2 for user2 while this value is set to be 1 for user1. These are just two values identifying 2 users.
For user1:
main.dart:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'livesession1to1.dart';
void main() {
runApp(MessagingExampleApp());
}
class NavigationService {
static GlobalKey<NavigatorState> navigatorKey =
GlobalKey<NavigatorState>();
}
/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging Example App',
navigatorKey: NavigationService.navigatorKey, // set property
theme: ThemeData.dark(),
routes: {
'/': (context) => Application(),
'/liveSession1to1': (context) =>LiveSession1to1(),
},
);
}
}
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String? token, String server_key) {
_messageCount++;
return jsonEncode({
'token': token,
'to':token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM! =============',
},
"delay_while_idle" : false,
"priority" : "high",
"content_available" : true
});
}
/// Renders the example application.
class Application extends StatefulWidget {
#override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
String? _token;
#override
void initState() {
super.initState();
}
showAlertDialog() {
BuildContext context=NavigationService.navigatorKey.currentContext!;
// set up the buttons
Widget cancelButton = TextButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget continueButton = TextButton(
child: Text("Continue"),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
Navigator.of(context).pushNamed('/liveSession1to1');
},
);
Timer? timer = Timer(Duration(milliseconds: 5000), (){
Navigator.of(context, rootNavigator: true).pop();
});
showDialog(
context: context,
builder: (BuildContext builderContext) {
return AlertDialog(
backgroundColor: Colors.black26,
title: Text('One to one live session'),
content: SingleChildScrollView(
child: Text('Do you want to connect for a live session ?'),
),
actions: [
cancelButton,
continueButton,
],
);
}
).then((value){
// dispose the timer in case something else has triggered the dismiss.
timer?.cancel();
timer = null;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My App'),
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: showAlertDialog,
backgroundColor: Colors.white,
child: const Icon(Icons.send),
),
),
body: SingleChildScrollView(
child: Text(
'Trigger Alert'
),
),
);
}
}
livesession1to1.dart:
import 'dart:async';
import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
// const appId = "<-- Insert App Id -->";
// const token = "<-- Insert Token -->";
const appId = "......";// Put Agora App ID from Agora site here
const token = "....";// Put token ( temporary token avilable from Agora site)
void main() => runApp(MaterialApp(home: LiveSession1to1()));
class LiveSession1to1 extends StatefulWidget {
#override
_LiveSession1to1State createState() => _LiveSession1to1State();
}
class _LiveSession1to1State extends State<LiveSession1to1> {
int _remoteUid=1;
bool _localUserJoined = false;
late RtcEngine _engine;
#override
void initState() {
super.initState();
setState(() {});
initAgora();
}
Future<void> initAgora() async {
// retrieve permissions
await [Permission.microphone, Permission.camera].request();
// Create RTC client instance
RtcEngineContext context = RtcEngineContext(appId);
_engine = await RtcEngine.createWithContext(context);
await _engine.enableVideo();
_engine.setEventHandler(
RtcEngineEventHandler(
joinChannelSuccess: (String channel, int uid, int elapsed) {
print("local user $uid joined");
setState(() {
_localUserJoined = true;
});
},
userJoined: (int uid, int elapsed) {
print("remote user $uid joined");
setState(() {
_remoteUid = uid;
});
},
userOffline: (int uid, UserOfflineReason reason) {
print("remote user $uid left channel");
setState(() {
// _remoteUid = null;
_remoteUid = 0;
});
},
),
);
try {
await _engine.joinChannel(token, "InstaClass", null, 0);
} catch (e) {
print("error with agora = ");
print("$e");
print("error printeddddd");
}
}
// Create UI with local view and remote view
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Agora Video Call'),
),
body: Stack(
children: [
Center(
child: _remoteVideo(),
),
Align(
alignment: Alignment.topLeft,
child: Container(
width: 100,
height: 150,
child: Center(
child: _localUserJoined
? RtcLocalView.SurfaceView()
: CircularProgressIndicator(),
),
),
),
],
),
);
}
// Display remote user's video
Widget _remoteVideo() {
if (_remoteUid != 0) {
return RtcRemoteView.SurfaceView(
uid: _remoteUid,
channelId: "InstaClass",
);
}else {
print("'Please wait for remote user to join',");
return Text(
'Please wait for remote user to join',
textAlign: TextAlign.center,
);
}
}
}
For user2:
main.dart:
import 'dart:async';
import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
const appId = "....."; // Same as user1 app
const token = "....."; // same as user1 app
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// int? _remoteUid=1;
int _remoteUid=2;
bool _localUserJoined = false;
late RtcEngine _engine;
#override
void initState() {
super.initState();
initAgora();
}
Future<void> initAgora() async {
// retrieve permissions
await [Permission.microphone, Permission.camera].request();
//create the engine
_engine = await RtcEngine.create(appId);
await _engine.enableVideo();
_engine.setEventHandler(
RtcEngineEventHandler(
joinChannelSuccess: (String channel, int uid, int elapsed) {
print("local user $uid joined");
setState(() {
_localUserJoined = true;
});
},
userJoined: (int uid, int elapsed) {
print("remote user $uid joined");
setState(() {
_remoteUid = uid;
});
},
userOffline: (int uid, UserOfflineReason reason) {
print("remote user $uid left channel");
setState(() {
// _remoteUid = null;
_remoteUid = 0;
});
},
),
);
// await _engine.joinChannel(token, "test", null, 0);
await _engine.joinChannel(token, "InstaClass", null, 0);
}
// Create UI with local view and remote view
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Agora Video Call'),
),
body: Stack(
children: [
Center(
child: _remoteVideo(),
),
Align(
alignment: Alignment.topLeft,
child: Container(
width: 100,
height: 150,
child: Center(
child: _localUserJoined
? RtcLocalView.SurfaceView()
: CircularProgressIndicator(),
),
),
),
],
),
);
}
// Display remote user's video
Widget _remoteVideo() {
/*if (_remoteUid != null) {
return RtcRemoteView.SurfaceView(uid: _remoteUid!);
}*/
if (_remoteUid != 0) {
return RtcRemoteView.SurfaceView(
uid: _remoteUid,
channelId: "InstaClass",
);
}else {
return Text(
'Please wait for remote user to join',
textAlign: TextAlign.center,
);
}
}
}
In order to get the app ID and token, login to Agora site. After logging in, go to the 'Project Management' section to see the projects already created there. Under the Functions column, click on the key symbol and you will be taken to a page where you can generate a temporary token. On that page, give the channel name input the value 'InstaClass' as I have used this name in my code.
How to make the video chat work smoothly after the first time it works well ?
I think the problem is that when pressing back button you are just being taken to the previous screen and the call session is not being end. You can try by leaving the channel when pressing back button like :
_engine.leaveChannel();
End Call button sample
ElevatedButton(
onPressed: () {
_rtcEngine.leaveChannel();
Navigator.pop(context);
},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
backgroundColor: MaterialStateProperty.all(Colors.red),
padding: MaterialStateProperty.all(
EdgeInsets.fromLTRB(15, 15, 15, 12)),
),
child: Icon(
Icons.phone,
size: 30,
),
)
Back Button override using WillPopScope
return WillPopScope(
onWillPop: () async {
_rtcEngine.leaveChannel();
return true;
},
child: Scaffold(
body: Container(),
),
);

ProviderNotFoundException was thrown building ConsumptionDialog because used `BuildContext` that does not include the provider

I'm a student and I don't learn mobile development at my school. I really appreciate it if anyone could help me. I dunno how to fix the error and I tried countless times.
Error: Could not find the correct Provider above this Builder Widget. This happens because you used a 'BuildContext' that does not include the provider of your choice.
The relevant error-causing widget was
ConsumptionDialog. 2 files were involved in this error.
1st File: consumption_dialog.dart
class ConsumptionDialog extends StatefulWidget {
#override
_ConsumptionDialogState createState() => _ConsumptionDialogState();
}
class _ConsumptionDialogState extends State<ConsumptionDialog> {
final _form = GlobalKey<FormState>();
String? _text;
String? _validateText(String? value) {
if (value == null) {
return "2000 ml minimun";
}
final number = int.tryParse(value);
if (number != null && number >= 2000) {
return null;
}
return "2000 ml minimum";
}
#override
Widget build(BuildContext context) {
final bloc = context.watch<WaterBloc>();
return AlertDialog(
title: Text(
"Daily consumption",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
content: Form(
key: _form,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Change your daily water consumption goal, in milliliters.",
textAlign: TextAlign.center,
),
SizedBox(height: 12),
TextFormField(
maxLength: 4,
initialValue: bloc.state.recommendedMilliliters.toString(),
keyboardType: TextInputType.number,
onSaved: (value) => _text = value,
validator: _validateText,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
hintText: "2000 ml",
counterText: "",
),
),
SizedBox(height: 24),
PrimaryButton(
onPressed: () {
if (_form.currentState?.validate() ?? false) {
_form.currentState?.save();
FocusScope.of(context).unfocus();
context.read<WaterBloc>().setRecommendedMilliliters(
int.parse(_text!),
);
Navigator.of(context).pop();
}
},
title: "Confirm",
),
SizedBox(height: 10),
SecondaryButton(
onPressed: () => Navigator.of(context).pop(),
title: "Cancel",
),
],
),
),
);
}
}
The error is shown inline:
Widget build(BuildContext context) {
final bloc = context.watch<WaterBloc>();
return AlertDialog(
2nd File: dialog.dart
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
import 'package:stayhydratedpal/widgets/confirmation_dialog.dart';
import 'package:stayhydratedpal/widgets/consumption_dialog.dart';
Future<bool> showConfirmationDialog(
BuildContext context, {
required String title,
required String content,
}) async {
final bool confirmed = await showModal(
context: context,
builder: (context) {
return ConfirmationDialog(
title: title,
content: content,
onConfirm: () => Navigator.of(context).pop(true),
onCancel: () => Navigator.of(context).pop(false),
);
},
) ??
false;
return confirmed;
}
Future<void> showConsumptionDialog(BuildContext context) {
return showModal(
context: context,
builder: (context) => ConsumptionDialog(),
);
}
The error is shown inline:
Future<void> showConsumptionDialog(BuildContext context) {
return showModal(
context: context,
builder: (context) => ConsumptionDialog(),
);
}
The way provider works is when you do Provider.of<T>(context)(The context must be a descendent of the widget where you injected T) it looks up the tree to find the T that you injected using Provider(create: (_)=> T())(can be ChangeNotifierProvider too doesn't matter). Also routes in the navigator stack aren't a parent of each other
they are
-> page1
-> page2
not
-> page1
-> page2
So this means when you use the Navigator to push a new page, Provider won't be able to find the injected provider you put on page1. And showModal uses Navigator push to open a dialog so basically just like any other route which means your ConfirmationDialog isn't finding the WaterBloc which you probably injected in the page you are opening it from.
One way to solve this is inject WaterBloc above the Navigator, MaterialApp contains the root navigator so inject the provider above Material App.
Another way is when opening the dialog you can do
Future<void> showConsumptionDialog(BuildContext context) {
return showModal(
context: context,
builder: (_) => Provider.value(
value: context.read<WaterBloc>(), // this context must be a descendent of the widget where you injected WaterBloc
child: ConsumptionDialog(),
),
);
}
A small tip, I would recommend you to learn Inherited Widgets a bit if you learn them well you can use Provider pretty easily, because Provider is just a wrapper over InheritedWidget

How to open my app by a link in a new tab?

I'm adding deep linking to my app, i'm using uni_links https://pub.dev/packages/uni_links.
everything works fine but the app opens in the same tab as the link, and not in a new one.
how can I make the app open in another tab?
example in the image: the app opens on the hangouts tab, instead of go back to it's own tab.
You should use flutter dynamic links
You should read this documentation enter link description here
current veriosn: firebase_dynamic_links: ^2.0.4
Example:
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MaterialApp(
title: 'Dynamic Links Example',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => _MainScreen(),
'/helloworld': (BuildContext context) => _DynamicLinkScreen(),
},
));
}
class _MainScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MainScreenState();
}
class _MainScreenState extends State<_MainScreen> {
String? _linkMessage;
bool _isCreatingLink = false;
String _testString =
'To test: long press link and then copy and click from a non-browser '
"app. Make sure this isn't being tested on iOS simulator and iOS xcode "
'is properly setup. Look at firebase_dynamic_links/README.md for more '
'details.';
#override
void initState() {
super.initState();
initDynamicLinks();
}
Future<void> initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData? dynamicLink) async {
final Uri? deepLink = dynamicLink?.link;
if (deepLink != null) {
// ignore: unawaited_futures
Navigator.pushNamed(context, deepLink.path);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
final PendingDynamicLinkData? data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
if (deepLink != null) {
// ignore: unawaited_futures
Navigator.pushNamed(context, deepLink.path);
}
}
Future<void> _createDynamicLink(bool short) async {
setState(() {
_isCreatingLink = true;
});
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://cx4k7.app.goo.gl',
link: Uri.parse('https://dynamic.link.example/helloworld'),
androidParameters: AndroidParameters(
packageName: 'io.flutter.plugins.firebasedynamiclinksexample',
minimumVersion: 0,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
),
iosParameters: IosParameters(
bundleId: 'com.google.FirebaseCppDynamicLinksTestApp.dev',
minimumVersion: '0',
),
);
Uri url;
if (short) {
final ShortDynamicLink shortLink = await parameters.buildShortLink();
url = shortLink.shortUrl;
} else {
url = await parameters.buildUrl();
}
setState(() {
_linkMessage = url.toString();
_isCreatingLink = false;
});
}
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: const Text('Dynamic Links Example'),
),
body: Builder(builder: (BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: !_isCreatingLink
? () => _createDynamicLink(false)
: null,
child: const Text('Get Long Link'),
),
ElevatedButton(
onPressed: !_isCreatingLink
? () => _createDynamicLink(true)
: null,
child: const Text('Get Short Link'),
),
],
),
InkWell(
onTap: () async {
if (_linkMessage != null) {
await launch(_linkMessage!);
}
},
onLongPress: () {
Clipboard.setData(ClipboardData(text: _linkMessage));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied Link!')),
);
},
child: Text(
_linkMessage ?? '',
style: const TextStyle(color: Colors.blue),
),
),
Text(_linkMessage == null ? '' : _testString)
],
),
);
}),
),
);
}
}
class _DynamicLinkScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: const Text('Hello World DeepLink'),
),
body: const Center(
child: Text('Hello, World!'),
),
),
);
}
}

This happens because you used a `BuildContext` that does not include the provider of your choice

I am Working on Flutter App Both for web and mobile and stuck at the Following Error:
======== Exception caught by widgets library =======================================================
The following ProviderNotFoundException was thrown building Products(dirty):
Error: Could not find the correct Provider<List<ProductsModel>> above this Products Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that Products is under your MultiProvider/Provider<List<ProductsModel>>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
```
consider using `builder` like so:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
```
The relevant error-causing widget was:
Products file:///E:/Flutter%20Projects/flutter_web_firebase_host/lib/screens/home/home.dart:37:63
When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49 throw_
packages/provider/src/provider.dart 332:7 _inheritedElementOf
packages/provider/src/provider.dart 284:30 of
packages/flutter_web_firebase_host/screens/databaseScreens/products.dart 10:31 build
packages/flutter/src/widgets/framework.dart 4569:28 build
...
====================================================================================================
Main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:flutter_web_firebase_host/provider/product_provider.dart';
import 'package:flutter_web_firebase_host/screens/wrapper.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final firestoreServise = FirestoreService();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
/* child: StreamProvider<Users>.value(
value: AuthService().user,
initialData: null*/
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
),
);
// );
}
Product.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/edit_product.dart';
import 'package:provider/provider.dart';
class Products extends StatelessWidget {
#override
Widget build(BuildContext context) {
final products = Provider.of<List<ProductsModel>>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text('Products'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => EditProduct()));
}),
],
),
body: (products != null)
? ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
trailing: Text(products[index].price.toString()),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditProduct(products[index])));
},
);
},
)
: Center(child: CircularProgressIndicator()));
}
}
Home.dart
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/products.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/shared/drawer.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
backgroundColor: Colors.brown[100],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[100],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
await _auth.signOut();
},
),
IconButton(
icon: Icon(Icons.add, color: Colors.black),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Products()));
}),
],
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50, 0, 0),
child: Container(
child: Text(
'Stock Market',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
)),
),
),
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Image.asset(
"assets/graph.jpg",
width: 500,
height: 600,
),
),
),
],
),
),
),
drawer: MyDrawer(),
),
);
}
}
product_provider.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:uuid/uuid.dart';
class ProductProvider with ChangeNotifier {
final firestoreService = FirestoreService();
String _name;
double _price;
String _productId;
var uuid = Uuid();
//Geters
String get name => _name;
double get price => _price;
//Seters
changeName(String value) {
_name = value;
notifyListeners();
}
changePrice(String value) {
_price = double.parse(value);
notifyListeners();
}
loadValues(ProductsModel product) {
_name=product.name;
_price=product.price;
_productId=product.productId;
}
saveProduct() {
print(_productId);
if (_productId == null) {
var newProduct = ProductsModel(name: name, price: price, productId: uuid.v4());
firestoreService.saveProduct(newProduct);
} else {
//Update
var updatedProduct =
ProductsModel(name: name, price: _price, productId: _productId);
firestoreService.saveProduct(updatedProduct);
}
}
}
Authservise.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Users _userFromFirebaseUser(User user) {
return user != null ? Users(uid: user.uid) : null;
}
// auth change user stream
Stream<Users> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user;
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
//sign in with google
Future<bool> loginWithGoogle() async {
try {
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount account = await googleSignIn.signIn();
if(account == null )
return false;
UserCredential res = await _auth.signInWithCredential(GoogleAuthProvider.credential(
idToken: (await account.authentication).idToken,
accessToken: (await account.authentication).accessToken,
));
if(res.user == null)
return false;
return true;
} catch (e) {
print(e.message);
print("Error logging with google");
return false;
}
}
}
Basically my app is connect to firebase both for web app and android app. Also i send data to firestore from my app but when i click the add button to go to textfield to send data it give the error as i mention it in start. I am using multiprovider as you can see my main.dart code
Is There anything I missing. I need Help.
the way to fix this is to put MultiProvider as parent of myApp in your main like this
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
child:MyApp(
));

Methods are not getting executed in the written order inside onPressed

Im trying to create a flutter app with a simple raised button that does the following:
sends an sms in the background using the sms package opens a webpage
2. in the app(only for 5 seconds) using url_launcher opens the phones
3. native app for making a voice call with the onPressed property.
And I wanted it to be in this order so that I can make the phone call at the end. However, the inside the onPressed opens the native phone call app first, which doesnt let my web page open unless I exit out of the phone call app.
Im having a hard time understanding why the phone call native app is opened first, even though I make the call the _makePhoneCall() method only after I make the _launchInApp(toLaunch) call. sendSMS() is being called correctly
How can I set this in a way that the phone call native app is called only after the webpage is opened in the app and follows the order? Any help would be great
Below is the piece of code:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:sms/sms.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Packages testing',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Packages testing'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _phone = '';
_launchInApp(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
headers: <String, String>{'my_header_key': 'my_header_value'},
);
} else {
throw 'Could not launch $url';
}
}
_makePhoneCall(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
void sendSMS() {
SmsSender sender = new SmsSender();
sender.sendSms(new SmsMessage(_phone, 'Testing Handset'));
}
#override
Widget build(BuildContext context) {
const String toLaunch = 'https://flutter.dev/';
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
onChanged: (String text) => _phone = text,
decoration:
const InputDecoration(hintText: 'Phone Number')),
),
FlatButton(
onPressed: () => setState(() {
sendSMS();
_launchInApp(toLaunch);
_makePhoneCall('tel:$_phone');
}),
child: const Text('Run All'),
),
const Padding(padding: EdgeInsets.all(16.0)),
],
),
],
),
);
}
}
You will have to use the await keyword before the _launchInApp function to make it work properly. Try the following code.
FlatButton(
onPressed: () aync {
sendSMS();
await _launchInApp(toLaunch);
_makePhoneCall('tel:$_phone');
}),
child: const Text('Run All'),
),
You created async functions but when you called them you did not specify that you want to wait for them to complete. Add the await keyword in OnPressed

Categories

Resources