FleetWorkAPI Docs

Hướng dẫn tích hợp Flutter SDK

Hướng dẫn tích hợp GPS Tracking cho ứng dụng Flutter mobile (iOS & Android).

Package: vietmap_tracking_plugin


Yêu cầu hệ thống

Minimum
Flutter3.3.0+
Dart3.8.0+
AndroidAPI 21+ (Android 5.0)
iOS15.0+

1. Cài đặt

pubspec.yaml

dependencies:
  vietmap_tracking_plugin: ^1.0.7
flutter pub get

2. Cấu hình Platform

Android — android/app/src/main/AndroidManifest.xml

<manifest>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />

  <application>
    <service
      android:name=".LocationTrackingService"
      android:enabled="true"
      android:exported="false"
      android:foregroundServiceType="location" />
  </application>
</manifest>

iOS — ios/Runner/Info.plist

<dict>
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>Ứng dụng cần GPS để theo dõi vị trí nhân viên khi đang chạy.</string>

  <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
  <string>Ứng dụng cần GPS để tiếp tục theo dõi khi chạy nền.</string>

  <key>NSLocationAlwaysUsageDescription</key>
  <string>Ứng dụng cần GPS khi chạy nền.</string>

  <key>UIBackgroundModes</key>
  <array>
    <string>location</string>
    <string>background-fetch</string>
    <string>background-processing</string>
  </array>

  <!-- Bắt buộc cho background tracking trên iOS -->
  <key>BGTaskSchedulerPermittedIdentifiers</key>
  <array>
    <string>com.vietmaptrackingsdk.background-location</string>
    <string>com.vietmaptrackingsdk.location-sync</string>
  </array>
</dict>

3. Khởi tạo SDK

import 'package:vietmap_tracking_plugin/vietmap_tracking_plugin.dart';

final controller = VietmapTrackingController.instance;

// Khởi tạo với API key
// baseURL là optional — SDK dùng URL production mặc định
await controller.initializeTracking('YOUR_API_KEY');

// Hoặc với custom server:
await controller.initializeTracking(
  'YOUR_API_KEY',
  baseURL: 'https://live.fleetwork.vn/api/v1',
);

// Đăng ký lifecycle observer (gọi 1 lần sau initializeTracking)
controller.registerLifecycleObserver();

Gọi initializeTracking() trước tất cả method khác. Throws INVALID_API_KEY nếu key không hợp lệ.


4. Quyền truy cập GPS

Bước 1 — Quyền foreground (khi app đang chạy):

final result = await controller.requestLocationPermissions();
print(result.granted);          // bool — đủ quyền foreground?
print(result.status.value);     // "granted" | "denied" | "not_granted"
print(result.fineLocation);     // bool
print(result.backgroundLocation); // bool

Bước 2 — Quyền background (bắt buộc để tiếp tục theo dõi khi màn hình tắt):

final status = await controller.requestAlwaysLocationPermissions();
// "granted" | "denied" | "when_in_use"

Kiểm tra trạng thái quyền (không hiện popup):

final result = await controller.hasLocationPermissions();
if (!result.granted) {
  // Dẫn user đến màn hình cấp quyền
}

5. Bắt đầu / Dừng theo dõi

// Bắt đầu tracking — timer mode (mỗi 10 giây)
await controller.startTracking(
  LocationTrackingConfig(
    intervalMs: 10000,        // Capture GPS mỗi 10 giây
    distanceFilter: 0,        // Tắt distance trigger
    accuracy: LocationAccuracy.high,
    backgroundMode: true,
    userId: 'user-001',
    vehicleId: 'vehicle-abc', // optional
    deviceId: 'device-001',   // optional
    notificationTitle: 'Đang theo dõi hành trình',   // Android only
    notificationMessage: 'Chạm để mở ứng dụng',      // Android only
  ),
);

// Bắt đầu tracking — distance mode (mỗi 15 mét)
await controller.startTracking(
  LocationTrackingConfig(
    intervalMs: 0,            // Tắt timer trigger
    distanceFilter: 15.0,     // Capture mỗi khi di chuyển ≥ 15m
    accuracy: LocationAccuracy.high,
    backgroundMode: true,
    userId: 'user-001',
  ),
);

// Dừng tracking
await controller.stopTracking();

LocationTrackingConfig — Tham số

Tham sốKiểuMô tả
intervalMsintKhoảng thời gian giữa 2 GPS points (ms). 0 = tắt timer.
distanceFilterdoubleKhoảng cách tối thiểu để capture point mới (mét). ≤ 0 = tắt.
accuracyLocationAccuracyhigh / medium / low.
backgroundModebooltrue = tiếp tục tracking khi app ở background.
userIdString?ID nhân viên.
vehicleIdString?ID xe.
notificationTitleString?Android: tiêu đề notification foreground service.
notificationMessageString?Android: nội dung notification.
allowMockLocationbooltrue = cho phép mock location. false = bật phát hiện GPS giả.

Lưu ý: Chỉ dùng một trong hai — intervalMs > 0 hoặc distanceFilter > 0. Không kết hợp cả hai.


6. Kiểm tra trạng thái

final isActive = await controller.isTrackingActive(); // bool

final status = await controller.getTrackingStatus();
print(status.isTracking);          // bool
print(status.trackingDuration);    // int (ms kể từ startTracking)
print(status.lastLocationUpdate);  // int? (unix ms)

7. Cập nhật cấu hình khi đang tracking

Thay đổi config mà không cần restart tracking:

await controller.updateTrackingConfig(
  LocationTrackingConfig(
    intervalMs: 30000,
    distanceFilter: 0,
    accuracy: LocationAccuracy.medium,
    backgroundMode: true,
  ),
);

8. Cập nhật thông tin phương tiện

// Cập nhật ngay — không cần restart tracking
await controller.setVehicleId('vehicle-xyz');
await controller.setDriverId('user-002');

// Lấy giá trị hiện tại
final vehicleId = await controller.getVehicleId();
final driverId  = await controller.getDriverId();

9. Smart Battery Optimization

SDK tự động chuyển đổi giữa 3 profiles tracking dựa trên chuyển động và mức pin:

ProfileIntervalKhi nào áp dụng
navigation5 giâyĐang vào góc cua (cần chính xác cao)
general30 giâyDi chuyển thẳng / đứng yên
batterySaver10 phútPin < 15% và không sạc
// Đặt preferred profile khi xe đang di chuyển
controller.setSmartBatteryPreferredProfile(SmartBatteryProfile.navigation);

// Feed GPS vào SmartBattery để phát hiện góc cua và đứng yên
controller.onLocationUpdate.listen((LocationData loc) {
  controller.feedLocationToSmartBattery(loc.speed, heading: loc.heading);
});

// Lắng nghe khi profile thay đổi
controller.onSmartBatteryProfileChanged.listen((SmartBatteryProfile profile) {
  print('Profile changed: ${profile.name}');
});

10. Offline Cache

SDK tự động lưu local khi mất mạng và gửi lại khi có kết nối.

// Cấu hình giới hạn cache (gọi trước startTracking)
await controller.configureCacheLimits(
  maxRecords: 5000,        // Số record tối đa
  maxDbSizeBytes: 52428800, // 50 MB
  batchSize: 50,           // Record mỗi lần upload
);

// Kiểm tra / quản lý cache
final count  = await controller.getCachedLocationsCount(); // số điểm chờ gửi
final bytes  = await controller.getDatabaseSizeBytes();    // kích thước cache

// Gửi cache ngay (không chờ timer 30s nội bộ)
await controller.uploadCachedLocationsManually();

// Bật / tắt auto upload
await controller.setAutoUpload(true);

// Xoá toàn bộ cache (không hoàn tác)
await controller.clearCachedLocations();

11. Event Streams

// Vị trí mới ghi nhận
controller.onLocationUpdate.listen((LocationData loc) {
  print('${loc.latitude}, ${loc.longitude}');
  print('Speed: ${loc.speed} m/s');     // m/s
  print('Heading: ${loc.heading}°');
});

// Thay đổi trạng thái tracking
controller.onTrackingStatusChanged.listen((TrackingStatus status) {
  print('isTracking: ${status.isTracking}');
});

// Profile Smart Battery thay đổi
controller.onSmartBatteryProfileChanged.listen((SmartBatteryProfile profile) {
  print('Battery profile: ${profile.name}');
});

12. Data Models

LocationData

FieldKiểuĐơn vịMô tả
latitudedoubleđộVĩ độ.
longitudedoubleđộKinh độ.
altitudedoublemétĐộ cao.
accuracydoublemétĐộ chính xác GPS.
speeddoublem/sTốc độ tức thời.
headingdouble0–360°Hướng đầu xe (0=Bắc).
timestampintunix msThời điểm capture.
dateTimeDateTimeGetter từ timestamp.

Lưu ý: speed đơn vị là m/s (mét/giây). Để chuyển sang km/h: speed * 3.6.

TrackingStatus

FieldKiểuMô tả
isTrackingboolTracking đang chạy.
lastLocationUpdateint?Unix ms lần GPS gần nhất.
trackingDurationintms kể từ startTracking().
lastUpdateTimeDateTime?Getter từ lastLocationUpdate.
durationDurationGetter từ trackingDuration.

PermissionResult

FieldKiểuMô tả
grantedboolĐủ quyền.
statusPermissionStatus.granted / .denied / .notGranted.
fineLocationboolQuyền GPS chính xác.
coarseLocationboolQuyền GPS xấp xỉ.
backgroundLocationboolQuyền background.

SmartBatteryProfile

enum SmartBatteryProfile {
  navigation,   // 5 giây — chính xác cao
  general,      // 30 giây — cân bằng mặc định
  batterySaver, // 10 phút — tiết kiệm pin tối đa
}

13. Full API Reference

Khởi tạo

Method / PropertyReturnMô tả
initializeTracking(apiKey, {baseURL})Future<void>Xác thực key phía server. Throws INVALID_API_KEY nếu thất bại.
setMetadata(Map)Future<void>Đính kèm key-value tùy ý vào mỗi bản ghi GPS.
configureAlertAPI(apiKey, apiID)Future<void>Cấu hình thông tin đăng nhập cảnh báo tốc độ.
setFakeGpsNotificationConfig({title, message})Future<void>Tùy chỉnh thông báo GPS giả native của SDK.
registerLifecycleObserver()voidBật chuyển đổi SDK background/foreground tự động.

Điều khiển Tracking

Method / PropertyReturnMô tả
startTracking(config)Future<bool>Bắt đầu GPS tracking. userId là bắt buộc.
stopTracking()Future<bool>Dừng GPS tracking.
isTrackingActive()Future<bool>Tracking đang chạy?
getCurrentLocation()Future<LocationData?>Vị trí gần nhất đã biết. null nếu chưa có tín hiệu.
getTrackingStatus()Future<TrackingStatus>Snapshot trạng thái hiện tại.
updateTrackingConfig(config)Future<bool>Áp dụng config mới cho phiên đang chạy.
getTrackingHealthStatus()Future<Map>Snapshot chẩn đoán: mạng, cache, SDK flags.

Quyền

Method / PropertyReturnMô tả
requestLocationPermissions()Future<PermissionResult>Xin quyền foreground.
requestAlwaysLocationPermissions()Future<String>Xin quyền background.
hasLocationPermissions()Future<PermissionResult>Kiểm tra quyền, không popup.

GPS giả

Method / PropertyReturnMô tả
setFakeGpsPolicy(policy)Future<void>Đặt chính sách xử lý GPS giả.
onFakeGpsDetectedStream<FakeGpsEvent>Stream sự kiện GPS giả.

Event Streams

Method / PropertyReturnMô tả
onLocationUpdateStream<LocationData>Stream GPS points.
onTrackingStatusChangedStream<TrackingStatus>Stream trạng thái tracking.
onFakeGpsDetectedStream<FakeGpsEvent>Stream sự kiện GPS giả.
onSmartBatteryProfileChangedStream<SmartBatteryProfile>Stream thay đổi profile.

Smart Battery

Method / PropertyReturnMô tả
setSmartBatteryPreferredProfile(profile)voidĐặt preferred profile khi di chuyển.

Cache & Đồng bộ

Method / PropertyReturnMô tả
setAutoUpload(enabled)Future<bool>Bật/tắt auto upload.
isNetworkConnected()Future<bool>Kết nối mạng.
getCachedLocationsCount()Future<int>Số records pending.
getDatabaseSizeBytes()Future<int>Kích thước cache (bytes).
uploadCachedLocationsManually()Future<bool>Flush cache ngay.
clearCachedLocations()Future<bool>Xoá toàn bộ cache.
configureCacheLimits(...)Future<bool>Cấu hình giới hạn cache.

Lịch sử

Method / PropertyReturnMô tả
getTrackingHistory({userId, fromTimestamp, toTimestamp, pageNumber, pageSize, sortDescending})Future<List<GpsLocation>>Lấy lịch sử GPS theo bộ lọc.

14. Fake GPS Detection

SDK có cơ chế phát hiện fake GPS / mock location ở native layer.

Hệ điều hành nào hỗ trợ

Nền tảngCơ chế phát hiện
iOS 15+CLLocationSourceInformation
iOS 11–14Không có API hệ thống để phát hiện trong SDK
Android 12+Location.isMock()
Android 18–30Location.isFromMockProvider()

iOS

Trên iOS 15 trở lên, SDK đọc location.sourceInformation từ CLLocation để xác định vị trí có bị giả lập hay không.

Các trường hợp SDK có thể phát hiện:

ReasonÝ nghĩa
simulatedBySoftwareVị trí được giả lập bởi phần mềm.
producedByAccessoryVị trí được tạo từ thiết bị / accessory bên ngoài.

Khi phát hiện, SDK sẽ fire event onFakeGPSDetected với payload:

KeyKiểuMô tả
isFakeboolLuôn là true khi event được gọi.
reasonstringsimulatedBySoftware hoặc producedByAccessory.
latdoubleVĩ độ của điểm bị phát hiện là fake.
lngdoubleKinh độ của điểm bị phát hiện là fake.
timestampdoubleUnix timestamp theo giây.

Giới hạn: iOS 11–14 không có CLLocationSourceInformation, nên SDK không thể phát hiện fake GPS trên các phiên bản này.

Android

Trên Android, SDK kiểm tra mock location ngay khi nhận được GPS point từ hệ điều hành:

  • Android 12+ dùng location.isMock()
  • Android 18–30 dùng location.isFromMockProvider()

Khi phát hiện, SDK fire callback native FakeGPSCallback.onFakeGPSDetected(lat, lng).

Lưu ý: kiểm tra fake GPS diễn ra trước bước shouldProcessLocation(). Điều đó có nghĩa là dù point sau đó bị skip do timing filter hoặc distance filter, callback fake GPS vẫn được gọi nếu hệ thống đánh dấu đó là mock location.

Khuyến nghị cho ứng dụng tích hợp

Khi tính năng Flutter forward hoàn tất, ứng dụng nên tự quyết định cách xử lý, ví dụ:

  • hiển thị cảnh báo cho người dùng
  • ghi log để kiểm tra nội bộ
  • gắn cờ bản ghi để backend review
  • vẫn cho tracking tiếp tục nhưng đánh dấu điểm nghi ngờ

On this page