snapshot of https://github.com/tauri-apps/plugins-workspace.git (v2, 2026-09-23; blobs > 131072B omitted)
Some checks failed
integration tests / run-integration-tests (windows-latest) (push) Has been cancelled
Test Rust / test (push) Has been cancelled
test plugins e2e (mobile) / ios (push) Has been cancelled
test plugins e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test plugins e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
integration tests / run-integration-tests (macos-latest) (push) Has been cancelled
version or publish / version-or-publish (push) Failing after 0s
integration tests / run-integration-tests (ubuntu-22.04) (push) Failing after 0s
Lint JavaScript / eslint (push) Failing after 0s
Sync / sync-to-mirrors (push) Failing after 0s
test plugins e2e (mobile) / android (push) Failing after 0s
test plugins e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
Test Rust / changes (push) Failing after 0s
Lint Rust / changes (push) Failing after 0s
Lint Rust / clippy (push) Has been skipped
Audit Rust / audit-rust (push) Failing after 1s
Audit JavaScript / audit-js (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-23 17:17:10 +05:00
commit 9ad64ec987
1469 changed files with 115067 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
/build
/.tauri

View File

@@ -0,0 +1,36 @@
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "app.tauri.geolocation"
compileSdk = 36
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.0")
implementation("com.google.android.material:material:1.7.0")
implementation("com.google.android.gms:play-services-location:21.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation(project(":tauri-android"))
}

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,2 @@
include ':tauri-android'
project(':tauri-android').projectDir = new File('./.tauri/tauri-api')

View File

@@ -0,0 +1,28 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.geolocation
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("app.tauri.geolocation", appContext.packageName)
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- <uses-feature android:name="android.hardware.gps" android:required="true" /> -->
</manifest>

View File

@@ -0,0 +1,144 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.geolocation
import android.annotation.SuppressLint
import android.content.Context
import android.location.Location
import android.location.LocationManager
import android.os.SystemClock
import androidx.core.location.LocationManagerCompat
import app.tauri.Logger
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
public class Geolocation(private val context: Context) {
private var fusedLocationClient: FusedLocationProviderClient? = null
private var locationCallback: LocationCallback? = null
fun isLocationServicesEnabled(): Boolean {
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return LocationManagerCompat.isLocationEnabled(lm)
}
@SuppressWarnings("MissingPermission")
fun sendLocation(enableHighAccuracy: Boolean, successCallback: (location: Location) -> Unit, errorCallback: (error: String) -> Unit) {
val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
if (resultCode == ConnectionResult.SUCCESS) {
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (this.isLocationServicesEnabled()) {
var networkEnabled = false
try {
networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
} catch (_: Exception) {
Logger.error("isProviderEnabled failed")
}
val lowPrio = if (networkEnabled) Priority.PRIORITY_BALANCED_POWER_ACCURACY else Priority.PRIORITY_LOW_POWER
val prio = if (enableHighAccuracy) Priority.PRIORITY_HIGH_ACCURACY else lowPrio
LocationServices
.getFusedLocationProviderClient(context)
.getCurrentLocation(prio, null)
.addOnFailureListener { e -> e.message?.let { errorCallback(it) } }
.addOnSuccessListener { location ->
if (location == null) {
errorCallback("Location unavailable.")
} else {
successCallback(location)
}
}
} else {
errorCallback("Location disabled.")
}
} else {
errorCallback("Google Play Services unavailable.")
}
}
@SuppressLint("MissingPermission")
fun requestLocationUpdates(enableHighAccuracy: Boolean, timeout: Long, successCallback: (location: Location) -> Unit, errorCallback: (error: String) -> Unit) {
val resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
if (resultCode == ConnectionResult.SUCCESS) {
clearLocationUpdates()
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (this.isLocationServicesEnabled()) {
var networkEnabled = false
try {
networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
} catch (_: Exception) {
Logger.error("isProviderEnabled failed")
}
val lowPrio = if (networkEnabled) Priority.PRIORITY_BALANCED_POWER_ACCURACY else Priority.PRIORITY_LOW_POWER
val prio = if (enableHighAccuracy) Priority.PRIORITY_HIGH_ACCURACY else lowPrio
val locationRequest = LocationRequest.Builder(timeout)
.setMaxUpdateDelayMillis(timeout)
.setMinUpdateIntervalMillis(timeout)
.setPriority(prio)
.build()
locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val lastLocation = locationResult.lastLocation
if (lastLocation == null) {
errorCallback("Location unavailable.")
} else {
successCallback(lastLocation)
}
}
}
fusedLocationClient?.requestLocationUpdates(locationRequest, locationCallback!!, null)
} else {
errorCallback("Location disabled.")
}
} else {
errorCallback("Google Play Services not available.")
}
}
fun clearLocationUpdates() {
if (locationCallback != null) {
fusedLocationClient?.removeLocationUpdates(locationCallback!!)
locationCallback = null
}
}
@SuppressLint("MissingPermission")
fun getLastLocation(maximumAge: Long): Location? {
var lastLoc: Location? = null
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
for (provider in lm.allProviders) {
val tmpLoc = lm.getLastKnownLocation(provider)
if (tmpLoc != null) {
val locationAge = SystemClock.elapsedRealtimeNanos() - tmpLoc.elapsedRealtimeNanos
val maxAgeNano = maximumAge * 1000000L
if (locationAge <= maxAgeNano && (lastLoc == null || lastLoc.elapsedRealtimeNanos > tmpLoc.elapsedRealtimeNanos)) {
lastLoc = tmpLoc
}
}
}
return lastLoc
}
}

View File

@@ -0,0 +1,172 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.geolocation
import android.Manifest
import android.app.Activity
import android.location.Location
import android.os.Build
import android.webkit.WebView
import app.tauri.Logger
import app.tauri.PermissionState
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.Permission
import app.tauri.annotation.PermissionCallback
import app.tauri.annotation.TauriPlugin
import app.tauri.plugin.Channel
import app.tauri.plugin.Invoke
import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin
@InvokeArg
class PositionOptions {
var enableHighAccuracy: Boolean = false
var maximumAge: Long = 0
var timeout: Long = 10000
}
@InvokeArg
class WatchArgs {
var options: PositionOptions = PositionOptions()
lateinit var channel: Channel
}
@InvokeArg
class ClearWatchArgs {
var channelId: Long = 0
}
// TODO: Plugin does not ask user to enable google location services (like gmaps does)
private const val ALIAS_LOCATION: String = "location"
private const val ALIAS_COARSE_LOCATION: String = "coarseLocation"
@TauriPlugin(
permissions = [
Permission(strings = [
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
],
alias = ALIAS_LOCATION
),
Permission(strings = [
Manifest.permission.ACCESS_COARSE_LOCATION
],
alias = ALIAS_COARSE_LOCATION
)
]
)
class GeolocationPlugin(private val activity: Activity): Plugin(activity) {
private lateinit var implementation: Geolocation
private var watchers = hashMapOf<Long, Pair<Invoke, WatchArgs>>()
override fun load(webView: WebView) {
super.load(webView)
implementation = Geolocation(activity.applicationContext)
}
override fun onPause() {
super.onPause()
// Clear all location updates on pause to avoid possible background location calls
implementation.clearLocationUpdates()
}
override fun onResume() {
super.onResume()
// resume watchers
for ((watcher, args) in watchers.values) {
startWatch(watcher, args)
}
}
@Command
override fun checkPermissions(invoke: Invoke) {
if (implementation.isLocationServicesEnabled()) {
super.checkPermissions(invoke)
} else {
invoke.reject("Location services are disabled.")
}
}
@Command
override fun requestPermissions(invoke: Invoke) {
if (implementation.isLocationServicesEnabled()) {
super.requestPermissions(invoke)
} else {
invoke.reject("Location services are disabled.")
}
}
@Command
fun getCurrentPosition(invoke: Invoke) {
val args = invoke.parseArgs(PositionOptions::class.java)
val location = implementation.getLastLocation(args.maximumAge)
if (location != null) {
invoke.resolve(convertLocation(location))
} else {
implementation.sendLocation(args.enableHighAccuracy,
{ loc -> invoke.resolve(convertLocation(loc)) },
{ error -> invoke.reject(error) })
}
}
@PermissionCallback
private fun positionPermissionCallback(invoke: Invoke) {
val permissionsResultJSON = JSObject()
permissionsResultJSON.put("location", getPermissionState(ALIAS_LOCATION))
permissionsResultJSON.put("coarseLocation", getPermissionState(ALIAS_COARSE_LOCATION))
invoke.resolve(permissionsResultJSON)
}
@Command
fun watchPosition(invoke: Invoke) {
val args = invoke.parseArgs(WatchArgs::class.java)
startWatch(invoke, args)
}
private fun startWatch(invoke: Invoke, args: WatchArgs) {
implementation.requestLocationUpdates(
args.options.enableHighAccuracy,
args.options.timeout,
{ location -> args.channel.send(convertLocation(location)) },
{ error -> args.channel.sendObject(error) })
watchers[args.channel.id] = Pair(invoke, args)
}
@Command
fun clearWatch(invoke: Invoke) {
val args = invoke.parseArgs(ClearWatchArgs::class.java)
watchers.remove(args.channelId)
if (watchers.isEmpty()) {
implementation.clearLocationUpdates()
}
invoke.resolve()
}
private fun convertLocation(location: Location): JSObject {
val ret = JSObject()
val coords = JSObject()
coords.put("latitude", location.latitude)
coords.put("longitude", location.longitude)
coords.put("accuracy", location.accuracy)
coords.put("altitude", location.altitude)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
coords.put("altitudeAccuracy", location.verticalAccuracyMeters)
}
coords.put("speed", location.speed)
coords.put("heading", location.bearing)
ret.put("timestamp", location.time)
ret.put("coords", coords)
return ret
}
}

View File

@@ -0,0 +1,21 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.geolocation
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}