I am using uni_links to get deeplink form other apps and trying to open the url in app using flutter_web_browser but when I open the app through deeplink it does not open the url instead its throwing an error called "dependOnInheritedWidgetOfExactType<_InheritedTheme>() or dependOnInheritedElement() was called before _HomeState.initState() completed." Below is my main.dart and homepage.dart
main.dart
import 'package:flutter/material.dart';
import 'home_widget.dart';
void main(){
runApp(new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'title',
theme: ThemeData(
// Define the default Brightness and Colors
brightness: Brightness.light,
primaryColor: Colors.deepOrange[800],
accentColor: Colors.orange[600],
),
home: Home(),
));
}
Homepage.dart
class Home extends StatefulWidget {
const Home({
Key key,
}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
String _latestLink = 'Unknown';
Uri _latestUri;
StreamSubscription _sub;
UniLinksType _type = UniLinksType.string;
#override
void initState(){
super.initState();
initPlatformState();
}
initPlatformState() async {
if (_type == UniLinksType.string) {
await initPlatformStateForStringUniLinks();
} else {
await initPlatformStateForUriUniLinks();
}
}
initPlatformStateForStringUniLinks() async {
// Attach a listener to the links stream
_sub = getLinksStream().listen((String link) {
if (!mounted) return;
setState(() {
_latestLink = link ?? 'Unknown';
_latestUri = null;
try {
if (link != null) _latestUri = Uri.parse(link);
} on FormatException {}
});
}, onError: (err) {
if (!mounted) return;
setState(() {
_latestLink = 'Failed to get latest link: $err.';
_latestUri = null;
});
});
// Attach a second listener to the stream
getLinksStream().listen((String link) {
print('got link: $link');
// launchURL(link);
}, onError: (err) {
print('got err: $err');
});
// Get the latest link
String initialLink;
Uri initialUri;
launchURL(initialLink);
// Platform messages may fail, so we use a try/catch PlatformException.
try {
initialLink = await getInitialLink();
if (initialLink != null) initialUri = Uri.parse(initialLink);
print('initial link: $initialLink');
} on PlatformException {
initialLink = 'Failed to get initial link.';
initialUri = null;
print(initialLink);
} on FormatException {
initialLink = 'Failed to parse the initial link as Uri.';
initialUri = null;
print(initialLink);
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_latestLink = initialLink;
_latestUri = initialUri;
});
}
initPlatformStateForUriUniLinks() async {
// Attach a listener to the Uri links stream
_sub = getUriLinksStream().listen((Uri uri) {
if (!mounted) return;
setState(() {
_latestUri = uri;
_latestLink = uri?.toString() ?? 'Unknown';
});
}, onError: (err) {
if (!mounted) return;
setState(() {
_latestUri = null;
_latestLink = 'Failed to get latest link: $err.';
});
});
// Attach a second listener to the stream
getUriLinksStream().listen((Uri uri) {
print('got uri: ${uri?.path} ${uri?.queryParametersAll}');
}, onError: (err) {
print('got err: $err');
});
// Get the latest Uri
Uri initialUri;
String initialLink;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
initialUri = await getInitialUri();
print('initial uri: ${initialUri?.path}'
' ${initialUri?.queryParametersAll}');
initialLink = initialUri?.toString();
} on PlatformException {
initialUri = null;
initialLink = 'Failed to get initial uri.';
} on FormatException {
initialUri = null;
initialLink = 'Bad parse the initial link as Uri.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_latestUri = initialUri;
print("latestUri : $_latestUri");
_latestLink = initialLink;
print("latestLink: $_latestLink");
});
}
launchURL(link) async {
await FlutterWebBrowser.openWebPage(url: link,androidToolbarColor: Theme.of(context).primaryColor);
}
#override
Widget build(BuildContext context){
return Scaffold(...)
}
#override
void dispose() {
// _bannerAd?.dispose();
super.dispose();
}
Try to call initPlatformState() after initState() has completed.
Something like this:
#override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
initPlatformState();
});
}
Another workaround is by adding a frame callback, which is better than using Future.delayed with a zero duration.
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
initPlatformState();
});
}
It is more explicit and clear as to what is happening. This kind of situation is what frame callback was designed for.
Related
I'm using awesome_notifications and flutter_background_service in conjunction to update some app state when receiving data notifications from FirebaseMessaging. As noted in the awesome_notifications, the background message handler must be a top-level function, so I am using flutter_background_service to pass data to the main isolate and update app state.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeBackgroundService();
FirebaseMessaging.onBackgroundMessage(_backgroundMessageHandler);
_initLocalNotifications();
runApp(MyApp());
}
I'm initializing the background service similarly to the example in flutter_background_service:
Future<void> initializeBackgroundService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onStart,
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStart,
onBackground: onIosBackground,
),
);
await service.startService();
}
and invoking update in the _backgroundMessageHandler when a notification is received:
Future<void> _backgroundMessageHandler(
RemoteMessage message,
) async {
final service = FlutterBackgroundService();
...
service.invoke('update', {
'key1': 'val1',
'key2': 'val2',
});
}
And in the StatefulWidget for my app in the main isolate, I'm listening on the update call to receive the data:
void listenForNotificationData() {
final backgroundService = FlutterBackgroundService();
backgroundService.on('update').listen((event) async {
print('received data message in feed: $event');
}, onError: (e, s) {
print('error listening for updates: $e, $s');
}, onDone: () {
print('background listen closed');
});
}
It's never invoking the listen callback on the 'update' event. I can confirm it's calling the invoke('update') portion and calling on('update').listen, but never receiving the update. It also doesn't seem to be erroring out. Am I missing a step somewhere here?
I was encountering the same issue on flutter background service. I solved it by removing the async keyword from the callback and creating a separate async function to perform the callback operations.
void listenForNotificationData() {
final backgroundService = FlutterBackgroundService();
backgroundService.on('update').listen((event) {
print('received data message in feed: $event');
}, onError: (e, s) {
print('error listening for updates: $e, $s');
}, onDone: () {
print('background listen closed');
});
}
void action(Map? event) async {
print('received data message in feed: $event');
}
Hope it helps, forgive me if there are syntax error
You can try this.
main(){
....
}
Future<void> readyForShared() async {
var sharedPreferences = await SharedPreferences.getInstance();
counterValue = sharedPreferences.getString("yourVariable") ?? "0";
}
Future<void> saveData(String value) async {
var sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("yourVariable", value);
}
#pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setString("hello", "world");
/// OPTIONAL when use custom notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
service.stopSelf();
});
// bring to foreground
Timer.periodic(const Duration(seconds: 1), (timer) async {
final receivePort = ReceivePort();
// here we are passing method name and sendPort instance from ReceivePort as listener
await Isolate.spawn(computationallyExpensiveTask, receivePort.sendPort);
if (service is AndroidServiceInstance) {
if (await service.isForegroundService()) {
//It will listen for isolate function to finish
// receivePort.listen((sum) {
// flutterLocalNotificationsPlugin.show(
// 888,
// 'Title',
// 'Description ${DateTime.now()}',
// const NotificationDetails(
// android: AndroidNotificationDetails(
// 'my_foreground',
// 'MY FOREGROUND SERVICE',
// icon: 'ic_bg_service_small',
// ongoing: true,
// ),
// ),
// );
// });
var sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.reload(); // Its important
service.setForegroundNotificationInfo(
title: "My App Service",
content: "Updated at ${sharedPreferences.getString("yourVariable") ?? 'no data'}",
);
}
}
/// you can see this log in logcat
if (kDebugMode) {
// print('FLUTTER BACKGROUND SERVICE: ${deee.toString()}');
}
// test using external plugin
final deviceInfo = DeviceInfoPlugin();
String? device;
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
device = androidInfo.model;
}
if (Platform.isIOS) {
final iosInfo = await deviceInfo.iosInfo;
device = iosInfo.model;
}
service.invoke(
'update',
{
"current_date": '400',
"device": device,
},
);
});
}
....
....
....
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
readyForShared(); // init shared preferences
});
}
...
...
...
ElevatedButton(onPressed:(){saveData('Your Updated data.');}....
I wrote an one-page desktop app to communicate with TCP Server.
In my code, I use Socket.listen() method to receive data and it is OK.
I used single subscription and it was enough for me.
I tried to convert it to StreamProvider[Riverpod] and I failed.
I used StreamController() then I get bad state.
I used StreamController.broadcast() and I couldn't get data from socket
Could you suggest me correct way?
For a side note: I'm not an experienced flutter developer, just try to learn :)
I added code blocks to below and also full code.
For the full code: https://gist.github.com/sphinxlikee/3cbfa47817a5187c7b67905028674041
UI:
Working code;
Future<void> createConnection() async {
try {
_socket = await Socket.connect(serverAddress, serverPort);
_changeConnectionState();
} catch (e) {
print('connection has an error and socket is null.');
print(e);
return;
}
listenSocket();
}
void listenSocket() {
_socket.listen(
(event) {
_getData(String.fromCharCodes(event));
print('received: $receivedData');
if (!_dataReceived) {
_changeDataReceivedState();
}
},
)
..onDone(
() {
_changeConnectionState();
_streamDone();
print('socket is closed');
},
)
..onError(
(error, stackTrace) {
print('$error');
},
);
}
Working code - UI side
class ReceivedData extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final receivedData = watch(tcpClientProvider).receivedData;
return Text('Received data: $receivedData');
}
}
For the StreamProvider I tried,
Future<void> createConnection() async {
try {
_socket = await Socket.connect(serverAddress, serverPort);
streamController.sink.add(_socket.listen((event) => String.fromCharCodes(event)));
_changeConnectionState();
} catch (e) {
print('connection has an error and socket is null.');
print(e);
return;
}
}
StreamProvider - UI side
final streamProvider = StreamProvider.autoDispose(
(ref) async* {
await for (final value in ref.watch(tcpClientProvider).streamController.stream) {
yield value;
}
},
);
class ReceivedDataWithProvider extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
AsyncValue receivedData = watch(streamProvider);
return receivedData.when(
data: (data) => Text('Received data: $data'),
loading: () => const CircularProgressIndicator(),
error: (err, stack) => Text('error'),
);
}
}
Socket implements Stream, so you could just write:
final streamProvider = StreamProvider.autoDispose<Uint8List>((ref) {
return ref.watch(tcpClientProvider)._socket;
});
If you still want to add a listener, there's no harm in having one if you need:
final streamProvider = StreamProvider.autoDispose<Uint8List>((ref) {
final client = ref.watch(tcpClientProvider);
return client._socket
..listen(
(event) {},
).onDone(
() {
client
.._changeConnectionState()
.._streamDone();
print('socket is closed');
},
);
});
AS I am new to flutter, I can't find why the SnackBar is not showing on my UI while I am calling different function for API call! In one case it is showing but not in other cases.
I have to show a Snackbar on success of each API call (like in my project it is on success of generateOtp and on success of verifyOtp).
Below is my code.
snackbar.dart
showInSnackBar(String message, key){
key.currentState.showSnackBar(
SnackBar(
content:Text(message),
backgroundColor: Colors.blueAccent[700],
)
);
}
api_service.dart
class ApiService {
bool isVerified = false;
BaseOptions options = BaseOptions(
baseUrl: "http://...",
);
generateOtp(String mobileNo, key) async {
Dio dio = new Dio(options);
FormData formData = FormData.fromMap({'mobile_no': mobileNo});
try {
Response response = await dio.post("generate_otp/", data: formData);
if (response.statusCode == 200) {
// on success of generate otp I have to show a message on SnackBar. But it is not working.
showInSnackBar(response.data["msg"], key);
print(response.data);
}
} on DioError catch (e) {
showInSnackBar(e.message, key);
}
}
Future<bool> verifyOtp(String mobileNo, String otp, key) async {
Dio dio = new Dio(options);
FormData formData = FormData.fromMap(
//.....);
try {
Response response = await dio.post("verify_otp/", data: formData);
if (response.statusCode == 200) {
// here also it is not working.
showInSnackBar(response.data["msg"], key);
// Otp verified
isVerified = true;
}
} on DioError catch (e) {
showInSnackBar(e.message, key);
}
return isVerified;
}
}
register.dart
class _RegisterPageState extends State<RegisterPage> {
var _key = new GlobalKey<ScaffoldState>();
//...........
service.generateOtp(_data.mobileNo, _key); /* here I am calling generateOtp() */
} else {
print('invalid credentials');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key,
body: SingleChildScrollView(
//..........
otp.dart
submit() async {
_formKey.currentState.save();
bool verify =
await service.verifyOtp(widget.mobNumber, pinController.text, _key); /* here I am calling
verifyOtp() */
if (verify) {
SharedPreferences preferences = await SharedPreferences.getInstance();
String userInfo = preferences.getString('user_data');
// Decoding String data to map
Map map = json.decode(userInfo);
service.registerUser(map);
} else {
showInSnackBar('Invalid otp', _key); /* here SnackBar is showing on my UI*/
}
}
Can anybody please help me to solve this!
Lack of context, (Context).
docs : https://api.flutter.dev/flutter/widgets/BuildContext-class.html
try this(work for me):
void _showSnackBar(BuildContext context, String text) {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(text)));
}
If You want to use snackbar without context u can use this package get: ^3.13.2
and call snackbar like this any where you want:
Get.snackbar(
"title",
"content",
);
I am trying to use this plugin https://pub.dev/packages/connectivity/example Issue is its not showing or print internet is connected or not.
This is my code
class _HomePageState extends State<HomePage> {
String _connectionStatus = 'Unknown';
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult> _connectivitySubscription;
#override
void initState() {
super.initState();
initConnectivity();
_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (mounted) {
if (userManager.getCurrentDriver() != null &&
userManager.getCurrentDriver().isNotEmpty) {
FirebaseFirestore.instance
.collection(FIREBASE_PATH_TRIP)
.doc(userManager.getCurrentDriver())
.get()
.then((event) {
if (event != null) {
var trip =
DriverModel.fromMap(Map<String, dynamic>.from(event.data()));
Provider.of<TripState>(context, listen: false).driver = trip;
Provider.of<BottomSheetSelector>(context, listen: false)
.changeSheet(SheetType.Profile);
} else {
userManager.saveCurrentDriver('');
}
});
}
if (Theme.of(context).platform == TargetPlatform.android) {
checkForAndroidUpdate(context);
}
}
});
}
#override
void dispose() {
_connectivitySubscription.cancel();
super.dispose();
}
Future<void> initConnectivity() async {
ConnectivityResult result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await _connectivity.checkConnectivity();
} on PlatformException catch (e) {
print(e.toString());
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return Future.value(null);
}
return _updateConnectionStatus(result);
}
#override
Widget build(BuildContext context) {
final _drawerKey = GlobalKey<ScaffoldState>();
ScreenUtil.init(context);
return SafeArea(
child: WillPopScope(
child: Scaffold(
key: _drawerKey,
backgroundColor: Colors.black,
resizeToAvoidBottomInset: false,
drawer: ViteDrawer(),
body: null,
),
));
}
Future<void> _updateConnectionStatus(ConnectivityResult result) async {
switch (result) {
case ConnectivityResult.wifi:
case ConnectivityResult.mobile:
case ConnectivityResult.none:
setState(() => _connectionStatus = result.toString());
break;
default:
setState(() => _connectionStatus = 'Failed to get connectivity.');
break;
}
}
}
What i need to do is simple print if internet is connected or not. I want to show alert but print is ok so ill manage it. But dont know why its not printing anything
You can try with this
Future<bool> check() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
print("Connected}");
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
print("Connected}");
return true;
}
print("not Connected}");
// return You can add your dialog for notify user to your connectivity is off
}
you can use below code to check the connectivity
Future<bool> checkInternetConnectivity() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
} else {
return false;
}
} on SocketException catch (_) {
return false;
}
}
simple
Future<bool> isConnected() async {
var result = await Connectivity().checkConnectivity();
return result != ConnectivityResult.none;
}
I'm trying to implement a renewable subscription in flutter using the flutter_in_app_purchases plugin. When I click on the screen that this is declared in, it goes through the initState() function and then gets to the initPlatformState() and goes through that successfully, but when it gets to the getProducts() function, it's returning an empty item list for the List items = FlutterInappPurchase.instance.getSubscriptions([productID]); call. I've added the monthly subscription in both the App Store Connect and Google Play Store and completed the tax forms. Any help would be appreciated.
List<IAPItem> _items = [];
static const String productID = 'monthly_subscription';
#override
void initState() {
super.initState();
print("IN INIT STATE");
initPlatformState();
}
Future<void> initPlatformState() async {
print("In init platform state");
// prepare
final bool available = await InAppPurchaseConnection.instance.isAvailable();
print(available);
var close = await FlutterInappPurchase.instance.endConnection;
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
print('In not mounded');
return;
}
// refresh items for android
/*try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch(e){
print(e.toString());
}*/
await _getProduct();
}
Future<Null> _getProduct() async {
print("In get products");
try {
List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions([productID]);
print("Items is: $items");
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
});
} catch(e) {
print(e.toString());
}
}
Here you have a working example from app in production. Disclaimer: I'm not using it anymore but the last time I did it worked fine:
class _InAppState extends State<InApp> {
StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
StreamSubscription _conectionSubscription;
final List<String> _productLists = Platform.isAndroid
? [
'subs_premium', 'subs_user'
]
: ['subs_premium', 'subs_boss', 'subscripcion_user'];
String _platformVersion = 'Unknown';
List<IAPItem> _items = [];
List<IAPItem> _subscripions = [];
List<PurchasedItem> _purchases = [];
#override
void initState() {
super.initState();
initPlatformState();
}
#override
void dispose() {
super.dispose();
if (_conectionSubscription != null) {
_conectionSubscription.cancel();
_conectionSubscription = null;
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterInappPurchase.instance.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// prepare
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
print('connected: $connected');
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
print('purchase-updated: $productItem');
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
print('purchase-error: $purchaseError');
});
final List<String> _SKUS = widget.premium ? ['subs_boss']
: ['subs_user'] ;
_getSubscriptions(_SKUS);
}
void _requestPurchase(IAPItem item) {
FlutterInappPurchase.instance.requestPurchase(item.productId);
}
Future _getProduct() async {
print('TEST 1 HERE ${_productLists.length}, ${_productLists.first.toString()}');
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
print('TEST 2 HERE ${items.length}');
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
this._purchases = [];
});
}
Future _getPurchases() async {
List<PurchasedItem> items =
await FlutterInappPurchase.instance.getAvailablePurchases();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}
Future _getSubscriptions(_SKUS) async {
List<IAPItem> items =
await FlutterInappPurchase.instance.getSubscriptions(_SKUS);
for (var item in items) {
print('${item.toString()}');
this._subscripions.add(item);
}
setState(() {
this._items = [];
this._subscripions = items;
});
}
Future _getPurchaseHistory() async {
List<PurchasedItem> items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}