How to stop app from crashing due to admob(flutter, iOS)? - ios

I tried implementing admob to my flutter app. I used open ads to show an ad on launch, but whenever I launch the app it always crashes. Maybe I implemented the code in Info.plist wrong?
enter image description here
enter image description here
AppOpenAd? openAd;
Future loadAd() async{
await AppOpenAd.load(
adUnitId: 'ca-app-pub-######',
request: const AdManagerAdRequest(),
adLoadCallback: AppOpenAdLoadCallback(
onAdLoaded: (ad){
print('ad is loaded');
openAd = ad;
openAd!.show();
},
onAdFailedToLoad: (error){
print('ad failed to load $error');
}),
orientation: AppOpenAd.orientationPortrait
);
}
void showAd() {
if(openAd==null){
print('show before loading');
loadAd();
return;
}
openAd!.fullScreenContentCallback = FullScreenContentCallback(
onAdShowedFullScreenContent: (ad){
print('onAdShowedFullScreenContent');
},
onAdFailedToShowFullScreenContent: (ad, error){
ad.dispose();
print('failed to load $error');
openAd = null;
loadAd();
}, onAdDismissedFullScreenContent: (ad){
ad.dispose();
print('dismissed');
openAd = null;
loadAd();
}
);
openAd!.show();
}
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await MobileAds.instance.initialize();
await loadAd();
final SharedPreferences prefs = await SharedPreferences.getInstance();
runApp(WhatsTheWord());
}

Related

Capacitor iOS Geolocation watchPostion kCLErrorDomain error 1 while permission granted

I am using an older version of the capacitor geolocation, v1.3.1, and recently switched to the watchPosition implementation but occasionally that created a situation where the position is null or undefined even when the device is showing the location icon being active for the app. I tried to solve that by falling back to the slower getCurrentPosition function but still persists. Has anyone run into this issue before? Here is a gist of the hook.
https://gist.github.com/billpull/8bc6e49872cfee29aa5cef193b59c835
useCurrentPosition.ts
const useCurrentPosition = (): GeoWatchPositionResult => {
const [position, setPosition] = useState<Position>();
const [watchId, setWatchId] = useState("");
const [error, setError] = useState();
const clearWatch = () => {
if (watchId) {
clearPosition({ id: watchId });
setWatchId("");
}
};
const startWatch = async () => {
if (!watchId) {
const id = await watchPosition(async (pos: Position | null, err) => {
if (err) {
setError(err);
}
if (pos) {
setPosition(pos);
} else {
const newPosition = await getCurrentPosition();
setPosition(newPosition);
}
});
setWatchId(id);
}
};
useEffect(() => {
startWatch();
return () => clearWatch();
}, []);
return { currentPosition: position, error };
};
Even though the watchPosition is still returning location data on the interval I am getting a kCLErrorDomain error 1. which online says it means the permission was denied but thats not the case the phone was just in sleep mode. Is there a way to catch this error specifically? Should I clear the watch and restart it on this error?
Edit:
One attempt I made was to use a try catch in the watch, but I still have encountered this issue.
const useCurrentPosition = (): GeoWatchPositionResult => {
const [position, setPosition] = useState<Position>();
const [watchId, setWatchId] = useState("");
const [error, setError] = useState();
const clearWatch = () => {
if (watchId) {
clearPosition({ id: watchId });
setWatchId("");
}
};
const startWatch = async () => {
if (!watchId) {
const id = await watchPosition(async (pos: Position | null, err) => {
try {
if (err) {
setError(err);
}
if (pos) {
setPosition(pos);
} else {
const newPosition = await getCurrentPosition();
setPosition(newPosition);
}
} catch (ex) {
await requestPermission();
clearWatch();
await startWatch();
}
});
setWatchId(id);
}
};
useEffect(() => {
startWatch();
return () => clearWatch();
}, []);
return { currentPosition: position, error };
};
I think you should use this code snippet to check the current position.
import { Geolocation, Geoposition } from '#ionic-native/geolocation/ngx';
constructor(private geolocation: Geolocation) { }
...
let watch = this.geolocation.watchPosition();
watch.subscribe((data) => {
// data can be a set of coordinates, or an error (if an error occurred).
// data.coords.latitude
// data.coords.longitude
});
You can also use the following code snippet to get the current position.
this.geolocation.getCurrentPosition().then((resp) => {
// resp.coords.latitude
// resp.coords.longitude
}).catch((error) => {
console.log('Error getting location', error);
});
If you want to handle the permission denied error, the best way to handle the permission denied error is to check the permission status of the app first before trying to access any location data. This can be done by using the Capacitor Permissions API. If the permission has been granted, you can then proceed to use the watchPosition or getCurrentPosition APIs. If the permission has been denied, you can present a prompt to the user to request permission again.
setState is an asynchronous function, so please pass to it an anonymous function:
if (pos) {
setPosition(pos);
} else {
const newPosition = await getCurrentPosition();
setPosition(() => newPosition);
}

Getting Puppeteer timeouts often on 'await browser.newpage'

I inherited a script to manage a deploy of Salesforce code to multiple orgs in one go, to ensure all orgs are on the same version. The code is maintained in a Github respository and the final step is the update of the main branch, so the deploy therefore has to be successful for all orgs before it updates the main branch. Currently we have 32 orgs for which the deploys run simultaneously (with more to be added).
The final step after the code has deployed successfully is to check all the Salesforce to Salesforce connections and mappings, since all the orgs update a 'hub' org. It is in this step that I've started getting Puppeteer timeouts. Sometimes it completes, sometimes it fails. It seems to be getting worse in that I have to rerun it 2 or 3 times to get it pass without timing out. I'm not experienced in Node or Puppeteer or scripts like these so don't know how to stop this happening. I've tried increasing the timeout from the default 30000 to 90000 but even then it fails sometimes so that is not a solution, obviously.
Interestingly a few of us have also been having problems lately with Chrome being dreadfully slow and timing out just in the browser (we run on the latest version of Chrome) and I read that Puppeteer uses Chrome. I tried googling but haven't found anything that helps me hence posting this query here.
I would appreciate any help to sort this out because running it multiple times for each deploy is not a viable solution, especially with the length of time it takes to complete.
This is the function from where it sets the timeout.
async function checkDifferencesForConnectionSafely(
argv: Config,
browser: Browser,
connection: Connection,
changes: SubscribedFieldUpdate[]
): Promise<void> {
const page = await browser.newPage();
page.setDefaultNavigationTimeout(90000); // added this but it still times out
try {
console.log(`Checking ${connection.username} -> ${connection.name}`);
await checkDifferencesForConnection(argv, page, connection, changes);
console.log(`Finished ${connection.username} -> ${connection.name}`);
} catch (e) {
console.log(`Failed ${connection.username} -> ${connection.name}`, e);
throw e;
} finally {
await page.close();
}
}
And this is the called function where I believe the timeout happens:
async function checkDifferencesForConnection(
argv: Config,
page: Page,
connection: Connection,
changes: SubscribedFieldUpdate[]
): Promise<void> {
await page.goto(connection.url);
const subscribedObjects = await getSubscribedObjects(page);
for (const object of subscribedObjects) {
await gotoObject(page, object);
const fields = await getSubscribedFields(page);
let changesMade = false;
for (const field of fields) {
field.isStrict = argv.strict;
if (field.selectedValueNeedsUpdate()) {
const newValue = field.newValue();
changes.push({
connection,
connectionObject: object,
connectionField: field,
newValue
});
await selectMapping(page, field, newValue);
changesMade = true;
} else if (!field.value) {
const options = field.options.map((o) => o.name);
throw new Error(
`No value for ${connection.name} -> ${object.name} -> ${field.name}, ` +
`options: ${options.join(", ")}`
);
}
}
if (!argv.skipPicklists) {
if (!argv.dryRun && changesMade) {
await saveSubscribedFields(page);
await gotoObject(page, object);
changesMade = false;
}
const pickListMappings = await getPicklistMappingLinks(page);
for (const pickListMapping of pickListMappings) {
try {
await pickListMapping.click();
} catch (e) {
console.log(
`Failed ${connection.username} -> ${connection.name} -> ${object.name} -> ${pickListMapping.id}`,
e
);
throw e;
}
const picklistValues = await getPicklistValues(page);
for (const picklistValue of picklistValues) {
picklistValue.isStrict = argv.strict;
if (picklistValue.selectedValueNeedsUpdate()) {
const newValue = picklistValue.newValue();
changes.push({
connection,
connectionObject: object,
connectionField: picklistValue,
newValue
});
await selectMapping(page, picklistValue, newValue);
changesMade = true;
}
}
await savePicklistMapping(page);
}
}
if (!argv.dryRun && changesMade) {
await saveSubscribedFields(page);
}
}
}
This is the error thrown (after running 2hrs 40min!)It is close to the end of the process so has completed most of the org checks at this stage. It doesn't always fail in the same place or on the same org checks so the timeout is not related to a specific connection.
The full script is here:
import puppeteer, { Browser, Page } from "puppeteer";
import { flatten } from "lodash";
import yargs from "yargs";
import pAll from "p-all";
import {
loginAndGetConnections,
Connection
} from "../page-objects/sf2sf-home.page-object";
import {
getSubscribedObjects,
ConnectionObject
} from "../page-objects/sf2sf-connection.page-object";
import {
SubscribedField,
SubscribedFieldOption,
getSubscribedFields,
gotoObject,
selectMapping,
getPicklistValues,
save as saveSubscribedFields,
getPicklistMappingLinks,
savePicklistMapping
} from "../page-objects/sf2sf-subscribed-fields.page-object";
import { SClusterConfig } from "../s-cluster-config";
class Config {
configFile: string;
clusterConfigFile: string;
dryRun: boolean;
strict: boolean;
concurrency: number;
skipPicklists: boolean;
constructor() {
// eslint-disable-next-line #typescript-eslint/no-explicit-any
const argv: any = yargs
.scriptName("publish-connections")
.describe("config-file", "The file configuring the SF2SF sync.")
.alias("config-file", "c")
.default("config-file", "./sf2sf.config.json")
.describe("cluster-config-file", "The file configuring the SF2SF sync.")
.alias("cluster-config-file", "f")
.string("cluster-config-file")
.required("cluster-config-file")
.describe(
"dry-run",
"don't make any changes, just print what you're going to do."
)
.boolean("dry-run")
.default("dry-run", false)
.describe("strict", "Prevents associations from being unassigned")
.boolean("strict")
.default("strict", false)
.number("concurrency")
.default("concurrency", 10)
.describe("skip-picklists", "Skip assigning the picklists")
.boolean("skip-picklists")
.default("skip-picklists", false).argv;
this.configFile = argv["config-file"];
this.clusterConfigFile = argv["cluster-config-file"];
this.dryRun = argv["dry-run"];
this.strict = argv["strict"];
this.concurrency = argv["concurrency"];
this.skipPicklists = argv["skip-picklists"];
}
}
interface SubscribedFieldUpdate {
connection: Connection;
connectionObject: ConnectionObject;
connectionField: SubscribedField;
newValue?: SubscribedFieldOption;
}
async function checkDifferencesForConnection(
argv: Config,
page: Page,
connection: Connection,
changes: SubscribedFieldUpdate[]
): Promise<void> {
await page.goto(connection.url);
const subscribedObjects = await getSubscribedObjects(page);
for (const object of subscribedObjects) {
await gotoObject(page, object);
const fields = await getSubscribedFields(page);
let changesMade = false;
for (const field of fields) {
field.isStrict = argv.strict;
if (field.selectedValueNeedsUpdate()) {
const newValue = field.newValue();
changes.push({
connection,
connectionObject: object,
connectionField: field,
newValue
});
await selectMapping(page, field, newValue);
changesMade = true;
} else if (!field.value) {
const options = field.options.map((o) => o.name);
throw new Error(
`No value for ${connection.name} -> ${object.name} -> ${field.name}, ` +
`options: ${options.join(", ")}`
);
}
}
if (!argv.skipPicklists) {
if (!argv.dryRun && changesMade) {
await saveSubscribedFields(page);
await gotoObject(page, object);
changesMade = false;
}
const pickListMappings = await getPicklistMappingLinks(page);
for (const pickListMapping of pickListMappings) {
try {
await pickListMapping.click();
} catch (e) {
console.log(
`Failed ${connection.username} -> ${connection.name} -> ${object.name} -> ${pickListMapping.id}`,
e
);
throw e;
}
const picklistValues = await getPicklistValues(page);
for (const picklistValue of picklistValues) {
picklistValue.isStrict = argv.strict;
if (picklistValue.selectedValueNeedsUpdate()) {
const newValue = picklistValue.newValue();
changes.push({
connection,
connectionObject: object,
connectionField: picklistValue,
newValue
});
await selectMapping(page, picklistValue, newValue);
changesMade = true;
}
}
await savePicklistMapping(page);
}
}
if (!argv.dryRun && changesMade) {
await saveSubscribedFields(page);
}
}
}
async function checkDifferencesForConnectionSafely(
argv: Config,
browser: Browser,
connection: Connection,
changes: SubscribedFieldUpdate[]
): Promise<void> {
const page = await browser.newPage();
page.setDefaultNavigationTimeout(90000);
try {
console.log(`Checking ${connection.username} -> ${connection.name}`);
await checkDifferencesForConnection(argv, page, connection, changes);
console.log(`Finished ${connection.username} -> ${connection.name}`);
} catch (e) {
console.log(`Failed ${connection.username} -> ${connection.name}`, e);
throw e;
} finally {
await page.close();
}
}
(async (): Promise<void> => {
const argv = new Config();
const { clusterConfigFile, concurrency } = argv;
const clusterConfig = await SClusterConfig.fromPath(clusterConfigFile);
const browser = await puppeteer.launch({});
const connections = flatten(
await pAll(
clusterConfig.usernames.map(
(username) => (): Promise<Connection[]> =>
loginAndGetConnections(browser, username)
),
{ concurrency }
)
).filter((conn) => conn.isActive);
const differences: SubscribedFieldUpdate[] = [];
await pAll(
connections.map(
(connection) => (): Promise<void> =>
checkDifferencesForConnectionSafely(
argv,
browser,
connection,
differences
)
),
{ concurrency }
);
const result = differences.map(
({ connection, connectionObject, connectionField, newValue }) => ({
username: connection.username,
connection: connection.name,
object: connectionObject.name,
field: connectionField.name,
oldValue: (connectionField.value && connectionField.value.name) || "",
newValue: (newValue && newValue.name) || ""
})
);
console.log(JSON.stringify(result, null, " "));
await browser.close();
})();

Data sharing between Safari and standalone iPhone 12 iOS 14.3

I tried to share data between Safari browser and standalone PWA on iPhone12 with iOS 14.3.
The information, that this should work are here: https://firt.dev/ios-14/
I#ve tried this: https://www.netguru.com/codestories/how-to-share-session-cookie-or-state-between-pwa-in-standalone-mode-and-safari-on-ios
Without success.
Are there any suggestions to running this? Or is it not possible ...
This is the code
const CACHE_NAME = "auth";
const TOKEN_KEY = "token";
const FAKE_TOKEN = "sRKWQu6hCJgR25lslcf5s12FFVau0ugi";
// Cache Storage was designed for caching
// network requests with service workers,
// mainly to make PWAs work offline.
// You can give it any value you want in this case.
const FAKE_ENDPOINT = "/fake-endpoint";
const saveToken = async (token: string) => {
try {
const cache = await caches.open(CACHE_NAME);
const responseBody = JSON.stringify({
[TOKEN_KEY]: token
});
const response = new Response(responseBody);
await cache.put(FAKE_ENDPOINT, response);
console.log("Token saved! 🎉");
} catch (error) {
// It's up to you how you resolve the error
console.log("saveToken error:", { error });
}
};
const getToken = async () => {
try {
const cache = await caches.open(CACHE_NAME);
const response = await cache.match(FAKE_ENDPOINT);
if (!response) {
return null;
}
const responseBody = await response.json();
return responseBody[TOKEN_KEY];
} catch (error) {
// Gotta catch 'em all
console.log("getToken error:", { error });
}
};
const displayCachedToken = async () => {
const cachedToken = await getToken();
console.log({ cachedToken });
};
// Uncomment the line below to save the fake token
// saveToken(FAKE_TOKEN);
displayCachedToken();
Without success means no result, i've tried to set data in safari and get them in standalone pwa

Exception Firebase Auth on flutter, using vccode

I am developing a login system, using firebase, flutter and vscode.
I would like to know how to handle exceptions generated by Firebase.
If EMAIL is already registered.
Currently generating an error:
Exception has occurred.
PlatformException (PlatformException(ERROR_EMAIL_ALREADY_IN_USE, The email address is already in use by another account., null))
If the email is already registered, I want to inform the user.
CODE:
Future<void> signUp({#required Map<String, dynamic> userData,#required String pass,#required VoidCallback onSuccess,#required VoidCallback onFail}) async{
isLoading = true;
notifyListeners();
_auth.createUserWithEmailAndPassword(
email: userData["email"],
password: pass
).then((user) async{
firebaseUser = user;
await _saveUserData(userData);
onSuccess();
isLoading = false;
notifyListeners();
}).catchError((e){
print(e);
onFail();
isLoading = false;
notifyListeners();
});
}
If you want to perform subsequent operations when ERROR_EMAIL_ALREADY_IN_USE is emitted.
I think it's a good idea to catch a PlatformException and branch the process with code as shown below.
try {
final result = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} on PlatformException catch (exception) {
switch (exception.code) {
case 'ERROR_EMAIL_ALREADY_IN_USE':
// do something...
default:
break;
}
use on PlatformException catch (e) and if (e.message == 'ERROR_EMAIL_ALREADY_IN_USE') to handle this case.

splash screen and one time intro in flutter

I want my splash screen to always appear in my application and it does which is great, but I have a walk through after the splash screen and I want it to be a one time walk through, So i want to add an integer to the shared preferences with a value of 0 and everytime I open the splash screen the value is incremented by one, so when "number" equals 1 or greater at the second run the splash screen skips the walkthrough and goes to home , here is the code that I want to edit now :
void initState() {
// TODO: implement initState
super.initState();
Timer(Duration(seconds: 5), () => MyNavigator.goToIntro(context));
}
And I want it to be like :
void initState() {
// TODO: implement initState
super.initState();int number=0;//this is in the shared prefs
Timer(Duration(seconds: 5), () => if(number==0){MyNavigator.goToIntro(context));
}else{MyNavigator.goToHome(context));
number++;}
}
The below code prints perfectly as we expect(during first launch only, "First launch"). You can use your navigation logic instead of print.
#override
void initState() {
super.initState();
setValue();
}
void setValue() async {
final prefs = await SharedPreferences.getInstance();
int launchCount = prefs.getInt('counter') ?? 0;
prefs.setInt('counter', launchCount + 1);
if (launchCount == 0) {
print("first launch"); //setState to refresh or move to some other page
} else {
print("Not first launch");
}
}
We need to have the number value to be saved across multiple app launches. We can use shared_preference plugin to achieve this.
secondly, getData that saved in our device.
Future<bool> getSaveData() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
bool isIntroScreenOpenedBefore =
sharedPreferences.getBool("isIntroScreenOpened") ?? false;
print(sharedPreferences.containsKey("isIntroScreenOpened")); // check your key either it is save or not?
if (isIntroScreenOpenedBefore == true) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return LoginBoard();
}));
} else {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return WalKThroughScreen();
}));
}
return isIntroScreenOpenedBefore;
}
at first, let's save the data as boolean
Future<void> saveData() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
bool isIntroScreenOpened = true;
sharedPreferences.setBool("isIntroScreenOpened", isIntroScreenOpened); // saved data to your device.
}
Answer by #Dinesh Balasubramanian is works really fine.
But I have 4 initial screen that need to show once. I have done that using same logic in each screen. and then my app was showing 5th screen second time like fast forwarding all the previous screen and stopping on 5th screen.
To resolve this I am getting all the set Preferences at main.dart to open directly 5th screen. but when I do that I am having this problem,
"E/flutter (32606): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)]
Unhandled Exception: Navigator operation requested with a context that
does not include a Navigator.
E/flutter (32606): The context used to
push or pop routes from the Navigator must be that of a widget that is
a descendant of a Navigator widget."
Here is code to switch from main.dart:
int firstLogin, firstMobile, firstOtp, firstInfo;
void setValue() async {
final prefs = await SharedPreferences.getInstance();
firstLogin = prefs.getInt('counterLogin') ?? 0;
firstMobile = prefs.getInt('counterMobile') ?? 0;
firstOtp = prefs.getInt('counterOtp') ?? 0;
firstInfo = prefs.getInt('counterInfo') ?? 0;
prefs.setInt('counterLogin', firstLogin + 1);
prefs.setInt('counterMobile', firstMobile + 1);
prefs.setInt('counterOtp', firstOtp + 1);
prefs.setInt('counterInfo', firstInfo + 1);
if ((firstLogin == 0) && (firstMobile == 0) && (firstOtp == 0) && (firstInfo == 0)) {
setState(() {
print("first launch");
Navigator.of(context).pushNamed(LoginScreen.routeName);
});
} else {
setState(() {
print("not first launch");
Navigator.of(context).pushNamed(LandingSection.routeName);
});
}
}
And calling the setValue() in initState()
I am looking forward for solution.

Resources