Bridge library for VK Mini Apps to communicate with VK clients across iOS, Android, and Web platforms
—
Access device location data and geographic information with privacy controls and accuracy options for location-based features.
Get current device location with coordinates and accuracy information.
/**
* Get device geolocation data
* @returns Current location coordinates and accuracy
*/
function send(method: 'VKWebAppGetGeodata'): Promise<{
lat: number;
long: number;
accuracy?: number;
}>;
/**
* Set location for the application context
* @param props.location - Location string or coordinates
*/
function send(method: 'VKWebAppSetLocation', props: {
location: string;
}): Promise<{ result: true }>;Usage Examples:
// Get current location
try {
const location = await bridge.send('VKWebAppGetGeodata');
console.log('Latitude:', location.lat);
console.log('Longitude:', location.long);
console.log('Accuracy:', location.accuracy, 'meters');
// Use location data
displayUserLocation(location.lat, location.long);
findNearbyPlaces(location.lat, location.long);
} catch (error) {
console.error('Location access failed:', error);
handleLocationError(error);
}
// Set application location context
try {
await bridge.send('VKWebAppSetLocation', {
location: 'Moscow, Russia'
});
console.log('App location context set');
} catch (error) {
console.error('Failed to set location:', error);
}
// Check location availability before use
const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');
if (canGetLocation) {
const geoData = await bridge.send('VKWebAppGetGeodata');
processLocationData(geoData);
} else {
// Fallback: IP-based location or manual input
useAlternativeLocationMethod();
}Implement common location-based functionality patterns.
// Distance calculation
function calculateDistance(
lat1: number, lon1: number,
lat2: number, lon2: number
): number {
const R = 6371; // Radius of Earth in kilometers
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLon = (lon2 - lon1) * Math.PI / 180;
const a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c; // Distance in kilometers
}
// Nearby places finder
async function findNearbyPlaces(userLat: number, userLon: number) {
const places = [
{ name: 'Coffee Shop', lat: 55.7558, lon: 37.6176 },
{ name: 'Restaurant', lat: 55.7539, lon: 37.6208 },
{ name: 'Park', lat: 55.7527, lon: 37.6156 }
];
const nearbyPlaces = places
.map(place => ({
...place,
distance: calculateDistance(userLat, userLon, place.lat, place.lon)
}))
.filter(place => place.distance <= 5) // Within 5km
.sort((a, b) => a.distance - b.distance);
console.log('Nearby places:', nearbyPlaces);
return nearbyPlaces;
}
// Location-based content filtering
async function getLocationBasedContent() {
try {
const location = await bridge.send('VKWebAppGetGeodata');
// Determine region/country from coordinates
const region = await getRegionFromCoordinates(location.lat, location.long);
// Filter content based on location
const localizedContent = await fetchContentForRegion(region);
return {
location,
region,
content: localizedContent
};
} catch (error) {
// Fallback to default content
return {
location: null,
region: 'default',
content: await fetchDefaultContent()
};
}
}
// Reverse geocoding helper
async function getRegionFromCoordinates(lat: number, lon: number): Promise<string> {
// Simple region detection based on coordinates
if (lat >= 55 && lat <= 56 && lon >= 37 && lon <= 38) {
return 'moscow';
} else if (lat >= 59 && lat <= 60 && lon >= 30 && lon <= 31) {
return 'saint-petersburg';
} else if (lat >= 40 && lat <= 85 && lon >= 19 && lon <= 170) {
return 'russia';
} else {
return 'international';
}
}Handle location permissions and user privacy controls.
// Location permission checker
class LocationManager {
private hasLocationPermission = false;
async checkLocationPermission(): Promise<boolean> {
try {
// Check if geolocation is supported
const isSupported = await bridge.supportsAsync('VKWebAppGetGeodata');
if (!isSupported) {
return false;
}
// Check granted permissions
const permissions = await bridge.send('VKWebAppGetGrantedPermissions');
this.hasLocationPermission = permissions.permissions.includes('location');
return this.hasLocationPermission;
} catch (error) {
console.error('Permission check failed:', error);
return false;
}
}
async requestLocation(): Promise<{ lat: number; long: number } | null> {
try {
// Check permission first
if (!await this.checkLocationPermission()) {
console.log('Location permission not granted');
return null;
}
// Get location
const location = await bridge.send('VKWebAppGetGeodata');
return location;
} catch (error) {
this.handleLocationError(error);
return null;
}
}
private handleLocationError(error: any) {
switch (error.error_data?.error_code) {
case 6: // Permission denied
console.error('Location permission denied by user');
this.showPermissionDialog();
break;
case 10: // Location not available
console.error('Location services not available');
this.showLocationUnavailableMessage();
break;
case 7: // Timeout
console.error('Location request timed out');
this.showTimeoutMessage();
break;
default:
console.error('Location error:', error);
this.showGenericErrorMessage();
}
}
private showPermissionDialog() {
// Show UI explaining why location is needed
console.log('Please enable location permissions in VK app settings');
}
private showLocationUnavailableMessage() {
// Show message about location services
console.log('Location services are not available on this device');
}
private showTimeoutMessage() {
// Show timeout message with retry option
console.log('Location request timed out. Please try again.');
}
private showGenericErrorMessage() {
// Show generic error message
console.log('Unable to get location. Please try again later.');
}
}Optimize location requests with caching and accuracy controls.
// Location cache manager
class LocationCache {
private cache: {
location: { lat: number; long: number; accuracy?: number };
timestamp: number;
maxAge: number;
} | null = null;
async getLocation(maxAge: number = 300000): Promise<{ lat: number; long: number } | null> {
// Check cache first
if (this.cache &&
Date.now() - this.cache.timestamp < maxAge &&
(this.cache.location.accuracy || 100) <= 100) {
console.log('Using cached location');
return this.cache.location;
}
try {
// Get fresh location
const location = await bridge.send('VKWebAppGetGeodata');
// Update cache
this.cache = {
location,
timestamp: Date.now(),
maxAge
};
console.log('Got fresh location');
return location;
} catch (error) {
// Return cached location if fresh request fails
if (this.cache) {
console.log('Using stale cached location due to error');
return this.cache.location;
}
throw error;
}
}
clearCache() {
this.cache = null;
}
getCacheAge(): number {
return this.cache ? Date.now() - this.cache.timestamp : -1;
}
}
// Usage example
const locationCache = new LocationCache();
async function getCurrentLocation() {
try {
// Get location with 5-minute cache
const location = await locationCache.getLocation(300000);
return location;
} catch (error) {
console.error('Failed to get location:', error);
return null;
}
}Geolocation services are available on the following platforms:
Always check method support and handle permissions appropriately:
async function initializeLocation() {
const canGetLocation = await bridge.supportsAsync('VKWebAppGetGeodata');
if (canGetLocation) {
const locationManager = new LocationManager();
const hasPermission = await locationManager.checkLocationPermission();
if (hasPermission) {
const location = await locationManager.requestLocation();
if (location) {
console.log('Location initialized:', location);
return location;
}
} else {
console.log('Location permission required');
}
} else {
console.log('Geolocation not supported on this platform');
}
return null;
}// Privacy-conscious location request
async function requestLocationWithExplanation(reason: string) {
// Show explanation first
const userConsent = confirm(`This app needs your location to ${reason}. Allow location access?`);
if (!userConsent) {
console.log('User declined location access');
return null;
}
try {
const location = await bridge.send('VKWebAppGetGeodata');
console.log('Location granted:', location);
return location;
} catch (error) {
console.error('Location request failed:', error);
return null;
}
}Install with Tessl CLI
npx tessl i tessl/npm-vkontakte--vk-bridge