搜尋套件、儲存庫與 APP 分類

套件詳情v2.3.15

geoflutterfire2

GeoFlutterFire2 是一個開源庫,可讓您根據地理位置儲存和查詢 Firestore 文件。

AndroidiOSWebmacOSWindows
近 30 天下載
4370
喜歡數
118
Pub 分數
140

安裝套件

flutter pub add geoflutterfire2

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

GeoFlutterFire2 是一個開源的 Flutter 套件,讓開發者能夠使用地理定位資料來儲存與查詢 Firestore 文件。它擴展了 Firebase Firestore 的地理空間功能,支援高效的位置基礎查詢,例如尋找附近的興趣點。此套件專為跨平台使用設計,支援 Android、iOS、Web、macOS 與 Windows,非常適合需要即時位置服務的應用程式。該套件可與現有的 Firebase 項目無縫整合,並簡化了在 Flutter 應用程式中處理地理定位的工作。

適用情境

  • 查找附近用戶或位置
  • 基於位置的即時通知
  • 移動應用中的地理圍欄
  • 位置感知搜尋功能
  • 映射與空間數據可視化

主要特色

  • Firestore 中的地緣空間查詢
  • 跨平台支援
  • 與 Firebase 的輕鬆整合
  • 支援基於距離的過濾
  • 輕量且高效

適合對象

  • 基於位置的應用開發
  • Firebase 驅動的應用程式帶地圖
  • 即時地理定位服務
  • 帶有空間資料的行動與網路應用
  • 使用 Flutter 和 Firestore 的開發人員

使用建議

  • 需要 Firebase Firestore 設定
  • 僅限 Firestore 的地理空間功能
  • 可能需要對大型數據集進行額外處理
  • 依賴於底層的 Firebase SDK
  • 不適用於僅離線的地點定位

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

GeoFlutterFire2 :earth_africa:

NB! GeoFlutterFire2 is the revisited & updated version of GeoFlutterFire

GeoFlutterFire is an open-source library that allows you to store and query a set of keys based on their geographic location. At its heart, GeoFlutterFire simply stores locations with string keys. Its main benefit, however, is the possibility of retrieving only those keys within a given geographic area - all in realtime.

GeoFlutterFire uses the Firebase Firestore Database for data storage, allowing query results to be updated in realtime as they change. GeoFlutterFire selectively loads only the data near certain locations, keeping your applications light and responsive, even with extremely large datasets.

GeoFlutterFire is designed as a lightweight add-on to cloud_firestore plugin. To keep things simple, GeoFlutterFire stores data in its own format within your Firestore database. This allows your existing data format and Security Rules to remain unchanged while still providing you with an easy solution for geo queries.

Heavily influenced by GeoFireX :fire::fire: from Jeff Delaney :sunglasses:

:tv: Checkout this amazing tutorial on fireship by Jeff, featuring the plugin!!

Getting Started

You should ensure that you add GeoFlutterFire as a dependency in your flutter project.

dependencies:
  geoflutterfire2: <latest-version>

You can also reference the git repo directly if you want:

dependencies:
  geoflutterfire2:
    git: git://github.com/beerstorm-net/GeoFlutterFire2.git

You should then run flutter pub get or update your packages in IntelliJ.

Example

There is a detailed example project in the example folder. Check that out or keep reading!

Initialize

You need a firebase project with Firestore setup.

import 'package:geoflutterfire2/geoflutterfire2.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

// Init firestore and geoFlutterFire
final geo = GeoFlutterFire();
final _firestore = FirebaseFirestore.instance;

Writing Geo data

Add geo data to your firestore document using GeoFirePoint

GeoFirePoint myLocation = geo.point(latitude: 12.960632, longitude: 77.641603);

Next, add the GeoFirePoint to you document using Firestore's add method

 _firestore
        .collection('locations')
        .add({'name': 'random name', 'position': myLocation.data});

Calling geoFirePoint.data returns an object that contains a geohash string and a Firestore GeoPoint. It should look like this in your database. You can name the object whatever you want and even save multiple points on a single document.

Query Geo data

Warning Querying locations creates 9 separated stream listeners on firestore. One for central geo hash and 8 surrounding it. within function creates a convenient broadcast stream, if you need more than one subscriber for the locations. But it also causes memory leak, because underlying stream listeners are not cancelled when you cancel StreamSubscription from within method.

It's much safer to use withinAsSingleStreamSubscription which you can cancel, and it will also cancel 9 underlying streams as well.

To query a collection of documents with 50kms from a point

// Create a geoFirePoint
GeoFirePoint center = geo.point(latitude: 12.960632, longitude: 77.641603);

// get the collection reference or query
var collectionReference = _firestore.collection('locations');

double radius = 50;
String field = 'position';

Stream<List<DocumentSnapshot>> stream = geo.collection(collectionRef: collectionReference)
                                        .within(center: center, radius: radius, field: field);

The within function returns a Stream of the list of DocumentSnapshot data, plus some useful metadata like distance from the centerpoint.

stream.listen((List<DocumentSnapshot> documentList) {
        // doSomething()
      });

You now have a realtime stream of data to visualize on a map.

:notebook: API

collection(collectionRef: CollectionReference)

Creates a GeoCollectionRef which can be used to make geo queries, alternatively can also be used to write data just like firestore's add / set functionality.

Example:

// Collection ref
// var collectionReference = _firestore.collection('locations').where('city', isEqualTo: 'bangalore');
var collectionReference = _firestore.collection('locations');
var geoRef = geo.collection(collectionRef: collectionReference);

Note: collectionReference can be of type CollectionReference or Query

Performing Geo-Queries

geoRef.within(center: GeoFirePoint, radius: double, field: String, {strictMode: bool})

Query the parent Firestore collection by geographic distance. It will return documents that exist within X kilometers of the center-point. field supports nested objects in the firestore document.

Note: Use optional parameter strictMode = true to filter the documents strictly within the bound of given radius.

Example:

// For GeoFirePoint stored at the root of the firestore document
geoRef.within(center: centerGeoPoint, radius: 50, field: 'position', strictMode: true);

// For GeoFirePoint nested in other objects of the firestore document
geoRef.within(center: centerGeoPoint, radius: 50, field: 'address.location.position', strictMode: true);

Each documentSnapshot.data() also contains distance calculated on the query.

Returns: Stream<List<DocumentSnapshot>>

Write Data

Write data just like you would in Firestore

geoRef.add(data)

Or use one of the client's conveniece methods

  • geoRef.setDoc(String id, var data, {bool merge}) - Set a document in the collection with an ID.
  • geoRef.setPoint(String id, String field, double latitude, double longitude)- Add a geohash to an existing doc
Read Data

In addition to Geo-Queries, you can also read the collection like you would normally in Firestore, but as an Observable

  • geoRef.data()- Stream of documentSnapshot
  • geoRef.snapshot()- Stream of Firestore QuerySnapshot
point(latitude: double, longitude: double)

Returns a GeoFirePoint allowing you to create geohashes, format data, and calculate relative distance.

Example: var point = geo.point(38, -119)

Getters
  • point.hash Returns a geohash string at precision 9
  • point.geoPoint Returns a Firestore GeoPoint
  • point.data Returns data object suitable for saving to the Firestore database
Geo Calculations
  • point.distance(latitude, longitude) Haversine distance to a point

:zap: Tips

Scale to Massive Collections

It's possible to build Firestore collections with billions of documents. One of the main motivations of this project was to make geoqueries possible on a queried subset of data. You can pass a Query instead of a CollectionReference into the collection(), then all geoqueries will be scoped with the constraints of that query.

Note: This query requires a composite index, which you will be prompted to create with an error from Firestore on the first request.

Example:

var queryRef = _firestore.collection('locations').where('city', isEqualTo: 'bangalore');
var stream = geo
              .collection(collectionRef: queryRef)
              .within(center: center, radius: rad, field: 'position');
Usage of strictMode

It's advisable to use strictMode = false for smaller radius to make use of documents from neighbouring hashes as well.

As the radius increases to a large number, the neighbouring hash precisions fetch documents which would be considerably far from the radius bounds, hence its advisable to use strictMode = true for larger radius.

Note: filtering for strictMode happens on client side, hence filtering at larger radius is at the expense of making unnecessary document reads.

Make Dynamic Queries the RxDart Way
var radius = BehaviorSubject<double>.seeded(1.0);
var collectionReference = _firestore.collection('locations');

stream = radius.switchMap((rad) {
      return geo
          .collection(collectionRef: collectionReference)
          .within(center: center, radius: rad, field: 'position');
    });

// Now update your query
radius.add(25);
Limitations
  • range queries on multiple fields is not suppoerted by cloud_firestore at the moment, since this library already uses range query on geohash field, you cannot perform range queries with GeoFireCollectionRef.
  • limit() and orderBy() are not supported at the moment. limit() could be used to limit docs inside each hash individually which would result in running limit on all 9 hashes inside the specified radius. orderBy() is first run on geohashes in the library, hence appending orderBy() with another feild wouldn't produce expected results. Alternatively documents can be sorted on client side.
Acknowledgements

NB! GeoFlutterFire2 is a revisited and updated version of GeoFlutterFire
The work originates from GeoFlutterFire by Darshan Narayanaswamy

所屬分類

依賴

依賴清單 2 項

原始碼儲存庫

使用此套件的專案