Converted Native to Turbo Module

This commit is contained in:
Tanmaya Biswal 2025-04-24 11:53:45 +05:30
parent b1f1f1e6ea
commit 9ae4a15260
15 changed files with 4571 additions and 368 deletions

299
App.tsx
View File

@ -8,29 +8,28 @@
* @format * @format
*/ */
import React from 'react'; import React, {useEffect} from 'react';
import { import {
SafeAreaView, SafeAreaView,
ScrollView,
StatusBar, StatusBar,
StyleSheet, StyleSheet,
Text, Text,
View, View,
Switch, Switch,
Button, Button,
Alert,
PermissionsAndroid, PermissionsAndroid,
// ToastAndroid, // ToastAndroid,
NativeModules, // NativeModules,
} from 'react-native'; } from 'react-native';
import BackgroundFetch from 'react-native-background-fetch';
import Geolocation, { import Geolocation, {
GeolocationError, GeolocationError,
GeolocationResponse, // GeolocationResponse,
} from '@react-native-community/geolocation'; } from '@react-native-community/geolocation';
const {ForegroundHeadlessModule} = NativeModules; import NativeTaskRunner from './specs/NativeTaskRunner';
// const {ForegroundHeadlessModule} = NativeModules;
const Colors = { const Colors = {
gold: '#fedd1e', gold: '#fedd1e',
@ -42,14 +41,37 @@ const Colors = {
}; };
/// Util class for handling fetch-event peristence in AsyncStorage. /// Util class for handling fetch-event peristence in AsyncStorage.
import Event from './src/Event'; // import Event from './src/Event';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Location from 'expo-location';
Geolocation.setRNConfiguration({ Geolocation.setRNConfiguration({
skipPermissionRequests: true, skipPermissionRequests: true,
locationProvider: 'auto', locationProvider: 'auto',
}); });
/*
function geoLocationPromise(): Promise<GeolocationResponse | GeolocationError> {
return new Promise((resolve, reject) => {
Geolocation.getCurrentPosition(
info => {
console.log(info);
resolve(info);
},
error => {
console.log(error);
reject(error);
},
{
timeout: 20000,
maximumAge: 0,
// enableHighAccuracy: true,
},
);
});
}
*/
const requestPermissions = async () => { const requestPermissions = async () => {
try { try {
const granted = await PermissionsAndroid.request( const granted = await PermissionsAndroid.request(
@ -85,219 +107,32 @@ const requestPermissions = async () => {
} }
}; };
function geoLocationPromise(): Promise<GeolocationResponse | GeolocationError> {
return new Promise((resolve, reject) => {
Geolocation.getCurrentPosition(
info => {
console.log(info);
resolve(info);
},
error => {
console.log(error);
reject(error);
},
{
timeout: 20000,
maximumAge: 0,
// enableHighAccuracy: true,
},
);
});
}
const App = () => { const App = () => {
const [enabled, setEnabled] = React.useState(false); const [enabled, setEnabled] = React.useState(false);
const [status, setStatus] = React.useState(-1);
const [events, setEvents] = React.useState<Event[]>([]);
React.useEffect(() => { useEffect(() => {
async function asyncTask() { async function getCurrentLocation() {
await requestPermissions(); let location = await Location.getLastKnownPositionAsync({});
initBackgroundFetch(); console.log(location);
loadEvents();
} }
async function xy() {
asyncTask();
}, []);
/// Configure BackgroundFetch.
///
const initBackgroundFetch = async () => {
const status: number = await BackgroundFetch.configure(
{
minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
stopOnTerminate: false,
enableHeadless: true,
startOnBoot: false,
// Android options
forceAlarmManager: false, // <-- Set true to bypass JobScheduler.
requiredNetworkType: BackgroundFetch.NETWORK_TYPE_NONE, // Default
requiresCharging: false, // Default
requiresDeviceIdle: false, // Default
requiresBatteryNotLow: false, // Default
requiresStorageNotLow: false, // Default
},
async (taskId: string) => {
console.log('[BackgroundFetch] taskId', taskId);
if (taskId === 'react-native-background-fetch') {
// console.log('[BackgroundFetch] taskId', taskId);
const event = await Event.create(taskId, false);
// Update state.
setEvents(prev => [...prev, event]);
}
if (taskId === 'com.transistorsoft.customtask') {
// Geolocation.getCurrentPosition(
// async info => {
// console.log(info);
// const event = await Event.create(taskId, false, `lat-${info.coords.latitude};long-${info.coords.longitude}`);
// },
// err => console.log(err),
// {
// timeout: 10000,
// maximumAge: 10000,
// enableHighAccuracy: false,
// },
// );
try { try {
const locInfo = (await geoLocationPromise()) as GeolocationResponse; await requestPermissions();
const event = await Event.create( const x = await AsyncStorage.getItem('locationtask');
taskId, if (x === '1') {
false,
`lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`,
);
// Update state.
setEvents(prev => [...prev, event]);
} catch (error) {
const g = error as GeolocationError;
if (g.message) {
const event = await Event.create(taskId, false, `${g.message}`);
// Update state.
setEvents(prev => [...prev, event]);
} else {
const event = await Event.create(taskId, false);
// Update state.
setEvents(prev => [...prev, event]);
}
}
// console.log('Running [customtask] here!');
}
// Finish.
BackgroundFetch.finish(taskId);
},
(taskId: string) => {
// Oh No! Our task took too long to complete and the OS has signalled
// that this task must be finished immediately.
console.log('[Fetch] TIMEOUT taskId:', taskId);
BackgroundFetch.finish(taskId);
},
);
setStatus(status);
setEnabled(true); setEnabled(true);
};
/// Load persisted events from AsyncStorage.
///
const loadEvents = () => {
Event.all()
.then(data => {
setEvents(data as Event[]);
})
.catch(error => {
Alert.alert('Error', 'Failed to load data from AsyncStorage: ' + error);
});
};
/// Toggle BackgroundFetch ON/OFF
///
const onClickToggleEnabled = (value: boolean) => {
setEnabled(value);
if (value) {
BackgroundFetch.start();
} else { } else {
BackgroundFetch.stop(); setEnabled(false);
} }
};
/// [Status] button handler. getCurrentLocation();
/// } catch (error) {
const onClickStatus = () => { console.log('Something went wrong', error);
BackgroundFetch.status().then((status: number) => {
let statusConst = '';
switch (status) {
case BackgroundFetch.STATUS_AVAILABLE:
statusConst = 'STATUS_AVAILABLE';
break;
case BackgroundFetch.STATUS_DENIED:
statusConst = 'STATUS_DENIED';
break;
case BackgroundFetch.STATUS_RESTRICTED:
statusConst = 'STATUS_RESTRICTED';
break;
} }
Alert.alert('BackgroundFetch.status()', `${statusConst} (${status})`);
});
};
/// [scheduleTask] button handler.
/// Schedules a custom-task to fire in 5000ms
///
const onClickScheduleTask = () => {
const delay = 600000;
BackgroundFetch.scheduleTask({
taskId: 'com.transistorsoft.customtask',
stopOnTerminate: false,
enableHeadless: true,
delay: delay,
forceAlarmManager: false,
periodic: true,
})
.then(() => {
Alert.alert(
'scheduleTask',
'Scheduled task with delay: ' + delay + 'ms',
);
})
.catch(error => {
Alert.alert('scheduleTask ERROR', error);
});
};
/// Clear the Events list.
///
const onClickClear = () => {
Event.destroyAll();
setEvents([]);
};
/// Fetch events renderer.
///
const renderEvents = () => {
if (!events.length) {
return (
<Text style={{padding: 10, fontSize: 16}}>
Waiting for BackgroundFetch events...
</Text>
);
} }
return events
.slice() xy();
.reverse() }, []);
.map(event => (
<View key={event.key} style={styles.event}>
<View style={{flexDirection: 'row'}}>
<Text style={styles.taskId}>
{event.taskId}&nbsp;{event.isHeadless ? '[Headless]' : ''}
</Text>
</View>
<Text style={styles.remark}>Remark - {event.location}</Text>
<Text style={styles.timestamp}>{event.timestamp}</Text>
</View>
));
};
async function onLocPress(): Promise<void> { async function onLocPress(): Promise<void> {
try { try {
@ -306,7 +141,18 @@ const App = () => {
// `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`, // `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`,
// 5000, // 5000,
// ); // );
ForegroundHeadlessModule.startService(); if (enabled) {
return;
}
try {
// ForegroundHeadlessModule.startService();
NativeTaskRunner.startService();
setEnabled(true);
AsyncStorage.setItem('locationtask', '1');
} catch (error) {
console.log(error);
}
console.log('Did it run?'); console.log('Did it run?');
} catch (error) { } catch (error) {
const g = error as GeolocationError; const g = error as GeolocationError;
@ -319,19 +165,14 @@ const App = () => {
} }
function onLocStop() { function onLocStop() {
ForegroundHeadlessModule.stopService(); try {
AsyncStorage.getItem('watchId', (err, result) => { // ForegroundHeadlessModule.stopService();
if (err) { NativeTaskRunner.stopService();
console.log('Couldnt get WatchID', err); setEnabled(false);
return; AsyncStorage.setItem('locationtask', '0');
} catch (error) {
console.log(error);
} }
console.log(result);
if (result) {
Geolocation.clearWatch(+result);
}
});
} }
return ( return (
@ -342,19 +183,9 @@ const App = () => {
<Text style={styles.title}>BGFetch Demo</Text> <Text style={styles.title}>BGFetch Demo</Text>
<Button title="Loc" onPress={onLocPress} /> <Button title="Loc" onPress={onLocPress} />
<Button title="Stop" onPress={onLocStop} /> <Button title="Stop" onPress={onLocStop} />
<Switch value={enabled} onValueChange={onClickToggleEnabled} />
</View> </View>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.eventList}>
{renderEvents()}
</ScrollView>
<View style={styles.toolbar}> <View style={styles.toolbar}>
<Button title={'status: ' + status} onPress={onClickStatus} /> <Switch value={enabled} />
<Text>&nbsp;</Text>
<Button title="scheduleTask" onPress={onClickScheduleTask} />
<View style={{flex: 1}} />
<Button title="clear" onPress={onClickClear} />
</View> </View>
</View> </View>
</SafeAreaView> </SafeAreaView>

View File

@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

View File

@ -45,7 +45,7 @@ public class ForegroundHeadlessService extends Service {
HeadlessJsTaskService.acquireWakeLockNow(context); HeadlessJsTaskService.acquireWakeLockNow(context);
// Schedule next execution // Schedule next execution
handler.postDelayed(this, 60000); handler.postDelayed(this, 120000);
} }
}; };

View File

@ -1,4 +1,5 @@
package com.poclocationgather package com.poclocationgather
import expo.modules.ReactActivityDelegateWrapper
import com.facebook.react.ReactActivity import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate import com.facebook.react.ReactActivityDelegate
@ -18,5 +19,5 @@ class MainActivity : ReactActivity() {
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled] * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/ */
override fun createReactActivityDelegate(): ReactActivityDelegate = override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled))
} }

View File

@ -1,4 +1,7 @@
package com.poclocationgather package com.poclocationgather
import android.content.res.Configuration
import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper
import android.app.Application import android.app.Application
import com.facebook.react.PackageList import com.facebook.react.PackageList
@ -11,16 +14,27 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader import com.facebook.soloader.SoLoader
import com.nativetaskrunner.NativeTaskRunnerPackage
class MainApplication : Application(), ReactApplication { class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost = override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) { ReactNativeHostWrapper(this, object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> = override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply { PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example: // Packages that cannot be autolinked yet can be added manually here, for example:
add(ForegroundHeadlessPackage()) add(ForegroundHeadlessPackage())
add(NativeTaskRunnerPackage())
} }
// override fun getPackages(): List<ReactPackage> {
// val packages = PackageList(this).packages
// // Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// packages.add(new ForegroundHeadlessPackage());
// packages.add(new NativeTaskRunnerPackage());
// return packages
// }
override fun getJSMainModuleName(): String = "index" override fun getJSMainModuleName(): String = "index"
@ -28,10 +42,10 @@ class MainApplication : Application(), ReactApplication {
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
} })
override val reactHost: ReactHost override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost) get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -40,5 +54,11 @@ class MainApplication : Application(), ReactApplication {
// If you opted-in for the New Architecture, we load the native entry point for this app. // If you opted-in for the New Architecture, we load the native entry point for this app.
load() load()
} }
ApplicationLifecycleDispatcher.onApplicationCreate(this)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
} }
} }

View File

@ -29,10 +29,6 @@ allprojects {
// Android JSC is installed from npm // Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist") url("$rootDir/../node_modules/jsc-android/dist")
} }
maven {
// react-native-background-fetch
url("${project(':react-native-background-fetch').projectDir}/libs")
}
} }
} }

View File

@ -1,6 +1,21 @@
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") } plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } extensions.configure(com.facebook.react.ReactSettingsExtension){ ex ->
def command = [
'node',
'--no-warnings',
'--eval',
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
'react-native-config',
'--json',
'--platform',
'android'
].toList()
ex.autolinkLibrariesFromCommand(command)
}
rootProject.name = 'POCLocationGather' rootProject.name = 'POCLocationGather'
include ':app' include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin') includeBuild('../node_modules/@react-native/gradle-plugin')
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle")
useExpoModules()

View File

@ -1,4 +1,14 @@
{ {
"name": "POCLocationGather", "name": "POCLocationGather",
"displayName": "POCLocationGather" "displayName": "POCLocationGather",
"expo": {
"plugins": [
[
"expo-location",
{
"locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location."
}
]
]
}
} }

View File

@ -16,7 +16,7 @@
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; containerPortal = 83CBB9F71A601CBA00E9B192;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A; remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = POCLocationGather; remoteInfo = POCLocationGather;
@ -85,7 +85,7 @@
name = Libraries; name = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
83CBB9F61A601CBA00E9B192 = { 83CBB9F61A601CBA00E9B192 /* PBXGroup */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13B07FAE1A68108700A75B9A /* POCLocationGather */, 13B07FAE1A68108700A75B9A /* POCLocationGather */,
@ -143,7 +143,7 @@
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = { 83CBB9F71A601CBA00E9B192 = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1210; LastUpgradeCheck = 1210;
@ -161,7 +161,7 @@
en, en,
Base, Base,
); );
mainGroup = 83CBB9F61A601CBA00E9B192; mainGroup = 83CBB9F61A601CBA00E9B192 /* PBXGroup */;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
@ -409,6 +409,7 @@
"-DFOLLY_HAVE_CLOCK_GETTIME=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1",
); );
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
}; };
name = Debug; name = Debug;
}; };
@ -475,6 +476,7 @@
); );
SDKROOT = iphoneos; SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
SWIFT_VERSION = 5.0;
}; };
name = Release; name = Release;
}; };
@ -501,5 +503,5 @@
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; rootObject = 83CBB9F71A601CBA00E9B192;
} }

View File

@ -1,10 +1,12 @@
import UIKit import UIKit
import ExpoModulesCore
import Expo
import React import React
import React_RCTAppDelegate import React_RCTAppDelegate
import ReactAppDependencyProvider import ReactAppDependencyProvider
@main @main
class AppDelegate: RCTAppDelegate { class AppDelegate: ExpoAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
self.moduleName = "POCLocationGather" self.moduleName = "POCLocationGather"
self.dependencyProvider = RCTAppDependencyProvider() self.dependencyProvider = RCTAppDependencyProvider()

View File

@ -1,3 +1,4 @@
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
# Resolve react_native_pods.rb with node to allow for hoisting # Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p', require Pod::Executable.execute_command('node', ['-p',
'require.resolve( 'require.resolve(
@ -15,7 +16,24 @@ if linkage != nil
end end
target 'POCLocationGather' do target 'POCLocationGather' do
config = use_native_modules! use_expo_modules!
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
else
config_command = [
'node',
'--no-warnings',
'--eval',
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
'react-native-config',
'--json',
'--platform',
'ios'
]
end
config = use_native_modules!(config_command)
use_react_native!( use_react_native!(
:path => config[:reactNativePath], :path => config[:reactNativePath],

4461
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,21 @@
"start": "react-native start", "start": "react-native start",
"test": "jest" "test": "jest"
}, },
"codegenConfig": {
"name": "NativeTaskRunnerSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.nativetaskrunner"
}
},
"dependencies": { "dependencies": {
"@react-native-async-storage/async-storage": "^2.1.2", "@react-native-async-storage/async-storage": "^2.1.2",
"@react-native-community/geolocation": "^3.4.0", "@react-native-community/geolocation": "^3.4.0",
"expo": "~52.0.0",
"expo-location": "~18.0.10",
"react": "18.3.1", "react": "18.3.1",
"react-native": "0.77.0", "react-native": "0.77.0"
"react-native-background-fetch": "^4.2.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.25.2", "@babel/core": "^7.25.2",

View File

@ -0,0 +1,9 @@
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
startService(): void;
stopService(): void;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeTaskRunner');

View File

@ -1,29 +1,33 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; // import AsyncStorage from '@react-native-async-storage/async-storage';
import Geolocation from '@react-native-community/geolocation'; // import Geolocation from '@react-native-community/geolocation';
import * as Location from 'expo-location';
module.exports = async () => { module.exports = async () => {
console.log('Background Geolocation task has hopefully started'); console.log('Background Geolocation task has hopefully started');
Geolocation.setRNConfiguration({ // Geolocation.setRNConfiguration({
skipPermissionRequests: false, // skipPermissionRequests: false,
locationProvider: 'playServices', // locationProvider: 'playServices',
}); // });
const watchId = Geolocation.getCurrentPosition( // const watchId = Geolocation.getCurrentPosition(
pos => // pos =>
console.log( // console.log(
'[Background location]', // '[Background location]',
pos.coords.latitude, // pos.coords.latitude,
'//', // '//',
pos.coords.longitude, // pos.coords.longitude,
), // ),
err => console.log('Location Error while running in Background', err), // err => console.log('Location Error while running in Background', err),
{ // {
interval: 180000, // interval: 180000,
maximumAge: 0, // maximumAge: 0,
timeout: 20000, // timeout: 20000,
}, // },
); // );
await AsyncStorage.setItem('watchId', `${watchId}`); let location = await Location.getLastKnownPositionAsync({});
console.log(location);
// await AsyncStorage.setItem('watchId', `${watchId}`);
}; };