can't load iap products in local, it waits forever - flutter

I'm using the official in_app_purchase plugin, version ^1.0.4, and I'm following the official guide from Google insert my first iap (https://codelabs.developers.google.com/codelabs/flutter-in-app-purchases#0).
My consumable iap product is active on Play console with name "pacchetto_25", I've already submitted to the alpha channel my app and is accepted, the tester email is correctly configured in the Tester Group and in Licence Testing.
Now I'm trying to load the iap products in my app, the code is the same of the guide:
Future<void> loadPurchases() async {
final available = await _iap.isAvailable();
if (!available) {
print("STORE NOT AVAILABLE");
return;
} else {
print("STORE AVAILABLE");
const ids = <String>{
"pacchetto_25",
};
final response = await _iap.queryProductDetails(ids);
response.notFoundIDs.forEach((element) {
print('Purchase $element not found');
});
response.productDetails.forEach((element) {
print("Purchase $element found");
});
// products =
// response.productDetails.map((e) => PurchasableProduct(e)).toList();
}
}
In my console I have the "STORE AVAILABLE" message, but then nothing else. If I put same debug point it does not stops on them, this problem appear after this line:
final response = await _iap.queryProductDetails(ids);
Do someone know what's happening? I've no errors in my console and the code after loadPurchases() is not executed, it's like is waiting forever... Any ideas?

Solved! If you have the same issue DON'T put
implementation("com.android.billingclient:billing:4.0.0")
in your build.gradle

Related

Login with facebook works on real phones but not emulators, it started happening with the new emulator update

This code works on real phones but not on emulators
I use flutter_facebook_auth. This exact code worked fine before emulator update and it's still works on real devices, but on emulator it just do nothing after coming back from fb login page.
static Future<User?> signInWithFacebook() async {
try {
//Trigger the sign-in flow
final LoginResult loginResult =
await FacebookAuth.instance.login(permissions: [
'public_profile',
'email',
'user_friends',
]);
if (loginResult.status == LoginStatus.success) {
print('success');
facebookAuthCredential =
FacebookAuthProvider.credential(loginResult.accessToken!.token);
print(loginResult.accessToken?.token);
Credential = await FirebaseAuth.instance
.signInWithCredential(facebookAuthCredential);
print('here 1');
UserData = await FacebookAuth.instance.getUserData(
fields:
"name,email,picture.width(400),birthday,friends,gender,link");
print(UserData);
} else {
print(loginResult.message);
error = loginResult.message!;
}
user = Credential.user;
await user
?.updatePhotoURL(UserData['picture']['data']['url'])
.then((value) {
print('success' + UserData['picture']['data']['url']);
});
return Credential.user;
} on FirebaseException catch (e) {
error = e.code;
print(e.code);
}
}
}
In the above code the app flow stops or freezes on
Credential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
What I have tried is:
Tried other emulators, different api's and models.
I tried adding new release and debug keyhashes to both facebook and firebase
I tried increasing emulator ram and cpu cores etc
I tried refreshing fb sdk and json and other dev dependencies
I tried flutter clean
I tried Invalidate Caches
I uninstalled android studio and all of it's components and install again
Is this happening with just me or it's a bug in the new emulator update?
It's been 12 hours, can somebody please help and check if their updated emulator is working with fb login
I solved it by downgrading emulator version to 31.2.9,
Here is emulator_archive how you can do it:

Connectivity plugin "getWifiName()" method to get ssid returns null in flutter for ios 13+

I am trying to get wifi ssid in flutter for ios(13+) with connectivity plugin but result returns null. I have added access wireless information from Xcode but still not working. Can anyone help out please?
Future<void> _updateConnectionStatus(ConnectivityResult result) async{
switch(result){
case ConnectivityResult.wifi:
String wifiName;
try {
if (Platform.isIOS) {
LocationAuthorizationStatus status =
await _connectivity.getLocationServiceAuthorization();
if (status == LocationAuthorizationStatus.notDetermined) {
print('wifiName notDetermined: ');
status = await _connectivity.requestLocationServiceAuthorization();
}
if (status == LocationAuthorizationStatus.authorizedAlways ||
status == LocationAuthorizationStatus.authorizedWhenInUse) {
print('wifiName authorizedWhenInUse: ');
wifiName = await _connectivity.getWifiName();
setState(() {
_ssid = wifiName != null ? wifiName : _ssid;
});
} else {
print('wifiName ,.,.,.,: ');
wifiName = await _connectivity.getWifiName();
}
} else {
LocationAuthorizationStatus status =
await _connectivity.getLocationServiceAuthorization();
// if(status == )
wifiName = await _connectivity.getWifiName();
print('android wifi');
print(wifiName);
}
} on PlatformException catch (e) {
print(e.toString());
wifiName = "Failed to get Wifi Name";
}
setState(() {
_connectionStatus ='result '+ '$result\n'
'Wifi Name: $wifiName\n';
print('_connectionStatus $_connectionStatus');
});
break;
case ConnectivityResult.mobile:
Fluttertoast.showToast(msg: 'Connected to mobile network');
break;
case ConnectivityResult.none:
Fluttertoast.showToast(msg: 'Connected to no network');
setState(() => _connectionStatus = result.toString());
break;
default:
setState(() => _connectionStatus = 'Failed to get connectivity.');
break;
}
}
I have tried with above code from connectivity plugin example. Also there is showing 'As of iOS 13, Apple announced that these APIs will no longer return valid information'. So how to achieve my goal?
In 2020, the flutter team decided to create a new plugin for wifi information, removing these methods from the connectivity plugin.
So check the network_info_plus plugin: the method signatures are just the same.
As on being able to access this on iOS 13+, according to the package's readme:
The CNCopyCurrentNetworkInfo will work for Apps that:
The app uses Core Location, and has the user’s authorization to use
location information.
The app uses the NEHotspotConfiguration API to configure the current
Wi-Fi network.
The app has active VPN configurations installed.
If your app falls into the last two categories, it will work as it is.
If your app doesn't fall into the last two categories, and you still
need to access the wifi information, you should request user's
authorization to use location information.
There is a helper method provided in this plugin to request the
location authorization: requestLocationServiceAuthorization. To
request location authorization, make sure to add the following keys to
your Info.plist file, located in /ios/Runner/Info.plist:
NSLocationAlwaysAndWhenInUseUsageDescription - describe why the app
needs access to the user’s location information all the time
(foreground and background). This is called Privacy - Location Always
and When In Use Usage Description in the visual editor.
NSLocationWhenInUseUsageDescription - describe why the app needs
access to the user’s location information when the app is running in
the foreground. This is called Privacy - Location When In Use Usage
Description in the visual editor.
So basically, from iOS13 on, you have to request the user's permission for location - it actually makes sense.

Open an app in flutter based on the url provided in the email sent for verification

So I have been working on a flutter app and once the user registers through my app they are sent an email for the verification of their account. Once the url in the link is tapped they are verified. Now after their verification,the users must be redirected to the app. I looked into firebase dynamic links but in all of the articles,they were trying to share their app by generating a link. Is there a way I can implement this? Thanks in advance!
Use this package
https://pub.dev/packages/uni_links
For getting the link when the app is started.
This is the case in which your app was in the closed state.
Future<Null> initUniLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
String initialLink = await getInitialLink();
// Parse the link and warn the user, if it is not correct,
// but keep in mind it could be `null`.
} on PlatformException {
// Handle exception by warning the user their action did not succeed
// return?
}
}
For listening to link clicks. This is for the case when your app is already open and you click the link.
_sub = getLinksStream().listen((String link) {
// Parse the link and warn the user, if it is not correct
}, onError: (err) {
// Handle exception by warning the user their action did not succeed
});
// NOTE: Don't forget to call _sub.cancel() in dispose()
}
Usually, you need to implement both of them together since your app may be in the closed state or open state while you click the link.
Future<Null> initUniLinks() async {
try {
String initialLink = await getInitialLink();
} on PlatformException {
}
_sub = getLinksStream().listen((String link) {}, onError: (err) {});
}}

Flutter getting an exception when calling queryPastPurchases (in_app_purchase plugin): Cannot find receipt for the current main bundle

I'm trying to utilise the in_app_purchase plugin (https://pub.dev/packages/in_app_purchase) for my Flutter App.
Calling a queryProductDetails(ids) works just fine,
but when calling the queryPastPurchases() I get the following exception:
PlatformException (PlatformException(storekit_no_receipt, Cannot find receipt for the current main bundle., null))
Seems like this is the source for the exception:
https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m
Worth mentioning:
I've setup an IAP in App-Store-Connect.
This IAP hasn't been sent for Apple approval yet.
App is in development, tested using TestFlight with beta testers.
Another issue is that this exception doesn't get cought in the try-catch statement (see code below), but only by the environment when checking the "All Exceptions" option in VSCode...
Tested on Emulator and real device.
[UPDATE]:
Added a breakpoint to the objective-c code of the plugin, and saw that the receiptURL refers to "sandboxReceipt". So maybe it's because I don't use sandbox users?
Future<void> _getPastPurchases() async {
try {
final QueryPurchaseDetailsResponse response = await InAppPurchaseConnection.instance.queryPastPurchases();
if (response.error != null) {
// Handle the error
print(response.error.toString());
}
print('response = ' + response.toString());
for (PurchaseDetails purchase in response.pastPurchases) {
if (Platform.isIOS) {
//InAppPurchaseConnection.instance.completePurchase(purchase);
}
}
setState(() {
_purchases = response.pastPurchases;
});
} on PlatformException catch(err) {
print(err.toString());
}
catch (err) {
print(err.toString());
}
}

in_app_purchases using flutter

I am trying to create an application that can handle In App Purchases Using Flutter.I am using the in_app_purchase 0.2.1 plugin .I have managed to setup my product on google play developer console as required but however when try to retrieve it from the application i am able to connect to the store successfully but i am not able to retrieve my product ,it always shows up as product not found.
I have followed a this tutorial https://joebirch.co/2019/05/31/adding-in-app-purchases-to-flutter-apps/ and also looked at the package documentation https://pub.dev/packages/in_app_purchase.
My google play setup for the product is shown below
google play console setup
google play console setup2
The function i am using is shown below.
Future<List<ProductDetails>> retrieveProducts() async {
final bool available = await InAppPurchaseConnection.instance.isAvailable();
if (!available) {
// Handle store not available
print("Store Temporarily Unavailable");
return null;
} else {
print("Store Temporarily Available");
const Set<String> _kIds = {'airtime123'};
final ProductDetailsResponse response =
await InAppPurchaseConnection.instance.queryProductDetails(_kIds);
if (response.notFoundIDs.isNotEmpty) {
print("product not found");
print(response.notFoundIDs[0]);
return null;
}
print("product found");
return response.productDetails;
}
}
This is the result i get
I/flutter ( 7254): Store Temporarily Available
I/flutter ( 7254): product not found
I/flutter ( 7254): airtime123
You need to use a reserved SKU for the test: android.test.purchased
const Set<String> _kIds = {'android.test.purchased'};
final ProductDetailsResponse response =
await InAppPurchaseConnection.instance.queryProductDetails(_kIds);