Code Monkey home page Code Monkey logo

moko-geo's Introduction

moko-mvvm
GitHub license Download kotlin-version

Mobile Kotlin geolocation module

This is a Kotlin Multiplatform library that provides geolocation to common code.

Table of Contents

Features

  • Geolocation tracking - track user geolocation from common code;
  • Compose Multiplatform support;

Requirements

  • Gradle version 6.0+
  • Android API 16+
  • iOS version 9.0+

Installation

root build.gradle

allprojects {
    repositories {
        mavenCentral()
    }
}

project build.gradle

dependencies {
    commonMainApi("dev.icerock.moko:geo:0.6.0")

    // Compose Multiplatform
    commonMainApi("dev.icerock.moko:geo-compose:0.6.0")
}

Usage

in common code:

class TrackerViewModel(
    val locationTracker: LocationTracker
) : ViewModel() {

    init {
        viewModelScope.launch {
            locationTracker.getLocationsFlow()
                .distinctUntilChanged()
                .collect { println("new location: $it") }
        }
    }

    fun onStartPressed() {
        viewModelScope.launch { locationTracker.startTracking() }
    }

    fun onStopPressed() {
        locationTracker.stopTracking()
    }
}

In Android:

// create ViewModel
val locationTracker = LocationTracker(
    permissionsController = PermissionsController(applicationContext = applicationContext)
)
val viewModel = TrackerViewModel(locationTracker)

// bind tracker to lifecycle
viewModel.locationTracker.bind(lifecycle, this, supportFragmentManager)

In iOS:

let viewModel = TrackerViewModel(
    locationTracker: LocationTracker(
        permissionsController: PermissionsController(),
        accuracy: kCLLocationAccuracyBest
    )
)

Samples

Please see more examples in the sample directory.

Set Up Locally

  • The geo directory contains the geo library;
  • In sample directory contains sample apps for Android and iOS; plus the mpp-library connected to the apps.

Contributing

All development (both new features and bug fixes) is performed in the develop branch. This way master always contains the sources of the most recently released version. Please send PRs with bug fixes to the develop branch. Documentation fixes in the markdown files are an exception to this rule. They are updated directly in master.

The develop branch is pushed to master on release.

For more details on contributing please see the contributing guide.

License

Copyright 2019 IceRock MAG Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

moko-geo's People

Contributors

alex009 avatar anton6tak avatar nailik avatar orhantozan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

moko-geo's Issues

Location Channel Buffer Issue

Hi

i found a problem with the Channel design.

Currently everytime there is a new location it gets send to the channel

 trackerScope.launch {
            extendedLocationsChannel.send(extendedLocation)
            locationsChannel.send(latLng)
        }

But when the app starts tracking but watches only one flow (e.g. only getLocationsFlow()),
there is never a receive action on the second channel (extendedLocationsChannel)

This leds to the issue that locationsChannel.send(latLng) is not called after 64 locations where send because the channels are implemented as:

private val locationsChannel = Channel<LatLng>(Channel.BUFFERED)
private val extendedLocationsChannel = Channel<ExtendedLocation>(Channel.BUFFERED)

And in the docs they mention


        /**
         * Requests a buffered channel with the default buffer capacity in the `Channel(...)` factory function.
         * The default capacity for a channel that [suspends][BufferOverflow.SUSPEND] on overflow
         * is 64 and can be overridden by setting [DEFAULT_BUFFER_PROPERTY_NAME] on JVM.
         * For non-suspending channels, a buffer of capacity 1 is used.
         */
        public const val BUFFERED: Int = -2

so this should be changed to

        /**
         * Requests a conflated channel in the `Channel(...)` factory function. This is a shortcut to creating
         * a channel with [`onBufferOverflow = DROP_OLDEST`][BufferOverflow.DROP_OLDEST].
         */
        public const val CONFLATED: Int = -1

Update readme

  • description with goals
  • features list
  • simple usage (geolocation tracking, latlng using)

Memory leak

CCLocationManager retain instance of LocationController.
Снимок экрана 2019-12-28 в 18 21 20

Update kotlin & coroutines

to use coroutines 1.4.2-native-mt we should update code of UIDispatcher, so we should update kotlin and coroutines

Android - add dialog to enable GPS

I tested this library on Android. It works perfectly fine, if GPS is enabled. If not, nothing happens. The official docs state that an app should check the settings and prompt a system dialog to enable GPS. Would be nice to see this feature.

Library is not compatible with moko permissions 0.18.0

moko-geo is crashing when used with moko-permissions 0.18.0 due to changes introduced in icerockdev/moko-permissions#114

Crash

java.lang.NoSuchMethodError: No interface method bind(Landroidx/lifecycle/Lifecycle;Landroidx/fragment/app/FragmentManager;)V in class Ldev/icerock/moko/permissions/PermissionsController; or its super classes (declaration of 'dev.icerock.moko.permissions.PermissionsController' appears in /data/app/~~mzYr2CSSRJBzdyXB69qEMw==/house.letmein.app.debug-L3ibmEofzpfG5nL4uKKVAA==/base.apk!classes25.dex)
        at dev.icerock.moko.geo.LocationTracker.bind(LocationTracker.kt:46)
        at dev.icerock.moko.geo.compose.BindLocationTrackerEffect_androidKt$BindLocationTrackerEffect$1.invokeSuspend(BindLocationTrackerEffect.android.kt:26)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
        at android.os.Handler.handleCallback(Handler.java:958)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:205)
        at android.os.Looper.loop(Looper.java:294)
        at android.app.ActivityThread.main(ActivityThread.java:8177)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@1f23d75, androidx.compose.runtime.BroadcastFrameClock@5c010a, StandaloneCoroutine{Cancelling}@739ad7b, AndroidUiDispatcher@e8c8798]

Workaround

Keep using moko-permissions 0.17.0 till moko-geo is updated

Fix

LocationTracker.bind and BindLocationTrackerEffect should be updated to adapt to a new PermissionsController.bind API. While releasing a new version of this library it would be nice to include also bumping other dependencies to the newest versions.

Android: allow changing underlying GPS service implementation

Current LocationTracker implementation is nailed to the FusedLocationProviderClient. Therefore moko-geo is unable to work properly on android devices without Google Services installed. Google Services are unavailable/not installed/not used on lots of chinese devices and some of open source firmwares.

This issue is somewhat releated to #16, because running moko-geo sample app on AVD image without Google APIs/Google Play leads to the same result with related log messages:

W/GooglePlayServicesUtil: dev.icerock.moko.samples.geo.debug requires the Google Play Store, but it is missing.
W/GoogleApiManager: The service for com.google.android.gms.internal.location.zzaz is not available [...]

There are at least couple of alternatives that can be used instead of FusedLocationProviderClient:

  • com.yandex.mapkit.location.LocationManager from Yandex MapKit (don't really know what they are using as underlying GPS service)
  • android.location.LocationManager from Android SDK

Besides, as a user of moko-geo I would like to have an ability to use my own bindings to location services from other custom private/device specific SDK's. So it's also would be nice to have an interface allowing to do such bindings and some APIs allowing to choose different implementations at runtime.

compose multplatform

geo locations works on the iOS side, but its not working for android. im using a pixel 7 device

altitude, accuracy, angle

Currently we are using your library. In our app we need functionality to get
altitude, accuracy, angle

screenModelScope.launch {
locationTracker?.getLocationsFlow()?.distinctUntilChanged()?.collect {
AppLogger.log("new location: $it.")
state.value.latitude = it.latitude
state.value.longitude = it.longitude
}
}

How can we do that.Does this functionality exist or not? Please do update as soon as possible. If not, we then have to move on to next library thanks. Since this seems great library for multiplatform, we don't want to switch.

Permission issue when start tracking location

Hi, I tried to do the same as construction in readme, and it shows the rationale dialog. My app already had Location permission but every time I tried to run LocationTracker.startTracking() it threw dev.icerock.moko.permissions.DeniedAlwaysException. I don't know why. Please help. Thank you.
image

Permission controller not accessible in iOS code

Hello,

I tried to use this library in my project. For the android part everything works as expected, but for iOS it's not. I am trying to initialize my dependencies as in readme:

let viewModel = TrackerViewModel(
    locationTracker: LocationTracker(
        permissionsController: PermissionsController(),
        accuracy: kCLLocationAccuracyBest
    )
)

But it's not possible. Firstly, there's no such class as LocationTracker - there's GeoLocationTracker instead. This wouldn't be a problem but the PermissionController doesn't exist either. The only thing that is accessible is PermissionsPermissionsControllerProtocol which is (of course) a protocol so it'd require an iOS specific implementation. Is there some bug in the library or I am doing sth wrong?

This is my shared module gradle file:

plugins {
    kotlin("multiplatform")
    id("com.android.library")
    kotlin("plugin.serialization") //version "1.4.32"
    id("io.realm.kotlin") version "0.10.0"
}

dependencies {
    commonMainApi("dev.icerock.moko:geo:0.5.0")
}

kotlin {
    android()
    
    listOf(
        iosX64(),
        iosArm64(),
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
        }
    }

    sourceSets {
        val coroutineVersion = "1.6.0"
        val ktor_version = "1.6.7"
        val serialization_version = "1.3.2"


        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion-native-mt") {
                    version { strictly("$coroutineVersion-native-mt") }
                }
                implementation("io.ktor:ktor-client-core:$ktor_version")
                implementation("io.ktor:ktor-client-serialization:$ktor_version")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
                implementation("io.ktor:ktor-client-logging:$ktor_version")
                implementation("io.realm.kotlin:library-base:0.10.0")
                implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:$ktor_version")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.13.2")
            }
        }
        val iosX64Main by getting
        val iosArm64Main by getting
        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktor_version")
            }
        }
        val iosX64Test by getting
        val iosArm64Test by getting
        val iosTest by creating {
            dependsOn(commonTest)
            iosX64Test.dependsOn(this)
            iosArm64Test.dependsOn(this)
        }
    }
}

android {
    compileSdk = 31
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdk = 21
        targetSdk = 31
    }
}

I tried other options (commonMainImplementation instead of ..api, export etc.) but the effect was always the same. I'd be very grateful for some hints

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.