Giter Site home page Giter Site logo

radarlabs / flutter-radar Goto Github PK

View Code? Open in Web Editor NEW
22.0 8.0 12.0 759 KB

Flutter package for Radar, the leading geofencing and location tracking platform

Home Page: https://radar.io

License: Apache License 2.0

Java 42.16% Objective-C 32.61% Dart 23.85% Ruby 1.39%
radar geolocation background-geolocation geofencing location-tracking geocoding-api

flutter-radar's Introduction

Radar

npm

Radar is the leading geofencing and location tracking platform.

The Radar SDK abstracts away cross-platform differences between location services, allowing you to add geofencing, location tracking, trip tracking, geocoding, and search to your apps with just a few lines of code.

Documentation

See the Radar overview documentation here.

Then, see the Flutter package documentation here.

Examples

See an example app in example/.

Support

Have questions? We're here to help! Email us at [email protected].

flutter-radar's People

Contributors

andlum avatar brettguenther avatar gabrielalao avatar jrtibbetts avatar kennyhuradar avatar nickpatrick avatar tjulien avatar york-wei avatar

Stargazers

 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  avatar  avatar

flutter-radar's Issues

Listeners not being called in background (when app is closed)

I have done the following, I want to send location data to my backend when the app is closed, and while event listeners get called when the app is open or minimised, they don't get called when the app is closed.

The docs say "Add event listeners outside of your view lifecycle if you want them to work when the app is in the background.", and I have tried putting this code in different places, calling from the app's main method, the initState of the home page or from a riverpod provider, but none of them work when the app is closed.

  @pragma('vm:entry-point')
  static void onLocation(Map result) {
    print('onLocation');
    sendLocationToBackend(result);
  }

  Radar.attachListeners();
  Radar.onLocation(onLocation);

Flutter SDK Geofencing capabilities

Any plans on a Flutter SDK update regarding the geofencing capabilities already present in the Android/iOS SDKs ? The plugin itself seems amazing for geofencing (my particular use case) but, from what I could see in the official documentation, background tracking regarding geofencing is only present on Android and iOS. There could be fixes around this problem with events but there is also no documentation about those in the Flutter SDK docs. Is this going to be a feature or is it on hold/not planned ?

Autocomplete null object reference error

For the Radar.autocomplete function, all parameters are listed as nullable. If the near parameter is not included, which according to the API reference docs is optional, the following error is returned by the SDK:

{error: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.HashMap.get(java.lang.Object)' on a null object reference}

This package often doesn't seem to follow the API references. For the autocomplete API, query is required, while near, layers, limit, country, mailable are optional. The flutter-radar package shows all parameters as nullable and returns the above error if near is null.

Source: https://radar.com/documentation/api#autocomplete

Migrate to null safety

Hello There.

As of now, most of the packages/plugin has been migrated to null-safety, and most of the projects use null safety.
Can you guys please migrate to null safety?
I would be happy to work on PR

Thanks
Jigar

Edit. 1
I see there is PR available to merge for null safety.

Any ETA when you guys can merge it

Radar SDK Listeners should not need to be marked static to allow for instance members to be utilized in logic

Currently in flutter-radar, you need to declare the listener functions in the exact way (see below) or else when you attach them using Radar.attachListener() you will get null exception errors.

 @pragma('vm:entry-point')
  static void onLocation(Map res) {
    print('📍📍 onLocation: $res');
  }

  @pragma('vm:entry-point')
  static void onClientLocation(Map res) {
    print('📍📍 onClientLocation: $res');
  }

  @pragma('vm:entry-point')
  static void onError(Map res) {
    print('📍📍 onError: $res');
  }

  @pragma('vm:entry-point')
  static void onLog(Map res) {
    print('📍📍 onLog: $res');
  }

  @pragma('vm:entry-point')
  static void onEvents(Map res) {
    print('📍📍 onEvents: $res');
  }

  @pragma('vm:entry-point')
  static void onToken(Map res) {
    print('📍📍 onToken: $res');
  }

Why do we need the static marker for these methods? And since we need them, how are we supposed to access the instance members of our parent class to be able to actually do something with the responses we get back?

Here is my current setup

class RadarWidget extends StatefulWidget {
  const RadarWidget({super.key});

  @override
  State<RadarWidget> createState() => _RadarWidgetState();
}

class _RadarWidgetState extends State<RadarWidget> {
  @override
  Widget build(BuildContext context) {
    print('Radar widget building');
    return const Placeholder();
  }

  @override
  void dispose() {
    // Clean up listeners if necessary
    Radar.detachListeners();
    Radar.stopTracking();
    print('Radar detached listeners and stopped tracking');
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    print('Radar init state');
    try {
      initRadar();
    } catch (err) {
      print("initRadar error occurred: $err");
    }
  }

  @pragma('vm:entry-point')
  static void onLocation(Map res) {
    print('📍📍 onLocation: $res');
  }

  @pragma('vm:entry-point')
  static void onClientLocation(Map res) {
    print('📍📍 onClientLocation: $res');
  }

  @pragma('vm:entry-point')
  static void onError(Map res) {
    print('📍📍 onError: $res');
  }

  @pragma('vm:entry-point')
  static void onLog(Map res) {
    print('📍📍 onLog: $res');
  }

  @pragma('vm:entry-point')
  static void onEvents(Map res) {
    print('📍📍 onEvents: $res');
  }

  @pragma('vm:entry-point')
  static void onToken(Map res) {
    print('📍📍 onToken: $res');
  }

  Future<void> initRadar() async {
    Radar.initialize(
        "prj_test_pk_1a0a3ab555e5e4c721ece54d8ce50bbdd9d73cb5"); //Radar api key
    Radar.setLogLevel('info');

    Radar.attachListeners();

    Radar.onLocation(onLocation);
    Radar.onClientLocation(onClientLocation);
    Radar.onError(onError);
    Radar.onEvents(onEvents);
    Radar.onLog(onLog);
    Radar.onToken(onToken);

    final status = await Radar.getPermissionsStatus();
    print("Radar permission status $status");

    // final requestedStatus = await Radar.requestPermissions(false);
    // print("Radar requested permission status $requestedStatus");

    await Radar.startTracking('continuous');
    await Radar.mockTracking(
        //(37.53206895196914,-77.42409998968543)
        origin: {
          'latitude': 37.53206895196914,
          'longitude': -77.42409998968543
        },
        //dest: (37.53011080455556, -77.42597953180213)
        destination: {
          'latitude': 37.53011080455556,
          'longitude': -77.42597953180213
        },
        mode: 'foot',
        steps: 10,
        interval: 5);
  }
}

I just want to expose these listener events to callbacks that I pass to the widget, but I can't do that because I can't access the widget in these static methods. How are we supposed to do anything with these listener events if the method needs to be marked as static?

Radar SDK isn't consistent with updating values and does not support offline or batch sync

We are currently on the Team Plan and our project name is TD God-View. We integrated the flutter plugin for our product which is a Logistics App.

We have observed some inconsistency in the behaviour of the plugin which we would like to clarify for trips.

  1. When we started a trip we noticed the trip did not have the userId field set even though we could see from the logs that we were setting this value
  2. Trip was not updated even after calling start trip, we could not see the trip on the radar dashboard. 
  3. At some point, after recalling the start trip function pertaining to our use case, we would get the results on radar sometimes in a perfect manner and sometimes we get it inconsistently.

Our implementation
We initialised the plugin on the main method, which was verified because the plugin logged the radar initialise method on the console.
await Radar.initialize(environment['RADAR_PUBLISHABLE_KEY']!);

The plugin logged this: 

I/RadarLogger(21315): :round_pushpin:️ Radar initialized

After initialising the plugin we set the user ID and the user description immediately after the user logged in following the documentation procedure which states that the function is meant to be called only once. And we also verified the plugin stored the data by calling the getUserId function on the plugin.

static Future<void> initRadar(BuildContext context) async{

 /// [TdUser] details
 String userId = context.read<LoginProvider>().currentUser!.id!;
 String displayName = context.read<LoginProvider>().currentUser!.displayName;

 /// [logger]
 log('');
 log('---------------- RADAR INITIALIZED ----------------');
 log('::::: UserId: $userId :::::');
 log('::::: Display Name: $displayName :::::');
 log('');

 /// Setting user's Description
 await Radar.setUserId(userId);
 await Radar.setDescription(displayName);
 await Radar.startTracking('continuous');
 log('Radar tracking');
}

This was logged immediately this method was called:

[log] ---------------- RADAR INITIALIZED ----------------
[log] ::::: UserId: Eds4G5HD2AypMeBPD :::::
[log] ::::: Display Name: Babalola Gbogo :::::

This was logged after a little while
[log] Radar tracking

Then we proceeded to starting a trip in which sometimes it won’t start and sometimes it will.

static Future<void> startTrip({
 required BuildContext context,
}) async {
 final Stop _firstStop = context
   .read<TripProvider>()
   .stops!
   .where((_stop) => _stop.position == 1)
   .toList()
   .first;
 final String externalId =
   '${_firstStop.deliveryTripId}_${_firstStop.stopId}';
 final outlet = await _getRetailOutlet(
  context,
  _firstStop,
 );

 /// [logger]
 log('');
 log('---------------- START TRIP ----------------');
 log('::::: First Stop: ${_firstStop.retailOutletName} :::::');
 log('::::: Outlet Type: ${outletMapper(
  outlet: outlet!.outletType,
 )} :::::');
 log('');

 /// Starting trip with radar
 await _startRadarTrip(
  externalId: externalId,
  outletType: outletMapper(
   outlet: outlet.outletType,
  ),
  outletId: outlet.retailOutletId!,
 );
  log('Trip Started');
}

We verified that it called these methods using the log output

[log] ---------------- START TRIP ----------------
[log] ::::: First Stop: Liquid metal :::::
[log] ::::: Outlet Type: large-super-market :::::

And then after a little delay this got logged
[log] Trip Started

Install Radar with Kotlin & Swift?

New Flutter projects uses Kotlin for Android and Swift for iOS by default, but in Radar's Flutter plugin docs (https://radar.com/documentation/sdk/flutter) the example is still in Java & Objective C. Since most Flutter devs are like me, who have very limited understanding of native platform, it would be very helpful to include steps to install Radar in Kotlin/Swift.

I also noticed that in my Flutter project, the MainApplication.java file is missing. No equivalent file in Kotlin either. I have no idea where to put the initialization code for Radar.

Am I missing anything?

reverseGeocode should use named parameters and follow API specification

The reverse geocode documentation: https://radar.com/documentation/api#reverse-geocode says there are two input parameters, coordinates and layers.

The flutter documentation here: https://radar.com/documentation/sdk/flutter#geocoding shows a type Map<String, dynamic> input that uses latitude, longitude, and accuracy. There is no description of what accuracy does, one can only assume. There is also no mention of the layers parameter.

The reverseGeocode function should use named parameters, not a Map<String, dynamic> type which can easily be mistyped. It should include:

latitude (type double)
longitude (type double)
layers (type List<Layer>, using enum to avoid mistyped layer names)

Example:

final res = await Radar.reverseGeocode({
  latitude: 11.1234,
  longitude: 22.3456,
  layers: [
    Layer.place,
    Layer.address,
    Layer.state,
  ],
});

Additionally, the return type should not be Map<dynamic, dynamic>? (again to avoid mistyped parameter names), but have its own class.

Warnings of depreciated API and unsafe/unchecked operations on android build

I get the following warnings when building:

Note: /home/john/.pub-cache/hosted/pub.dev/flutter_radar-3.9.0/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: /home/john/.pub-cache/hosted/pub.dev/flutter_radar-3.9.0/android/src/main/java/io/radar/flutter/RadarFlutterPlugin.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Dart Error: Dart_LookupLibrary When building/running app in release mode.

I have been facing an issue related to working of radar in release mode. While in debug mode the library is working fine with no errors, I think it is being caused due to obfuscation due to which R8 is removing the native code/methods [https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md]. I tried adding @pragma("vm:entry-point") to the flutter_radar.dart but it didn't solve the issue. This same issue is reproducible in the radar example code. Help from the team would be great.

flutter doctor:

[✓] Flutter (Channel stable, 3.19.3, on macOS 13.5 22G74 darwin-arm64, locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.87.2)
[✓] Connected device (3 available)
[✓] Network resources
• No issues found!

LOGS:

E/flutter ( 5294): [ERROR:flutter/shell/common/shell.cc(117)] Dart Error: Dart_LookupLibrary: library 'package:flutter_radar/flutter_radar.dart' not found.
E/flutter ( 5294): [ERROR:flutter/runtime/dart_isolate.cc(677)] Could not resolve main entrypoint function.
E/flutter ( 5294): [ERROR:flutter/runtime/dart_isolate.cc(168)] Could not run the run main Dart entrypoint.
E/flutter ( 5294): [ERROR:flutter/runtime/runtime_controller.cc(462)] Could not create root isolate.
E/flutter ( 5294): [ERROR:flutter/shell/common/shell.cc(669)] Could not launch engine with configuration.

Im not sure it will help in explanation of this issue or debugging as this issue is appearing in stock radar example too. But I have included proguard-rules in my personal project as its an requirement by flutter_local_notifcation package:
proguard-rules.pro

## Gson rules
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
#-keepattributes InnerClasses
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

Edit: adding @pragma("vm:entry-point") before class Radar make the error E/flutter ( 6472): [ERROR:flutter/shell/common/shell.cc(117)] Dart Error: Dart_LookupLibrary: library 'package:flutter_radar/flutter_radar.dart' not found. go away.

@pragma("vm:entry-point")
class Radar {
  static const MethodChannel _channel = const MethodChannel('flutter_radar');

But the library still doesn't works.

Radar.onEvents() never called

I have a problem with Radar.onEvents(), is never called :

Radar.initialize("prj_test_pk_*");
Radar.setUserId(mUserId);
Radar.startTracking('responsive');
Radar.onEvents((result) {
    print("RADAR GEOFENCE DETECTED EVENTS");
    print(result);
});

On my IDE logs I've :
Capture d’écran 2023-01-18 à 16 17 28

But my print on the onEvents listener not show.

What have I done wrong ?

Thanks.

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.