Skip to content

Commit

Permalink
add support for getCurrentLocation
Browse files Browse the repository at this point in the history
  • Loading branch information
HarshaR1642 committed Aug 17, 2024
1 parent 467b62d commit 82bf2cf
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 2 deletions.
90 changes: 90 additions & 0 deletions android/src/main/java/com/rnbridge/geofencing/GeofenceManager.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.rnbridge.geofencing

import android.Manifest
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.os.Build
import android.util.Log
import androidx.core.app.ActivityCompat
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.WritableArray
import com.google.android.gms.location.Geofence
import com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER
Expand All @@ -17,6 +23,8 @@ import com.google.android.gms.location.GeofencingRequest
import com.google.android.gms.location.LocationServices
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.util.Locale
import java.util.TimeZone

private const val REQUEST_CODE = 1729

Expand All @@ -37,6 +45,44 @@ class GeofenceManager(private val context: Context) {
)
}

@SuppressLint("MissingPermission")
fun getCurrentLocation(promise: Promise) {
if (!isForegroundLocationAuthorized()) {
promise.reject(Error("Location permission not given"))
return
}
val response = Arguments.createMap()
val activity = (context as ReactApplicationContext).currentActivity ?: return
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity)
fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
if (location == null) {
promise.reject(Error("Location is undefined"))
return@addOnSuccessListener
}
response.putDouble("latitude", location.latitude)
response.putDouble("longitude", location.longitude)
response.putDouble("altitude", location.altitude)

val geocoder = Geocoder(context, Locale.getDefault())
geocoder.getAddress(location.latitude, location.longitude) { address ->
if (address == null) {
promise.resolve(response)
return@getAddress
}

response.putString("city", address.locality)
response.putString("state", address.adminArea)
response.putString("country", address.countryName)
response.putString("isoCountryCode", address.countryCode)
response.putString("name", address.featureName)
response.putString("postalCode", address.postalCode)
response.putString("timeZone", TimeZone.getDefault().id)

promise.resolve(response)
}
}
}

fun getRegisteredGeofences(promise: Promise) {
val ids = readFromSharedPreferences()
promise.resolve(ids.toWritableArray())
Expand All @@ -49,6 +95,10 @@ class GeofenceManager(private val context: Context) {
radiusInMeters: Float,
promise: Promise
) {
if (!isBackgroundLocationAuthorized()) {
promise.reject(Error("Background location permission not given"))
return
}
val geofence = listOf(createGeofence(id, location, radiusInMeters))
client.addGeofences(createGeofencingRequest(geofence), geofencingPendingIntent)
.addOnSuccessListener {
Expand Down Expand Up @@ -169,6 +219,46 @@ class GeofenceManager(private val context: Context) {
return Arguments.fromArray(this.toTypedArray())
}

@Suppress("DEPRECATION")
fun Geocoder.getAddress(
latitude: Double,
longitude: Double,
address: (Address?) -> Unit
) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getFromLocation(latitude, longitude, 1) { address(it.firstOrNull()) }
return
}

try {
address(getFromLocation(latitude, longitude, 1)?.firstOrNull())
} catch (e: Exception) {
address(null)
}
}

private fun isForegroundLocationAuthorized(): Boolean {
return ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}

private fun isBackgroundLocationAuthorized(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) == PackageManager.PERMISSION_GRANTED
} else {
return true
}
}

companion object {
const val TAG = "GeofenceManager"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class GeofencingModule(reactContext: ReactApplicationContext) :
return NAME
}

@ReactMethod
fun getCurrentLocation(promise: Promise) {
geofenceManager.getCurrentLocation(promise)
}

@ReactMethod
fun getRegisteredGeofences(promise: Promise) {
geofenceManager.getRegisteredGeofences(promise)
Expand Down
15 changes: 15 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getRegisteredGeofences,
requestLocation,
getLocationAuthorizationStatus,
getCurrentLocation,
} from '@rn-bridge/react-native-geofencing';

const Button = ({
Expand Down Expand Up @@ -50,6 +51,20 @@ export const App = () => {
}}
/>

<Button
textStyle={styles.textStyle}
style={styles.button}
title="Get Current Location"
onPress={async () => {
const response = await getCurrentLocation();
console.log('getCurrentLocation:', response);
Alert.alert(
'Status',
`Latitude: ${response.latitude}\nLongitude: ${response.longitude}`
);
}}
/>

<Button
textStyle={styles.textStyle}
style={styles.button}
Expand Down
3 changes: 3 additions & 0 deletions ios/Geofencing.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ @interface RCT_EXTERN_MODULE(Geofencing, RCTEventEmitter)
RCT_EXTERN_METHOD(requestLocation:(NSDictionary *)params
withSuccessCallback:(RCTResponseSenderBlock)successCallback)

RCT_EXTERN_METHOD(getCurrentLocation:(RCTPromiseResolveBlock)resolve
withReject:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(getRegisteredGeofences:(RCTPromiseResolveBlock)resolve
withReject:(RCTPromiseRejectBlock)reject)

Expand Down
44 changes: 42 additions & 2 deletions ios/Geofencing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,46 @@ class Geofencing: RCTEventEmitter, CLLocationManagerDelegate {
resolve(getLocationAuthorizationStatus())
}

func geocode(latitude: Double, longitude: Double, callback: @escaping (CLPlacemark?, Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude)) { callback($0?.first, $1)
}
}

@objc(getCurrentLocation: withReject:)
func getCurrentLocation(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {

if !isLocationAuthorized() {
reject("Permission", "Location permission not given", NSError(domain: "getCurrentLocation", code: 200))
return
}

let location = locationManager.location
let response: NSMutableDictionary = [:]
let latitude = location?.coordinate.latitude ?? 0
let longitude = location?.coordinate.longitude ?? 0

response["latitude"] = location?.coordinate.latitude
response["longitude"] = location?.coordinate.longitude
response["altitude"] = location?.altitude

geocode(latitude: latitude, longitude: longitude) { placemark, error in
guard let placemark = placemark, error == nil else {
resolve(response)
return
}

response["name"] = placemark.name
response["city"] = placemark.locality
response["state"] = placemark.administrativeArea
response["postalCode"] = placemark.postalCode
response["country"] = placemark.country
response["isoCountryCode"] = placemark.isoCountryCode
response["timeZone"] = placemark.timeZone?.identifier

resolve(response)
}
}

@objc(requestLocation: withSuccessCallback:)
func requestLocation(params: NSDictionary, successCallback: @escaping RCTResponseSenderBlock) {

Expand All @@ -46,7 +86,7 @@ class Geofencing: RCTEventEmitter, CLLocationManagerDelegate {
@objc(getRegisteredGeofences:withReject:)
func getRegisteredGeofences(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
if !isLocationAuthorized() {
reject("Permission", "Needed Authorization always but got \(getLocationAuthorizationStatus())", NSError(domain: "getRegisteredGeofences", code: 200))
reject("Permission", "Location permission not given", NSError(domain: "getRegisteredGeofences", code: 200))
return
}

Expand All @@ -59,7 +99,7 @@ class Geofencing: RCTEventEmitter, CLLocationManagerDelegate {
@objc(addGeofence:withResolve:withReject:)
func addGeofence(params: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
if !isLocationAuthorized() {
reject("Permission", "Needed Authorization always but got \(getLocationAuthorizationStatus())", NSError(domain: "addGeofence", code: 200))
reject("Permission", "Location permission not given", NSError(domain: "addGeofence", code: 200))
return
}

Expand Down
17 changes: 17 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,23 @@ export async function getLocationAuthorizationStatus(): Promise<string> {
return await Geofencing.getLocationAuthorizationStatus();
}

type locationType = {
latitude: number;
longitude: number;
altitude: number;
name: string;
city: string;
state: string;
country: string;
postalCode: string;
isoCountryCode: string;
timeZone: string;
};

export async function getCurrentLocation(): Promise<locationType> {
return await Geofencing.getCurrentLocation();
}

type paramsType = {
id: string;
latitude: number;
Expand Down

0 comments on commit 82bf2cf

Please sign in to comment.