facing issue in method channel internet connectivity in unit testing in flutter - flutter

I have checked internet connectivity in flutter while calling api in store class like this using 'connectivity' library.
Future<bool> callApi() async {
final isInternet = await Util.checkInternetAndShowDialog(context);
if (isInternet) {
final future = _repository.callApi();
var res = await future;
return true;
}
return false;
}
In Util class network connectivity is been checked like this::
class Util {
static Future<bool> checkInternetAndShowDialog(BuildContext context) async{
var internet = await NetworkConnectivity.rechability();
if (internet == false) {
AlertMessage().showAlertDialog(context, 'error message');
}
return internet;
}
}
In NetworkConnectivity class network connectivity is been checked using Connectivity library.
class NetworkConnectivity {
static Future<bool> rechability() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
}
return false;
}
}
my test cases code is like below:
test('call api successfully', () async {
when(mockStore.callApi()).thenAnswer((realInvocation) => Future.value());
expect(await store.callApi(), true);
});
so while writing unit testing I am facing error of connectivity and method channel.
connectivity error image
Can any one help please me how I can mock for internet connectivity in unit testing and pass the test in flutter. I shall be thankful for this.

Related

How to check network connectivity in Flutter?

I want to check if user has internet connection and want it to be dynamic. Customisable messages will be shown to user according to it.
ElevatedButton(
onPressed: () async {
ans = await InternetConnectionChecker().hasConnection;
print(ans);
},
child: const Text('Fetch Data'),
),
I can check it when clicked on the button by the user but I want it to be automatic when user hops on the home page.
I tried putting
ans = await InternetConnectionChecker().hasConnection;
print(ans);
in initState but it doesn't work. Any suggestions as to how should I improve it?
EDIT :
I tried the first solution and on click of a button I get all the results perfectly
onPressed: () async {
var connectivityResult = await (Connectivity().checkConnectivity());
var subscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) {
print("Changed to $result");
});
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network.
print("Mobile");
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
print("Wifi");
}
},
It shows none when no internet is there. To mobile when connected to mobile hotspot and wifi when connected to wifi network.
But my issue still remains that I want to check internet connection when a user comes to my home page.
I tried this :
var subscription;
#override
initState() async {
super.initState();
print("hlo");
var connectivityResult = await (Connectivity().checkConnectivity());
var subscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) {
print("Changed to $result");
});
}
But this doesn't work. What am I dooing wrong? Can i improve this?
This plugin allows Flutter apps to discover network connectivity and configure themselves accordingly. It can distinguish between cellular vs WiFi connection. check here
connectivity_plus 3.0.2
import 'package:connectivity_plus/connectivity_plus.dart';
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network. }
else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
}
You can use connectivity_plus package to check internet connection. The http package that we use to call api can't tell if we don't have internet or the server is down.
class NetworkConnectivity {
NetworkConnectivity._();
static final _instance = NetworkConnectivity._();
static NetworkConnectivity get instance => _instance;
final _networkConnectivity = Connectivity();
final _controller = StreamController.broadcast();
Stream get myStream => _controller.stream;
// 1.
void initialise() async {
ConnectivityResult result = await _networkConnectivity.checkConnectivity();
_checkStatus(result);
_networkConnectivity.onConnectivityChanged.listen((result) {
print(result);
_checkStatus(result);
});
}
// 2.
void _checkStatus(ConnectivityResult result) async {
bool isOnline = false;
try {
final result = await InternetAddress.lookup('example.com');
isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty;
} on SocketException catch (_) {
isOnline = false;
}
_controller.sink.add({result: isOnline});
}
void disposeStream() => _controller.close();
}
You can use the following guide: Flutter Internet Connectivity

Check or listen continuously to internet connection/Network Connectivity in dart, flutter app

I have been searching for long to know the best approach to listen to internet connection in flutter/dart app. I think this approach is better for now and it can be of help to some like me who has been searching. I have used many connectivity plugins, but it didn't work. I have equally used data_connection_checker, lookUpAddress etc as suggested by many but to no avail. But below helped.
Use the below plugins to check or listen to Internet Connection / Network Connectivity in dart, flutter app.
connectivity_plus
internet_connection_checker
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
class ConnectionUtil {
static final ConnectionUtil _singleton = new ConnectionUtil._internal();
ConnectionUtil._internal();
static ConnectionUtil getInstance() => _singleton;
bool hasConnection = false;
StreamController connectionChangeController = StreamController();
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
}
void _connectionChange(ConnectivityResult result) {
_hasInternetInternetConnection();
}
Stream get connectionChange => connectionChangeController.stream;
Future<bool> _hasInternetInternetConnection() async {
bool previousConnection = hasConnection;
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi) {
// this is the different
if (await InternetConnectionChecker().hasConnection) {
hasConnection = true;
} else {
hasConnection = false;
}
} else {
hasConnection = false;
}
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
Implement this code on the stateful widget.....
bool hasInterNetConnection = false;
#override
initState() {
ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
connectionStatus.initialize();
connectionStatus.connectionChange.listen(connectionChanged);
super.initState();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
hasInterNetConnection = hasConnection;
});
}
Good luck
I had faced a similar problem a few weeks ago. This is a good approach. The internet_connection_checker plugin allows one to address issues at the network layer that the connectivity_plus plugin cannot address. I have carried out an implementation of these two plugins using the bloc library. For more information and code refer to this Stackoverflow post and this Github issue.

Use StreamSubscription as Future in Dart/Flutter

I want to connect my Flutter app to bluetooth device with flutter_blue library, and return a result (anything) when the connection is ON. But I don't understand how to do.
Here my code :
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device.discoverServices().then((value) => _initFeatures(value));
}
})
..onDone(() {
// Cascade
print("onDone");
});
subscription.asFuture();
//subscription.cancel();
}
And when I call this function with
await newDevice.connect(bluetoothDevice).then((value) => print('OK'));
OK is written before the real connection. _initFeatures if well call when the device is connected.
I try to use asFuture from StreamSubscription with onDone, but that change nothing.
Could you help me please ?
UPDATE 12/10
I've worked on another project for few monthes, and when I come back, I can't solve the problem, so I add the full code.
The concept is a class widget calls the connect future in other class and need to receipt the end of work.
Widget
Future<void> _connectDevice() async {
try {
widget.device.connect(widget.btDevice!).then((value) => _initValue());
} catch (e) {
print(e);
}
}
_initValue() is a method to create the rest of the screen
and the Future connect()
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device
.discoverServices()
.then((value) => _initFeatures(value))
.then((value) => print("OK"));
}
});
await subscription.asFuture();
await subscription.cancel();
}
What I'd like is the Future finishes when print("OK") is called, in order .then((value) => _initValue()); is called.
The problem is only this end. Maybe it's not the good way to implement this kind of solution.

flutter in_app_purchases not available on emulator - getting error android

I am trying to implement in_app_purchase: ^0.3.5+1 for 1st time.
I have an active product setup on the Google Developer Console but I can't seem to get my emulator to hit the store. The connection's isAvailable method always returns false. Stepping through the code the connection instance seems to show the following error message in the private property _purchasedUpdatedStream. Not sure what this means. Seems relevant. Not sure what steps to take from here. Any help is much appreciated.
The getter '_purchaseUpdatedStream' isn't defined for the class 'GooglePlayConnection'.
'GooglePlayConnection' is from 'package:in_app_purchase/src/in_app_purchase/google_play_connection.dart' ('../../flutterSDK/.pub-cache/hosted/pub.dartlang.org/in_app_purchase-0.3.5+1/lib/src/in_app_purchase/google_play_connection.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_purchaseUpdatedStream'.
_purchaseUpdatedStream
Store class looks like this:
import 'dart:async';
import 'dart:io';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:quifil/models/status_ml.dart';
class StoreAPI {
InAppPurchaseConnection _iap;
bool available = true;
StreamSubscription<List<PurchaseDetails>> _subscription;
final String myProductID = 'quifil_ad_free';
bool _isPurchased = false;
List _purchases = [];
List _products = [];
StoreAPI() {
InAppPurchaseConnection.enablePendingPurchases();
_iap = InAppPurchaseConnection.instance;
}
bool get isPurchased {
return _isPurchased;
}
set isPurchased(bool value) {
_isPurchased = value;
}
List get purchases {
return _purchases;
}
set purchases(List value) {
_purchases = value;
}
List get products {
return _products;
}
set products(List value) {
_products = value;
}
Future<Status> fetchStoreInfo() async {
Status status = Status(true);
bool available = await _iap.isAvailable();
if (available) {
await _getProducts();
await _getPastPurchases();
verifyPurchase();
_subscription = _iap.purchaseUpdatedStream.listen((purchases) {
purchases.addAll(purchases);
verifyPurchase();
});
} else {
status.success = false;
status.error = "Store is unavailable";
}
return status;
}
Future<void> _getProducts() async {
Set<String> ids = Set.from([myProductID]);
ProductDetailsResponse response = await _iap.queryProductDetails(ids);
products = response.productDetails;
}
Future<void> _getPastPurchases() async {
QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases();
for (PurchaseDetails purchase in response.pastPurchases) {
if (Platform.isIOS) {
_iap.consumePurchase(purchase);
}
}
purchases = response.pastPurchases;
}
void verifyPurchase() {
PurchaseDetails purchase = hasPurchased(myProductID);
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
if (purchase.pendingCompletePurchase) {
_iap.completePurchase(purchase);
isPurchased = true;
}
}
}
PurchaseDetails hasPurchased(String productID) {
return purchases.firstWhere((purchase) => purchase.productID == productID,
orElse: () => null);
}
}
Turns out I had 2 items I changed to fix this.
My laptop was using wifi but wifi was not the 1st choice when it came to network access. So I disabled my other other LAN adapters. There is also a way to set the priority of your adaptors so that the wifi is top priority. It seems the emulator likes to pick the top priority.
My laptop wifi adapter DNS was using an address I did not recognize. So I changed it to use Google's DNS as 8.8.8.8 and the alternate as 8.8.4.4.

How to get local IP in Flutter Web

I'm trying to get the local IP address in a Flutter Web app. Searching the internet I came around this package: get_ip 0.4.0 - it states it is working under web.
I have this function:
Future<void> initPlatformState() async {
print("Test");
String ipAddress;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
ipAddress = await GetIp.ipAddress;
} on PlatformException {
ipAddress = 'Failed to get ipAddress.';
} on Exception {
print("Exception");
}
print("Ip: $ipAddress");
}
and I call it in initState of main.dart.
The console just has the output Test, it does not output the IP or Exception.
Has someone already used this package? Would there be an other way for a web app to get the local IP?
(I'm using MacOS)
The get_ip package states that it supports Android/iOS.
So,instead of using the package,you can directly interact with ipify endpoint.
Check out their API documentation for more!
Future<String> getIP() async {
try {
const url = 'https://api.ipify.org';
var response = await http.get(url);
if (response.statusCode == 200) {
print(response.body);
return response.body;
} else {
print(response.body);
return null;
}
} catch (exception) {
print(exception);
return null;
}
}
I'm Using ip_geolocation_api Package for getting an IP address and it is working as expected
String text = '';
GeolocationData geolocationData;
#override
void initState() {
super.initState();
this.getIp();
}
Future<void> getIp() async {
geolocationData = await GeolocationAPI.getData();
if (geolocationData != null) {
setState(() {
text = geolocationData.ip;
print(text);
});
}
}
Now You have IP in the text Variable.