0
# Geolocation Services
1
2
Access device location data and geographic information with privacy controls and accuracy options for location-based features.
3
4
## Capabilities
5
6
### Location Data Access
7
8
Get current device location with coordinates and accuracy information.
9
10
```typescript { .api }
11
/**
12
* Get device geolocation data
13
* @returns Current location coordinates and accuracy
14
*/
15
function send(method: 'VKWebAppGetGeodata'): Promise<{
16
lat: number;
17
long: number;
18
accuracy?: number;
19
}>;
20
21
/**
22
* Set location for the application context
23
* @param props.location - Location string or coordinates
24
*/
25
function send(method: 'VKWebAppSetLocation', props: {
26
location: string;
27
}): Promise<{ result: true }>;
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
// Get current location
34
try {
35
const location = await bridge.send('VKWebAppGetGeodata');
36
console.log('Latitude:', location.lat);
37
console.log('Longitude:', location.long);
38
console.log('Accuracy:', location.accuracy, 'meters');
39
40
// Use location data
41
displayUserLocation(location.lat, location.long);
42
findNearbyPlaces(location.lat, location.long);
43
} catch (error) {
44
console.error('Location access failed:', error);
45
handleLocationError(error);
46
}
47
48
// Set application location context
49
try {
50
await bridge.send('VKWebAppSetLocation', {
51
location: 'Moscow, Russia'
52
});
53
console.log('App location context set');
54
} catch (error) {
55
console.error('Failed to set location:', error);
56
}
57
58
// Check location availability before use
59
const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');
60
if (canGetLocation) {
61
const geoData = await bridge.send('VKWebAppGetGeodata');
62
processLocationData(geoData);
63
} else {
64
// Fallback: IP-based location or manual input
65
useAlternativeLocationMethod();
66
}
67
```
68
69
### Location-Based Features
70
71
Implement common location-based functionality patterns.
72
73
```typescript
74
// Distance calculation
75
function calculateDistance(
76
lat1: number, lon1: number,
77
lat2: number, lon2: number
78
): number {
79
const R = 6371; // Radius of Earth in kilometers
80
const dLat = (lat2 - lat1) * Math.PI / 180;
81
const dLon = (lon2 - lon1) * Math.PI / 180;
82
const a =
83
Math.sin(dLat/2) * Math.sin(dLat/2) +
84
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
85
Math.sin(dLon/2) * Math.sin(dLon/2);
86
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
87
return R * c; // Distance in kilometers
88
}
89
90
// Nearby places finder
91
async function findNearbyPlaces(userLat: number, userLon: number) {
92
const places = [
93
{ name: 'Coffee Shop', lat: 55.7558, lon: 37.6176 },
94
{ name: 'Restaurant', lat: 55.7539, lon: 37.6208 },
95
{ name: 'Park', lat: 55.7527, lon: 37.6156 }
96
];
97
98
const nearbyPlaces = places
99
.map(place => ({
100
...place,
101
distance: calculateDistance(userLat, userLon, place.lat, place.lon)
102
}))
103
.filter(place => place.distance <= 5) // Within 5km
104
.sort((a, b) => a.distance - b.distance);
105
106
console.log('Nearby places:', nearbyPlaces);
107
return nearbyPlaces;
108
}
109
110
// Location-based content filtering
111
async function getLocationBasedContent() {
112
try {
113
const location = await bridge.send('VKWebAppGetGeodata');
114
115
// Determine region/country from coordinates
116
const region = await getRegionFromCoordinates(location.lat, location.long);
117
118
// Filter content based on location
119
const localizedContent = await fetchContentForRegion(region);
120
121
return {
122
location,
123
region,
124
content: localizedContent
125
};
126
} catch (error) {
127
// Fallback to default content
128
return {
129
location: null,
130
region: 'default',
131
content: await fetchDefaultContent()
132
};
133
}
134
}
135
136
// Reverse geocoding helper
137
async function getRegionFromCoordinates(lat: number, lon: number): Promise<string> {
138
// Simple region detection based on coordinates
139
if (lat >= 55 && lat <= 56 && lon >= 37 && lon <= 38) {
140
return 'moscow';
141
} else if (lat >= 59 && lat <= 60 && lon >= 30 && lon <= 31) {
142
return 'saint-petersburg';
143
} else if (lat >= 40 && lat <= 85 && lon >= 19 && lon <= 170) {
144
return 'russia';
145
} else {
146
return 'international';
147
}
148
}
149
```
150
151
### Location Permission Management
152
153
Handle location permissions and user privacy controls.
154
155
```typescript
156
// Location permission checker
157
class LocationManager {
158
private hasLocationPermission = false;
159
160
async checkLocationPermission(): Promise<boolean> {
161
try {
162
// Check if geolocation is supported
163
const isSupported = await bridge.supportsAsync('VKWebAppGetGeodata');
164
if (!isSupported) {
165
return false;
166
}
167
168
// Check granted permissions
169
const permissions = await bridge.send('VKWebAppGetGrantedPermissions');
170
this.hasLocationPermission = permissions.permissions.includes('location');
171
172
return this.hasLocationPermission;
173
} catch (error) {
174
console.error('Permission check failed:', error);
175
return false;
176
}
177
}
178
179
async requestLocation(): Promise<{ lat: number; long: number } | null> {
180
try {
181
// Check permission first
182
if (!await this.checkLocationPermission()) {
183
console.log('Location permission not granted');
184
return null;
185
}
186
187
// Get location
188
const location = await bridge.send('VKWebAppGetGeodata');
189
return location;
190
} catch (error) {
191
this.handleLocationError(error);
192
return null;
193
}
194
}
195
196
private handleLocationError(error: any) {
197
switch (error.error_data?.error_code) {
198
case 6: // Permission denied
199
console.error('Location permission denied by user');
200
this.showPermissionDialog();
201
break;
202
case 10: // Location not available
203
console.error('Location services not available');
204
this.showLocationUnavailableMessage();
205
break;
206
case 7: // Timeout
207
console.error('Location request timed out');
208
this.showTimeoutMessage();
209
break;
210
default:
211
console.error('Location error:', error);
212
this.showGenericErrorMessage();
213
}
214
}
215
216
private showPermissionDialog() {
217
// Show UI explaining why location is needed
218
console.log('Please enable location permissions in VK app settings');
219
}
220
221
private showLocationUnavailableMessage() {
222
// Show message about location services
223
console.log('Location services are not available on this device');
224
}
225
226
private showTimeoutMessage() {
227
// Show timeout message with retry option
228
console.log('Location request timed out. Please try again.');
229
}
230
231
private showGenericErrorMessage() {
232
// Show generic error message
233
console.log('Unable to get location. Please try again later.');
234
}
235
}
236
```
237
238
### Location Caching and Optimization
239
240
Optimize location requests with caching and accuracy controls.
241
242
```typescript
243
// Location cache manager
244
class LocationCache {
245
private cache: {
246
location: { lat: number; long: number; accuracy?: number };
247
timestamp: number;
248
maxAge: number;
249
} | null = null;
250
251
async getLocation(maxAge: number = 300000): Promise<{ lat: number; long: number } | null> {
252
// Check cache first
253
if (this.cache &&
254
Date.now() - this.cache.timestamp < maxAge &&
255
(this.cache.location.accuracy || 100) <= 100) {
256
console.log('Using cached location');
257
return this.cache.location;
258
}
259
260
try {
261
// Get fresh location
262
const location = await bridge.send('VKWebAppGetGeodata');
263
264
// Update cache
265
this.cache = {
266
location,
267
timestamp: Date.now(),
268
maxAge
269
};
270
271
console.log('Got fresh location');
272
return location;
273
} catch (error) {
274
// Return cached location if fresh request fails
275
if (this.cache) {
276
console.log('Using stale cached location due to error');
277
return this.cache.location;
278
}
279
throw error;
280
}
281
}
282
283
clearCache() {
284
this.cache = null;
285
}
286
287
getCacheAge(): number {
288
return this.cache ? Date.now() - this.cache.timestamp : -1;
289
}
290
}
291
292
// Usage example
293
const locationCache = new LocationCache();
294
295
async function getCurrentLocation() {
296
try {
297
// Get location with 5-minute cache
298
const location = await locationCache.getLocation(300000);
299
return location;
300
} catch (error) {
301
console.error('Failed to get location:', error);
302
return null;
303
}
304
}
305
```
306
307
## Platform Availability
308
309
Geolocation services are available on the following platforms:
310
311
- **iOS WebView**: Full GPS access with VKWebAppGetGeodata
312
- **Android WebView**: Full GPS access with VKWebAppGetGeodata
313
- **Web/Desktop**: Limited availability (may not work in all contexts)
314
315
Always check method support and handle permissions appropriately:
316
317
```typescript
318
async function initializeLocation() {
319
const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');
320
321
if (canGetLocation) {
322
const locationManager = new LocationManager();
323
const hasPermission = await locationManager.checkLocationPermission();
324
325
if (hasPermission) {
326
const location = await locationManager.requestLocation();
327
if (location) {
328
console.log('Location initialized:', location);
329
return location;
330
}
331
} else {
332
console.log('Location permission required');
333
}
334
} else {
335
console.log('Geolocation not supported on this platform');
336
}
337
338
return null;
339
}
340
```
341
342
## Privacy and Best Practices
343
344
1. **Request location only when needed** - Don't request location access immediately on app start
345
2. **Explain why location is needed** - Show clear UI explaining the benefit to users
346
3. **Handle permission denial gracefully** - Provide alternative functionality when location is denied
347
4. **Cache location data** - Avoid frequent location requests to preserve battery
348
5. **Respect accuracy** - Use appropriate accuracy thresholds for your use case
349
6. **Provide manual alternatives** - Allow users to manually enter location when automatic detection fails
350
351
```typescript
352
// Privacy-conscious location request
353
async function requestLocationWithExplanation(reason: string) {
354
// Show explanation first
355
const userConsent = confirm(`This app needs your location to ${reason}. Allow location access?`);
356
357
if (!userConsent) {
358
console.log('User declined location access');
359
return null;
360
}
361
362
try {
363
const location = await bridge.send('VKWebAppGetGeodata');
364
console.log('Location granted:', location);
365
return location;
366
} catch (error) {
367
console.error('Location request failed:', error);
368
return null;
369
}
370
}
371
```