Closed GoethelHB closed 2 months ago
Show me all the code where you interact with BackgroundGeolocation
Hello Chris, thank you for your fast reply. I sent you a mail with all the code, where interacting with the plugin.
Post your code here. Not email.
I dont want ALL your code, only code that referenced BackgroundGeolocation
Ok, so here is the related code.
Config:
const { settings } = await getGeofenceAccuracyLevel();
const params = new URLSearchParams({});
const refreshUrl = `url`;
return {
...settings,
//desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
//distanceFilter: 10,
//stopTimeout: 5,
logLevel: (process.env.BUILD_MODE === "production") ? BackgroundGeolocation.LOG_LEVEL_ERROR : BackgroundGeolocation.LOG_LEVEL_VERBOSE,
logMaxDays: (process.env.BUILD_MODE === "production") ? 3 : 28,
enableHeadless: true,
stopOnTerminate: false,
startOnBoot: true,
locationAuthorizationAlert: i18n.t("geofence.iosLocationAuthorizationAlert", { returnObjects: true }),
backgroundPermissionRationale: i18n.t("geofence.androidPopupAllowAllTheTime", { returnObjects: true }),
notification: {
smallIcon: "drawable/notification_icon",
largeIcon: "", // empty string to remove (default) icon
text: i18n.t("geofence.androidNotification.text"),
},
disableProviderChangeRecord: true,
disableLocationAuthorizationAlert: false,
//disableMotionActivityUpdates: true, if true will no longer ask the physical activity permission, which the plugin would need for better geofencing
persistMode: BackgroundGeolocation.PERSIST_MODE_GEOFENCE,
url: geofenceEventUrl,
method: "POST",
autoSync: true,
geofenceTemplate: JSON.stringify({
id: deviceId,
gwId: "<%= geofence.identifier %>",
loc: "<%= geofence.action %>",
ts: "<%= timestamp %>",
}),
httpRootProperty: ".",
headers: restHeaders,
authorization: {
strategy: "JWT",
accessToken: accessToken,
refreshToken: refreshToken,
refreshUrl: refreshUrl,
refreshPayload: {
[name]: "{refreshToken}",
},
refreshHeaders: {
...
},
},
}
Init / ready:
if (Capacitor.isNativePlatform()) {
try {
const oldConfig = await BackgroundGeolocation.getState();
await BackgroundGeolocation.ready(oldConfig);
} catch (error) {
console.warn("renderIfAuthenticated, BackgroundGeolocation.ready failed", error);
}
}
const registerGeofenceListeners = async (): Promise<void> => {
await BackgroundGeolocation.removeListeners();
BackgroundGeolocation.onAuthorization(async ({ status, success, error, response }) => {
if (success) {
if (typeof response === "object" && typeof response.access_token === "string" && typeof response.refresh_token === "string") { // && typeof response.old_token_id === "string"
await setTokens({
accessToken: response.access_token,
refreshToken: response.refresh_token,
});
} else {
console.warn("onAuthorization invalid body response", status, response);
}
} else {
console.warn("onAuthorization unsuccessful", status, error);
}
});
};
export const readyGeofence = async (): Promise<void> => {
try {
const { accessToken, refreshToken } = await getTokens();
if (accessToken !== "" && refreshToken !== "") {
const config = await getDefaultGeofenceConfig(accessToken, refreshToken);
const { enabled } = await BackgroundGeolocation.setConfig(config);
await registerGeofenceListeners();
if (enabled) {
// TODO: fights the symptom of a rare bug, where the plugin is in a bugged state and can only be repaired by restarting it.
void restartGeofencePlugin(); // long running task -> no await
}
} else {
console.warn("tokens are empty in readyGeofence");
}
} catch (error) {
console.error("readyGeofence catch", error);
}
};
export const restartGeofencePlugin = async (): Promise<void> => {
try {
const { enabled } = await BackgroundGeolocation.getState();
if (enabled) {
await BackgroundGeolocation.stop();
}
const geofs = await BackgroundGeolocation.getGeofences();
await enableDisableGeofence(geofs); // This sends exit events and enter events by readding all geofences
} catch (error) {
console.warn("Error while trying to restartGeofencePlugin");
}
};
Check permissions:
export const checkAndRequestGeolocationPermission = async (requestEnable: boolean = true): Promise<AuthorizationStatus> => {
try {
const { status } = await BackgroundGeolocation.getProviderState();
if (requestEnable && ![BackgroundGeolocation.AUTHORIZATION_STATUS_WHEN_IN_USE, BackgroundGeolocation.AUTHORIZATION_STATUS_ALWAYS].includes(status)) {
try {
return await BackgroundGeolocation.requestPermission();
} catch (authStatus) {
console.warn("Geolocation-Permissions not granted", authStatus);
return authStatus as AuthorizationStatus;
}
} else {
return status;
}
} catch (error) {
console.error("checkAndRequestGeolocationPermission error", error);
return BackgroundGeolocation.AUTHORIZATION_STATUS_NOT_DETERMINED;
}
};
Enable / disable:
const enableDisableGeofence = async (newGeofences: Array<Geofence>): Promise<void> => {
const { enabled, url } = await BackgroundGeolocation.getState();
let geofenceUrl = url;
let hasGeofences = false;
try {
const geofences = await BackgroundGeolocation.getGeofences();
hasGeofences = (geofences.length + newGeofences.length) > 0;
} catch (error) {
console.warn("Exception in 'BackgroundGeolocation.getGeofences'", error);
}
if (enabled && !hasGeofences) {
await BackgroundGeolocation.stop();
} else if (!enabled && hasGeofences) {
const authorizationStatus = await checkAndRequestGeolocationPermission();
if ([BackgroundGeolocation.AUTHORIZATION_STATUS_WHEN_IN_USE, BackgroundGeolocation.AUTHORIZATION_STATUS_ALWAYS].includes(authorizationStatus)) {
// fallback, if url is undefined
const { locationTracking } = await getGeofenceAccuracyLevel(); // defaults to low
let startGeofenceState: State;
if (locationTracking) {
startGeofenceState = await BackgroundGeolocation.start();
} else {
startGeofenceState = await BackgroundGeolocation.startGeofences();
}
if ((geofenceUrl === undefined || geofenceUrl.length === 0) && startGeofenceState.url) {
geofenceUrl = startGeofenceState.url;
}
}
}
if (newGeofences.length > 0) {
await BackgroundGeolocation.addGeofences(newGeofences);
}
const { status } = await BackgroundGeolocation.getProviderState();
if (geofenceUrl && status === BackgroundGeolocation.AUTHORIZATION_STATUS_ALWAYS && newGeofences.length > 0) {
await sendExitEvents(newGeofences, geofenceUrl);
try {
await BackgroundGeolocation.changePace(true);
} catch {
console.warn("enableDisableGeofence, could not changePace, error!");
}
}
};
const enableDisable = async (data, geofenceAllowed: boolean): Promise<void> => { // called by some events
const geofenceExists = await BackgroundGeolocation.geofenceExists(data.id);
if (geofenceAllowed && !geofenceExists) {
const newGeofence = await makeGeofence(data.id, data.latitude!, data.longitude!, data.geofence_radius);
if (newGeofence) {
await enableDisableGeofence([newGeofence]);
}
} else if (!geofenceAllowed && geofenceExists) {
await BackgroundGeolocation.removeGeofence(data.id);
await enableDisableGeofence([]);
}
};
export const checkGeofenceRemoved = async (id): Promise<void> => {
try {
if (await BackgroundGeolocation.geofenceExists(id)) {
await BackgroundGeolocation.removeGeofence(id);
await enableDisableGeofence([]);
}
} catch (error) {
console.error("checkGeofenceRemoved error", error);
}
};
change acc level:
export const setGeofenceAccuracyLevel = async (value: GeofenceAccuracyLevel["value"]): Promise<void> => {
await Preferences.set({ key: "geofence_accuracy_level", value: value });
const { locationTracking, settings } = await getGeofenceAccuracyLevel();
const state = await BackgroundGeolocation.setConfig(settings);
if (state.enabled) {
if (state.trackingMode === 0 && locationTracking) {
await BackgroundGeolocation.stop();
await BackgroundGeolocation.start();
} else if (state.trackingMode === 1 && !locationTracking) {
await BackgroundGeolocation.stop();
await BackgroundGeolocation.startGeofences();
}
}
};
logout:
const { enabled } = await BackgroundGeolocation.getState();
if (enabled) {
await BackgroundGeolocation.removeGeofences();
await BackgroundGeolocation.stop();
}
And here the android native code:
public class RefreshWorker extends Worker {
public Result doWork() {
Context context = getApplicationContext();
String url = getInputData().getString("url");
int status = refreshTokens(url);
if (status >= 200 && status <= 299) {
CookieManager.getInstance().flush();
String refreshToken = getRefreshCookieValue(context);
String accessToken = getAccessCookieValue(context);
TSAuthorization authorization = TSConfig.getInstance(context).getAuthorization();
authorization.setRefreshToken(refreshToken);
authorization.setAccessToken(accessToken);
TSConfig.getInstance(context)
.updateWithBuilder()
.setAuthorization(authorization)
.commit();
BackgroundGeolocation.getInstance(context).sync();
}
// TODO: fights the symptom of a rare bug, where the plugin is in a bugged state and can only be repaired by restarting it.
what does “bugged state” mean?
I can reproduce your error by calling .geofenceExists(null)
.
I suggest you check this code:
const geofenceExists = await BackgroundGeolocation.geofenceExists(data.id);
Ensure that your data.id
contains a String
.
Hello Chris, thanks a lot for your fast reply. Changed the code to check for data.id . Is it possible to catch the error too, if this approach isn't helping?
For your first question about the rare bug: We had an issue, if the app is booting and the plugin isn't fully started, and you get a geofence event, it wasn't send out. So we just restarted the magic. It might be possible, we fixed this already, but not yet retested.
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.
Hello, got some crashreports during appstart from sqlite, while sdk is checking GeofenceDAO.exists.
Fatal Exception: java.lang.IllegalArgumentException the bind value at index 1 is null
Your Environment
Expected Behavior
App shouldn't crash, if there is an sqlite error or if queryargs are missing.
Actual Behavior
App crashed with: Fatal Exception: java.lang.IllegalArgumentException the bind value at index 1 is null
Debug logs
Logs
``` android.database.sqlite.SQLiteProgram.bindString (SQLiteProgram.java:184) android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings (SQLiteProgram.java:220) android.database.sqlite.SQLiteDirectCursorDriver.query (SQLiteDirectCursorDriver.java:49) android.database.sqlite.SQLiteDatabase.rawQueryWithFactory (SQLiteDatabase.java:2254) android.database.sqlite.SQLiteDatabase.queryWithFactory (SQLiteDatabase.java:2101) android.database.sqlite.SQLiteDatabase.query (SQLiteDatabase.java:1972) android.database.sqlite.SQLiteDatabase.query (SQLiteDatabase.java:2178) com.transistorsoft.locationmanager.data.sqlite.GeofenceDAO.exists (Unknown Source:25) com.transistorsoft.locationmanager.geofence.TSGeofenceManager$f.run (Unknown Source:10) java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:644) java.lang.Thread.run (Thread.java:1012) ```