How can I open/close Admob with Firebase Remote Config? - flutter

I'm new to Flutter and Remote Config. In my project, I'm trying to close my ad banners from remote config like true/false statement but I think I'm missing something out. I would really appreciate if you give me any advice.
I imported remote plugin for flutter and made the android integration. After that I initialize it
Future<RemoteConfig> setupRemoteConfig() async {
final RemoteConfig remoteConfig = await RemoteConfig.instance;
// Enable developer mode to relax fetch throttling
remoteConfig.setConfigSettings(RemoteConfigSettings(debugMode: true));
await remoteConfig.activateFetched();
remoteConfig.setDefaults(<String, dynamic>{
'admob_status': 'true',
});
return remoteConfig;
}
and after that, I added it below statement to my build widget.
var value = remoteConfig.getString("admob_status");
if(value == "true"){
FirebaseAdMob.instance.initialize(appId: FirebaseAdMob.testAppId)
.then((response) {
myBanner
..load()
..show(
//anchorOffset: 60.0,
anchorType: AnchorType.bottom);
});
} else if(value == "false") {
return null;
}
and output is "the method 'getString' was called on null."

I think I found the solution, it seems working. Maybe it can help you in the future
checkAdmobStatus() async {
final RemoteConfig remoteConfig = await RemoteConfig.instance;
final defaults = <String, dynamic>{'status': 'true'};
await remoteConfig.setDefaults(defaults);
await remoteConfig.fetch();
await remoteConfig.activateFetched();
if ('true' == remoteConfig.getString('status')) {
FirebaseAdMob.instance
.initialize(appId: FirebaseAdMob.testAppId)
.then((response) {
myBanner
..load()
..show(anchorType: AnchorType.bottom);
});
}
}

Related

Unhandled Exception: type 'Null' is not a subtype of type 'ApiResponse<Map<String, dynamic>>'

I'm getting the following error while fetching data from server but I know this error is not about how I'm fetching data. It is related to the null safety which was added in latest flutter update. I'm not so much familier with it.
Here is the Errors
enter image description here
I tried to check if there was something wrong on the line highlighted and for me it was ok.
Here is the code of servers_http.dart:
ApiResponse<Map<String, dynamic>> resp = await get<Map<String, dynamic>>("detail/random");
if (resp.success ?? false) {
return StarConfig.fromJson(resp.data!);
}
return null;
}```
**and this stars_provider.dart**
```///Initialize engine and load last server
void initialize(BuildContext context) {
engine = OpenStar(onStarStageChanged: onStarStageChanged, onStarStatusChanged: onStarStatusChanged)
..initialize(
lastStatus: onStarStatusChanged,
lastStage: (stage) => onStarStageChanged(stage, stage.name),
groupIdentifier: groupIdentifier,
localizedDescription: localizationDescription,
providerBundleIdentifier: providerBundleIdentifier,
);
Preferences.instance().then((value) async {
starConfig = value.getServer() ?? await ServersHttp(context).random();
notifyListeners();
});
}```
what I need to change?
Slution 1:
my understanding that you are requesting data from the server using
ApiResponse<Map<String, dynamic>> resp = await get<Map<String, dynamic>>("detail/random");
if so all you need to do is to change it to :
ApiResponse<Map<String, dynamic>>? resp = await get<Map<String, dynamic>>("detail/random");
if (resp?.success ?? false) {
return StarConfig.fromJson(resp.data!);
}
Slution 2:
i believe this function is the problem and starConfig doesn't accept null and base on your code :
Preferences.instance().then((value) async {
starConfig = value.getServer() ?? await ServersHttp(context).random();
notifyListeners();
});
this part is returning null when his only job is to return ApiResponse<Map<String, dynamic>>
await ServersHttp(context).random()
now this i believe this will work if you
Preferences.instance().then((value) async {
ApiResponse<Map<String, dynamic>> test;
starConfig = value.getServer() ?? test.fromJson({});
notifyListeners();
});
Note : i don't know what ServersHttp(context).random() do.

The operation 'uploadBytesResumable' cannot be performed on a root reference, create a non-root reference using child

I was using Firebase services without rules for testing like this:
allow read, write: if true; and when I decide to set rules this problem happened suddenly!
allow read, write: if request.auth != null;
FirebaseError: Firebase Storage: The operation 'uploadBytesResumable' cannot be performed on a root reference, create a non-root reference using child, such as .child('file.png'). (storage/invalid-root-operation)
Before changing the rules, I uploaded many images to storage and view them in my app, but now I'm trying with all my information without any changes!!
This is the method which I use to upload the images, I didn't change anything in it before or after changing the rules:
Reference reference = FirebaseStorage.instance.ref();
Future uploadImage() async {
reference.child('Items/${itemNameController.text}.jpg');
await reference.putData(
webImage!,
SettableMetadata(contentType: 'image/jpeg'),
);
downloadUrl = await reference.getDownloadURL();
update();
}
By the way, I'm using Flutter web.
And I'm using this package: firebase_storage: ^11.0.6
Update
I will put here the full code for my operation, the problem is happening when I try to upload to fireStorage, but there is another function to store data in fireStore.
I have tried the solution that typed down by Someone, but still have the same problem when I combine functions (FireStorage - FireStore) with each other:
Database database = Database();
String? id;
Future saveToDb() async {
var formData = formKey.currentState;
if (formData!.validate()) {
await uploadImage().whenComplete(() async {
await addToFireStore();
clearData();
Get.snackbar(
'Adding done',
'Adding item done successfully',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: AppColors.mainColor,
borderRadius: Dimensions.radius20,
duration: const Duration(seconds: 3),
padding: EdgeInsets.fromLTRB(
Dimensions.width30,
Dimensions.height20,
Dimensions.width40,
Dimensions.height20,
),
);
update();
});
}
}
Future uploadImage() async {
await database.reference.child('Items/${itemNameController.text}.jpg').putData(
webImage!,
SettableMetadata(contentType: 'image/jpeg'),
);
downloadUrl = await database.reference.getDownloadURL();
update();
}
Future addToFireStore() async {
for (var i in database.categoriesModel) {
if (database.categoryValue == i.name) {
id = i.id;
}
}
await database.catCollectionRef
.doc(id)
.collection('Items')
.doc(const Uuid().v4())
.set({
'id': const Uuid().v4(),
'Name': itemNameController.text,
'Decryption': itemDescController.text,
'Availability': switchValue.toString(),
'Category': database.categoryValue,
'Quantity type': quantityValue,
'Quantity value': itemQuanController.text,
'Price': itemPriceController.text,
'Image': downloadUrl,
});
update();
}
clearData() {
webImage?.clear();
itemNameController.clear();
itemDescController.clear();
itemQuanController.clear();
itemPriceController.clear();
database.categoryValue = 'Choose one';
switchValue = false;
quantityValue = 'Choose One';
downloadUrl = '';
update();
}
I use the saveToDb() function in the UI button to set the whole operation, but returns the same problem!!!
you're referencing to the root directlt, calling the child() on statement will not change the reference, try:
Reference reference = FirebaseStorage.instance.ref();
Future uploadImage() async {
await reference.child('Items/${itemNameController.text}.jpg').putData(
webImage!,
SettableMetadata(contentType: 'image/jpeg'),
);
downloadUrl = await reference.getDownloadURL();
update();
}

Flutter:Immediately received new config in client from remote when changed config from console

I create a service to get config from Firebase remote config:
const String _ShowDataBanner = "show_data_banner";
const String _ShowMainBanner = "show_main_banner";
const String _ShowMainColorBanner = "show_main_color_banner";
class RemoteConfigService {
final RemoteConfig _remoteConfig;
final defaults = <String, dynamic>{
_ShowMainBanner: false,
_ShowMainColorBanner: "0xffcccccc"
};
RemoteConfigService({RemoteConfig remoteConfig})
: _remoteConfig = remoteConfig;
static RemoteConfigService _instance;
static Future<RemoteConfigService> getInstance() async {
if (_instance == null) {
_instance = RemoteConfigService(
remoteConfig: await RemoteConfig.instance,
);
}
return _instance;
}
String get showMainBanner => _remoteConfig.getString(_ShowDataBanner);
Future initialise() async {
try {
await _remoteConfig.setDefaults(defaults);
await _fetchAndActivate();
} on FetchThrottledException catch (e) {
print("Remote config fetch throttled: $e");
} catch (e) {
print(
"unable to fetch remote config. Catched or default values will be used");
}
}
Future _fetchAndActivate() async {
// await _remoteConfig.fetch();
await _remoteConfig.fetch(expiration: Duration(seconds: 0));
_remoteConfig
.activateFetched()
.then((value) => print("---------> ${value.toString()}"));
}
}
When i change config from Firebase console I have to stop/start app to updated my config.It is possible to received new config in client from remote immediately when i changed config from console?
Firebase remote config is not meant to be used like this. Its not a real-time thing. But if you want to update immediately after updating config from firebase console, then you can do that by providing expiration parameter a duration of 0 seconds.
await remoteConfig.fetch(expiration: const Duration(seconds: 0));
It will fetch the latest values every time but this is not recommended as you can also get FetchThrottledException.
Future<RemoteConfig> setupRemoteConfig() async {
final RemoteConfig remoteConfig = RemoteConfig.instance;
await remoteConfig.ensureInitialized();
await remoteConfig.fetchAndActivate();
var hello = remoteConfig.getString("hello");
print("hello: |${hello}|");
return remoteConfig;
}
await remoteConfig.fetchAndActivate(); is very important.

Flutter Location package requestService() never returns

I have a function like this. Using Location package from flutter it shows the dialog to enable GPS.
Future<bool> _checkServiceStatus() async {
final Location location = Location();
bool serviceStatus = await location.serviceEnabled();
if (!serviceStatus) {
serviceStatus = await location.requestService();
print('status -> $serviceStatus');
}
return serviceStatus;
}
When its calling await location.requestService(), it is showing the dialog to enable GPS but after that it never returns the result.
Even its not executing the print() function.
What am i doing wrong here?
Any help would be very appreciated! Thanks in advance.
I had the same issue. It could be solved by upgrading your Flutter project, follow this link https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects
Try this code to check wather permission enabled, service enabled than it returns true else false. Must configure "location" package related configuration in android and ios projects.
Future<bool> checkServiceStatus() async {
final Location location = Location();
final locationPermission = await location.hasPermission();
if (locationPermission == PermissionStatus.granted) {
final locationServiceEnabled = await location.serviceEnabled();
if (locationServiceEnabled == true) {
return true;
} else {
final requestServiceStatus = await location.requestService();
if (requestServiceStatus == true) {
return true;
} else {
BotToast.showSimpleNotification(
title: "Enable GPS to allow this feature");
return false;
}
}
} else {
BotToast.showSimpleNotification(title: "Required location permission to allow this feature");
return false;
}
}

Flutter initState wait for async function to complete

in my main.dart i have among others those two functions:
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
}
And
#override
void initState() {
super.initState();
_fetchMasterData();
}
What i would like to have is to wait in initState till _fethcMasterData is done bevore Widgert build is called.
Is that possible? Many thanks for any help!
Here how I use an async func in initstate;
builder() async {
favoriteDatabase =
await $FloorFavoriteDatabase.databaseBuilder('favorite_database.db')
.build();
setState(() {
favoriteDao = favoriteDatabase.favoriteDao;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
getNamePreferences().then(updateName));
});
builder();
favoriteDao.findAllMoviesAsStreamW();
favoriteDao.findAllMoviesAsStream();
}
Also you can check this mini article too.
It is not possible to await in initState, so when you finish all loading process then you can call SetState method which populate your widget with actual data.
Second solution could be use of futurebuilder or streambuilder where you want to show data but it is only possible if any methods data is not dependent on each other.
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
SetState((){}); // added line
}